mirror of
https://github.com/ModOrganizer2/modorganizer.git
synced 2026-07-27 13:58:24 -07:00
Compare commits
75
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
500ab7f706 | ||
|
|
08309b71ba | ||
|
|
dce78b62b8 | ||
|
|
af6e1c3ab4 | ||
|
|
50325c8fc2 | ||
|
|
7a382eab75 | ||
|
|
8e6868bf88 | ||
|
|
a891146446 | ||
|
|
72f14df8a7 | ||
|
|
0fa7155eb8 | ||
|
|
c6c61ce792 | ||
|
|
ef801879ab | ||
|
|
1e6c5f7c25 | ||
|
|
49e1dd23b6 | ||
|
|
9c31cfa915 | ||
|
|
91dd38cb29 | ||
|
|
bf0db9c218 | ||
|
|
8fcf21e771 | ||
|
|
b46b2fe6f2 | ||
|
|
e91eebefbe | ||
|
|
2e605b275b | ||
|
|
5f2a49b3be | ||
|
|
c4955231cf | ||
|
|
87f4e2df26 | ||
|
|
9272013103 | ||
|
|
78c4178f2a | ||
|
|
7d79e3ad1e | ||
|
|
d0f2c4fcf7 | ||
|
|
36ac91e0b7 | ||
|
|
5c968a1242 | ||
|
|
e09cef3909 | ||
|
|
8d34ae3413 | ||
|
|
849a0a0ef4 | ||
|
|
3b3717a021 | ||
|
|
fe37b48dff | ||
|
|
f8c683f700 | ||
|
|
49cbe03491 | ||
|
|
6069decb15 | ||
|
|
30dece9093 | ||
|
|
50d0523622 | ||
|
|
067f272da3 | ||
|
|
97111de140 | ||
|
|
280691ebc3 | ||
|
|
1606c1366f | ||
|
|
8077c1ad73 | ||
|
|
aadd076269 | ||
|
|
d8cb9a4e37 | ||
|
|
3c21d1884a | ||
|
|
16bda49e06 | ||
|
|
daf8bab136 | ||
|
|
2c4ba2c62c | ||
|
|
0ae7d4753c | ||
|
|
f0ba6ce95c | ||
|
|
cdea0c9da5 | ||
|
|
0beb88760b | ||
|
|
45f6cd21a2 | ||
|
|
fc3753dcc5 | ||
|
|
9bc123e8e2 | ||
|
|
d161e1a0d6 | ||
|
|
1c9018e9fd | ||
|
|
4fbfc9aa54 | ||
|
|
528338d7bf | ||
|
|
5b04f38345 | ||
|
|
de27ab391f | ||
|
|
d9a6dbb916 | ||
|
|
f682f82db5 | ||
|
|
a47d971788 | ||
|
|
59d6b7840b | ||
|
|
b4220cf2f4 | ||
|
|
e0eb97922d | ||
|
|
10485e15e4 | ||
|
|
ec0ea9df8d | ||
|
|
24cc386191 | ||
|
|
0a19f04339 | ||
|
|
74c75e60d6 |
@@ -2,3 +2,14 @@ syntax: glob
|
||||
ModOrganizer-build-desktop*
|
||||
outputd/*
|
||||
output/*
|
||||
build-ModOrganizer-*
|
||||
source/NCC/*/bin
|
||||
source/NCC/*/obj
|
||||
source/NCC/bin
|
||||
*.orig
|
||||
source/plugins/proxyPython/build
|
||||
staging/*
|
||||
source - Copy/*
|
||||
ModOrganizer-build-*
|
||||
pdbs/*
|
||||
source/NCC/BossDummy.x/*
|
||||
|
||||
@@ -10,10 +10,14 @@ SUBDIRS = bsatk \
|
||||
archive \
|
||||
helper \
|
||||
plugins \
|
||||
proxydll
|
||||
proxydll \
|
||||
nxmhandler \
|
||||
BossDummy \
|
||||
pythonRunner \
|
||||
esptk
|
||||
|
||||
hookdll.depends = shared
|
||||
organizer.depends = shared, uibase
|
||||
organizer.depends = shared, uibase, plugins
|
||||
|
||||
CONFIG(debug, debug|release) {
|
||||
DESTDIR = outputd
|
||||
|
||||
+83
-83
@@ -17,86 +17,86 @@ You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "activatemodsdialog.h"
|
||||
#include "ui_activatemodsdialog.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QLabel>
|
||||
|
||||
ActivateModsDialog::ActivateModsDialog(const std::map<QString, std::vector<QString> > &missingPlugins, QWidget *parent)
|
||||
: TutorableDialog("ActivateMods", parent), ui(new Ui::ActivateModsDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
|
||||
QHeaderView *headerView = modsTable->horizontalHeader();
|
||||
#if QT_VERSION >= 0x050000
|
||||
headerView->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
headerView->setSectionResizeMode(1, QHeaderView::Interactive);
|
||||
#else
|
||||
headerView->setResizeMode(0, QHeaderView::Stretch);
|
||||
headerView->setResizeMode(1, QHeaderView::Interactive);
|
||||
#endif
|
||||
|
||||
int row = 0;
|
||||
|
||||
modsTable->setRowCount(missingPlugins.size());
|
||||
|
||||
for (std::map<QString, std::vector<QString> >::const_iterator espIter = missingPlugins.begin();
|
||||
espIter != missingPlugins.end(); ++espIter, ++row) {
|
||||
modsTable->setCellWidget(row, 0, new QLabel(espIter->first));
|
||||
if (espIter->second.size() == 0) {
|
||||
modsTable->setCellWidget(row, 1, new QLabel(tr("not found")));
|
||||
} else {
|
||||
QComboBox* combo = new QComboBox();
|
||||
for (std::vector<QString>::const_iterator modIter = espIter->second.begin();
|
||||
modIter != espIter->second.end(); ++modIter) {
|
||||
combo->addItem(*modIter);
|
||||
}
|
||||
modsTable->setCellWidget(row, 1, combo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ActivateModsDialog::~ActivateModsDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
void ActivateModsDialog::on_buttonBox_accepted()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
std::set<QString> ActivateModsDialog::getModsToActivate()
|
||||
{
|
||||
std::set<QString> result;
|
||||
QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
|
||||
|
||||
for (int row = 0; row < modsTable->rowCount(); ++row) {
|
||||
QComboBox *comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1));
|
||||
if (comboBox != NULL) {
|
||||
result.insert(comboBox->currentText());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::set<QString> ActivateModsDialog::getESPsToActivate()
|
||||
{
|
||||
std::set<QString> result;
|
||||
QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
|
||||
|
||||
for (int row = 0; row < modsTable->rowCount(); ++row) {
|
||||
QComboBox *comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1));
|
||||
if (comboBox != NULL) {
|
||||
QLabel *espName = dynamic_cast<QLabel*>(modsTable->cellWidget(row, 0));
|
||||
|
||||
result.insert(espName->text());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#include "activatemodsdialog.h"
|
||||
#include "ui_activatemodsdialog.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QLabel>
|
||||
|
||||
ActivateModsDialog::ActivateModsDialog(const std::map<QString, std::vector<QString> > &missingPlugins, QWidget *parent)
|
||||
: TutorableDialog("ActivateMods", parent), ui(new Ui::ActivateModsDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
|
||||
QHeaderView *headerView = modsTable->horizontalHeader();
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
headerView->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
headerView->setSectionResizeMode(1, QHeaderView::Interactive);
|
||||
#else
|
||||
headerView->setResizeMode(0, QHeaderView::Stretch);
|
||||
headerView->setResizeMode(1, QHeaderView::Interactive);
|
||||
#endif
|
||||
|
||||
int row = 0;
|
||||
|
||||
modsTable->setRowCount(missingPlugins.size());
|
||||
|
||||
for (std::map<QString, std::vector<QString> >::const_iterator espIter = missingPlugins.begin();
|
||||
espIter != missingPlugins.end(); ++espIter, ++row) {
|
||||
modsTable->setCellWidget(row, 0, new QLabel(espIter->first));
|
||||
if (espIter->second.size() == 0) {
|
||||
modsTable->setCellWidget(row, 1, new QLabel(tr("not found")));
|
||||
} else {
|
||||
QComboBox* combo = new QComboBox();
|
||||
for (std::vector<QString>::const_iterator modIter = espIter->second.begin();
|
||||
modIter != espIter->second.end(); ++modIter) {
|
||||
combo->addItem(*modIter);
|
||||
}
|
||||
modsTable->setCellWidget(row, 1, combo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ActivateModsDialog::~ActivateModsDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
void ActivateModsDialog::on_buttonBox_accepted()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
std::set<QString> ActivateModsDialog::getModsToActivate()
|
||||
{
|
||||
std::set<QString> result;
|
||||
QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
|
||||
|
||||
for (int row = 0; row < modsTable->rowCount(); ++row) {
|
||||
QComboBox *comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1));
|
||||
if (comboBox != NULL) {
|
||||
result.insert(comboBox->currentText());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::set<QString> ActivateModsDialog::getESPsToActivate()
|
||||
{
|
||||
std::set<QString> result;
|
||||
QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
|
||||
|
||||
for (int row = 0; row < modsTable->rowCount(); ++row) {
|
||||
QComboBox *comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1));
|
||||
if (comboBox != NULL) {
|
||||
QLabel *espName = dynamic_cast<QLabel*>(modsTable->cellWidget(row, 0));
|
||||
|
||||
result.insert(espName->text());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
|
||||
|
||||
This file is part of Mod Organizer.
|
||||
|
||||
Mod Organizer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Mod Organizer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "baincomplexinstallerdialog.h"
|
||||
#include "textviewer.h"
|
||||
#include "ui_baincomplexinstallerdialog.h"
|
||||
|
||||
#include <QDir>
|
||||
|
||||
|
||||
using namespace MOBase;
|
||||
|
||||
|
||||
BainComplexInstallerDialog::BainComplexInstallerDialog(DirectoryTree *tree, const QString &modName, bool hasPackageTXT, QWidget *parent)
|
||||
: TutorableDialog("BainInstaller", parent), ui(new Ui::BainComplexInstallerDialog), m_Manual(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->nameEdit->setText(modName);
|
||||
|
||||
for (DirectoryTree::const_node_iterator iter = tree->nodesBegin(); iter != tree->nodesEnd(); ++iter) {
|
||||
const QString &dirName = (*iter)->getData().name;
|
||||
if ((dirName.compare("fomod", Qt::CaseInsensitive) == 0) ||
|
||||
(dirName.startsWith("--"))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QListWidgetItem *item = new QListWidgetItem(ui->optionsList);
|
||||
item->setText((*iter)->getData().name);
|
||||
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||
item->setCheckState(item->text().mid(0, 2) == "00" ? Qt::Checked : Qt::Unchecked);
|
||||
item->setData(Qt::UserRole, qVariantFromValue((void*)(*iter)));
|
||||
ui->optionsList->addItem(item);
|
||||
}
|
||||
|
||||
ui->packageBtn->setEnabled(hasPackageTXT);
|
||||
}
|
||||
|
||||
|
||||
BainComplexInstallerDialog::~BainComplexInstallerDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
QString BainComplexInstallerDialog::getName() const
|
||||
{
|
||||
return ui->nameEdit->text();
|
||||
}
|
||||
|
||||
|
||||
void BainComplexInstallerDialog::moveTreeUp(DirectoryTree *target, DirectoryTree::Node *child)
|
||||
{
|
||||
for (DirectoryTree::const_node_iterator iter = child->nodesBegin();
|
||||
iter != child->nodesEnd();) {
|
||||
target->addNode(*iter, true);
|
||||
iter = child->detach(iter);
|
||||
}
|
||||
|
||||
for (DirectoryTree::const_leaf_reverse_iterator iter = child->leafsRBegin();
|
||||
iter != child->leafsREnd(); ++iter) {
|
||||
target->addLeaf(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DirectoryTree *BainComplexInstallerDialog::updateTree(DirectoryTree *tree)
|
||||
{
|
||||
DirectoryTree *newTree = new DirectoryTree;
|
||||
|
||||
for (DirectoryTree::const_node_reverse_iterator iter = tree->nodesRBegin();
|
||||
iter != tree->nodesREnd();) {
|
||||
QList<QListWidgetItem*> items = ui->optionsList->findItems((*iter)->getData().name, Qt::MatchFixedString);
|
||||
if ((items.count() == 1) && (items.at(0)->checkState() == Qt::Checked)) {
|
||||
moveTreeUp(newTree, *iter);
|
||||
}
|
||||
iter = tree->erase(iter);
|
||||
}
|
||||
|
||||
return newTree;
|
||||
}
|
||||
|
||||
|
||||
void BainComplexInstallerDialog::on_okBtn_clicked()
|
||||
{
|
||||
this->accept();
|
||||
}
|
||||
|
||||
|
||||
void BainComplexInstallerDialog::on_cancelBtn_clicked()
|
||||
{
|
||||
this->reject();
|
||||
}
|
||||
|
||||
|
||||
void BainComplexInstallerDialog::on_manualBtn_clicked()
|
||||
{
|
||||
m_Manual = true;
|
||||
this->reject();
|
||||
}
|
||||
|
||||
void BainComplexInstallerDialog::on_packageBtn_clicked()
|
||||
{
|
||||
TextViewer viewer("package.txt", this);
|
||||
viewer.setDescription("");
|
||||
viewer.addFile(QDir::tempPath().append("/package.txt"), false);
|
||||
viewer.exec();
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
|
||||
|
||||
This file is part of Mod Organizer.
|
||||
|
||||
Mod Organizer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Mod Organizer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BAINCOMPLEXINSTALLERDIALOG_H
|
||||
#define BAINCOMPLEXINSTALLERDIALOG_H
|
||||
|
||||
|
||||
#include "mytree.h"
|
||||
#include "installdialog.h"
|
||||
#include "tutorabledialog.h"
|
||||
|
||||
|
||||
namespace Ui {
|
||||
class BainComplexInstallerDialog;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Dialog to choose from options offered by a (complex) bain package
|
||||
**/
|
||||
class BainComplexInstallerDialog : public MOBase::TutorableDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
* @param tree the directory tree of the archive. The caller is resonsible to verify this actually qualifies as a bain installer
|
||||
* @param modName proposed name for the mod. The dialog allows the user to change this
|
||||
* @param hasPackageTXT set to true if a package.txt is available for this archive. The file has to be unpacked to QDir::tempPath before displaying the dialog!
|
||||
* @param parent parent widget
|
||||
**/
|
||||
explicit BainComplexInstallerDialog(MOBase::DirectoryTree *tree, const QString &modName, bool hasPackageTXT, QWidget *parent);
|
||||
~BainComplexInstallerDialog();
|
||||
|
||||
/**
|
||||
* @return bool true if the user requested the manual dialog
|
||||
**/
|
||||
bool manualRequested() const { return m_Manual; }
|
||||
|
||||
/**
|
||||
* @return QString the (user-modified) name to be used for the mod
|
||||
**/
|
||||
QString getName() const;
|
||||
|
||||
/**
|
||||
* @brief retrieve the updated archive tree from the dialog. The caller is responsible to delete the returned tree.
|
||||
*
|
||||
* @note This call is destructive on the input tree!
|
||||
*
|
||||
* @param tree input tree. (TODO isn't this the same as the tree passed in the constructor?)
|
||||
* @return DataTree* a new tree with only the selected options and directories arranged correctly. The caller takes custody of this pointer!
|
||||
**/
|
||||
MOBase::DirectoryTree *updateTree(MOBase::DirectoryTree *tree);
|
||||
|
||||
private slots:
|
||||
|
||||
void on_manualBtn_clicked();
|
||||
|
||||
void on_okBtn_clicked();
|
||||
|
||||
void on_cancelBtn_clicked();
|
||||
|
||||
void on_packageBtn_clicked();
|
||||
|
||||
private:
|
||||
|
||||
void moveTreeUp(MOBase::DirectoryTree *target, MOBase::DirectoryTree::Node *child);
|
||||
|
||||
private:
|
||||
|
||||
Ui::BainComplexInstallerDialog *ui;
|
||||
|
||||
bool m_Manual;
|
||||
|
||||
};
|
||||
|
||||
#endif // BAINCOMPLEXINSTALLERDIALOG_H
|
||||
+192
-190
@@ -17,193 +17,195 @@ You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "bbcode.h"
|
||||
|
||||
#include <QRegExp>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace BBCode {
|
||||
|
||||
|
||||
class BBCodeMap {
|
||||
|
||||
typedef std::map<QString, std::pair<QRegExp, QString> > TagMap;
|
||||
|
||||
public:
|
||||
|
||||
static BBCodeMap &instance() {
|
||||
static BBCodeMap s_Instance;
|
||||
return s_Instance;
|
||||
}
|
||||
|
||||
QString convertTag(const QString &input, int &length)
|
||||
{
|
||||
// extract the tag name
|
||||
m_TagNameExp.indexIn(input, 1, QRegExp::CaretAtOffset);
|
||||
QString tagName = m_TagNameExp.cap(0).toLower();
|
||||
//qDebug("tag name %s", tagName.toUtf8().constData());
|
||||
TagMap::iterator tagIter = m_TagMap.find(tagName);
|
||||
if (tagIter != m_TagMap.end()) {
|
||||
// recognized tag
|
||||
if (tagName.endsWith('=')) {
|
||||
tagName.chop(1);
|
||||
}
|
||||
QString closeTag = tagName == "*" ? "<br/>"
|
||||
: QString("[/%1]").arg(tagName);
|
||||
|
||||
int closeTagPos = input.indexOf(closeTag, 0, Qt::CaseInsensitive);
|
||||
//qDebug("close tag %s at %d", closeTag.toUtf8().constData(), closeTagPos);
|
||||
|
||||
if (closeTagPos > -1) {
|
||||
length = closeTagPos + closeTag.length();
|
||||
QString temp = input.mid(0, length);
|
||||
if (tagIter->second.first.indexIn(temp) == 0) {
|
||||
return temp.replace(tagIter->second.first, tagIter->second.second);
|
||||
} else {
|
||||
// expression doesn't match. either the input string is invalid
|
||||
// or the expression is
|
||||
qWarning("%s doesn't match the expression for %s",
|
||||
temp.toUtf8().constData(), tagName.toUtf8().constData());
|
||||
length = 0;
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// not a recognized tag or tag invalid
|
||||
length = 0;
|
||||
return QString();
|
||||
}
|
||||
|
||||
private:
|
||||
BBCodeMap()
|
||||
: m_TagNameExp("^[a-zA-Z*]*=?")
|
||||
{
|
||||
m_TagMap["b"] = std::make_pair(QRegExp("\\[b\\](.*)\\[/b\\]"),
|
||||
"<b>\\1</b>");
|
||||
m_TagMap["i"] = std::make_pair(QRegExp("\\[i\\](.*)\\[/i\\]"),
|
||||
"<i>\\1</i>");
|
||||
m_TagMap["u"] = std::make_pair(QRegExp("\\[u\\](.*)\\[/u\\]"),
|
||||
"<u>\\1</u>");
|
||||
m_TagMap["s"] = std::make_pair(QRegExp("\\[s\\](.*)\\[/s\\]"),
|
||||
"<s>\\1</s>");
|
||||
m_TagMap["sub"] = std::make_pair(QRegExp("\\[sub\\](.*)\\[/sub\\]"),
|
||||
"<sub>\\1</sub>");
|
||||
m_TagMap["sup"] = std::make_pair(QRegExp("\\[sup\\](.*)\\[/sup\\]"),
|
||||
"<sup>\\1</sup>");
|
||||
m_TagMap["size="] = std::make_pair(QRegExp("\\[size=([^\\]]*)\\](.*)\\[/size\\]"),
|
||||
"<font size=\"\\1\">\\2</font>");
|
||||
m_TagMap["color="] = std::make_pair(QRegExp("\\[color=([^\\]]*)\\](.*)\\[/color\\]"),
|
||||
"<font style=\"color: #\\1;\">\\2</font>");
|
||||
m_TagMap["font="] = std::make_pair(QRegExp("\\[font=([^\\]]*)\\](.*)\\[/font\\]"),
|
||||
"<font face=\\1>\\2</font>");
|
||||
m_TagMap["center"] = std::make_pair(QRegExp("\\[center\\](.*)\\[/center\\]"),
|
||||
"<div align=\"center\">\\1</div>");
|
||||
m_TagMap["quote"] = std::make_pair(QRegExp("\\[quote\\](.*)\\[/quote\\]"),
|
||||
"<blockquote>\"\\1\"</blockquote>");
|
||||
m_TagMap["quote="] = std::make_pair(QRegExp("\\[quote=([^\\]]*)\\](.*)\\[/quote\\]"),
|
||||
"<blockquote>\"\\2\"<br/><span>--\\1</span></blockquote></p>");
|
||||
m_TagMap["code"] = std::make_pair(QRegExp("\\[code\\](.*)\\[/code\\]"),
|
||||
"<pre>\\1</pre>");
|
||||
m_TagMap["heading"]= std::make_pair(QRegExp("\\[heading\\](.*)\\[/heading\\]"),
|
||||
"<h2><strong>\\1</strong></h2>");
|
||||
|
||||
// lists
|
||||
m_TagMap["list"] = std::make_pair(QRegExp("\\[list\\](.*)\\[/list\\]"),
|
||||
"<ul>\\1</ul>");
|
||||
m_TagMap["list="] = std::make_pair(QRegExp("\\[list.*\\](.*)\\[/list\\]"),
|
||||
"<ol>\\1</ol>");
|
||||
m_TagMap["ul"] = std::make_pair(QRegExp("\\[ul\\](.*)\\[/ul\\]"),
|
||||
"<ul>\\1</ul>");
|
||||
m_TagMap["ol"] = std::make_pair(QRegExp("\\[ol\\](.*)\\[/ol\\]"),
|
||||
"<ol>\\1</ol>");
|
||||
m_TagMap["li"] = std::make_pair(QRegExp("\\[li\\](.*)\\[/li\\]"),
|
||||
"<li>\\1</li>");
|
||||
m_TagMap["*"] = std::make_pair(QRegExp("\\[\\*\\](.*)<br/>"),
|
||||
"<li>\\1</li>");
|
||||
|
||||
// tables
|
||||
m_TagMap["table"] = std::make_pair(QRegExp("\\[table\\](.*)\\[/table\\]"),
|
||||
"<table>\\1</table>");
|
||||
m_TagMap["tr"] = std::make_pair(QRegExp("\\[tr\\](.*)\\[/tr\\]"),
|
||||
"<tr>\\1</tr>");
|
||||
m_TagMap["th"] = std::make_pair(QRegExp("\\[th\\](.*)\\[/th\\]"),
|
||||
"<th>\\1</th>");
|
||||
m_TagMap["td"] = std::make_pair(QRegExp("\\[td\\](.*)\\[/td\\]"),
|
||||
"<td>\\1</td>");
|
||||
|
||||
// web content
|
||||
m_TagMap["url"] = std::make_pair(QRegExp("\\[url\\](.*)\\[/url\\]"),
|
||||
"<a href=\"\\1\">\\1</a>");
|
||||
m_TagMap["url="] = std::make_pair(QRegExp("\\[url=([^\\]]*)\\](.*)\\[/url\\]"),
|
||||
"<a href=\"\\1\">\\2</a>");
|
||||
m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"),
|
||||
"<img src=\"\\1\"/>");
|
||||
m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"),
|
||||
"<img src=\"\\2\" align=\"\\1\" />");
|
||||
m_TagMap["email="] = std::make_pair(QRegExp("\\[email=\"?([^\\]]*)\"?\\](.*)\\[/email\\]"),
|
||||
"<a href=\"mailto:\\1\">\\2</a>");
|
||||
m_TagMap["youtube"] = std::make_pair(QRegExp("\\[youtube\\](.*)\\[/youtube\\]"),
|
||||
"<a href=\"http://www.youtube.com/v/\\1\">http://www.youtube.com/v/\\1</a>");
|
||||
|
||||
// make all patterns non-greedy and case-insensitive
|
||||
for (TagMap::iterator iter = m_TagMap.begin(); iter != m_TagMap.end(); ++iter) {
|
||||
iter->second.first.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
iter->second.first.setMinimal(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
QRegExp m_TagNameExp;
|
||||
TagMap m_TagMap;
|
||||
};
|
||||
|
||||
|
||||
QString convertToHTML(const QString &inputParam)
|
||||
{
|
||||
// this code goes over the input string once and replaces all bbtags
|
||||
// it encounters. This function is called recursively for every replaced
|
||||
// string to convert nested tags.
|
||||
//
|
||||
// This could be implemented simpler by applying a set of regular expressions
|
||||
// for each recognized bb-tag one after the other but that would probably be
|
||||
// very inefficient (O(n^2)).
|
||||
|
||||
QString input = inputParam.mid(0).replace("\r\n", "<br/>");
|
||||
input.replace("\\\"", "\"").replace("\\'", "'");
|
||||
|
||||
QString result;
|
||||
int lastBlock = 0;
|
||||
int pos = 0;
|
||||
|
||||
// iterate over the input buffer
|
||||
while ((pos = input.indexOf('[', lastBlock)) != -1) {
|
||||
// append everything between the previous tag-block and the current one
|
||||
result.append(input.midRef(lastBlock, pos - lastBlock));
|
||||
|
||||
// convert the tag and content if necessary
|
||||
int length = -1;
|
||||
QString replacement = BBCodeMap::instance().convertTag(input.mid(pos), length);
|
||||
if (length != 0) {
|
||||
QString temp = convertToHTML(replacement);
|
||||
result.append(temp);
|
||||
// length contains the number of characters in the original tag
|
||||
pos += length;
|
||||
} else {
|
||||
// nothing replaced
|
||||
result.append('[');
|
||||
++pos;
|
||||
}
|
||||
lastBlock = pos;
|
||||
}
|
||||
|
||||
// append the remainder (everything after the last tag)
|
||||
result.append(input.midRef(lastBlock));
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace BBCode
|
||||
|
||||
#include "bbcode.h"
|
||||
|
||||
#include <QRegExp>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace BBCode {
|
||||
|
||||
|
||||
class BBCodeMap {
|
||||
|
||||
typedef std::map<QString, std::pair<QRegExp, QString> > TagMap;
|
||||
|
||||
public:
|
||||
|
||||
static BBCodeMap &instance() {
|
||||
static BBCodeMap s_Instance;
|
||||
return s_Instance;
|
||||
}
|
||||
|
||||
QString convertTag(const QString &input, int &length)
|
||||
{
|
||||
// extract the tag name
|
||||
m_TagNameExp.indexIn(input, 1, QRegExp::CaretAtOffset);
|
||||
QString tagName = m_TagNameExp.cap(0).toLower();
|
||||
//qDebug("tag name %s", tagName.toUtf8().constData());
|
||||
TagMap::iterator tagIter = m_TagMap.find(tagName);
|
||||
if (tagIter != m_TagMap.end()) {
|
||||
// recognized tag
|
||||
if (tagName.endsWith('=')) {
|
||||
tagName.chop(1);
|
||||
}
|
||||
QString closeTag = tagName == "*" ? "<br/>"
|
||||
: QString("[/%1]").arg(tagName);
|
||||
|
||||
int closeTagPos = input.indexOf(closeTag, 0, Qt::CaseInsensitive);
|
||||
//qDebug("close tag %s at %d", closeTag.toUtf8().constData(), closeTagPos);
|
||||
|
||||
if (closeTagPos > -1) {
|
||||
length = closeTagPos + closeTag.length();
|
||||
QString temp = input.mid(0, length);
|
||||
if (tagIter->second.first.indexIn(temp) == 0) {
|
||||
return temp.replace(tagIter->second.first, tagIter->second.second);
|
||||
} else {
|
||||
// expression doesn't match. either the input string is invalid
|
||||
// or the expression is
|
||||
qWarning("%s doesn't match the expression for %s",
|
||||
temp.toUtf8().constData(), tagName.toUtf8().constData());
|
||||
length = 0;
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// not a recognized tag or tag invalid
|
||||
length = 0;
|
||||
return QString();
|
||||
}
|
||||
|
||||
private:
|
||||
BBCodeMap()
|
||||
: m_TagNameExp("^[a-zA-Z*]*=?")
|
||||
{
|
||||
m_TagMap["b"] = std::make_pair(QRegExp("\\[b\\](.*)\\[/b\\]"),
|
||||
"<b>\\1</b>");
|
||||
m_TagMap["i"] = std::make_pair(QRegExp("\\[i\\](.*)\\[/i\\]"),
|
||||
"<i>\\1</i>");
|
||||
m_TagMap["u"] = std::make_pair(QRegExp("\\[u\\](.*)\\[/u\\]"),
|
||||
"<u>\\1</u>");
|
||||
m_TagMap["s"] = std::make_pair(QRegExp("\\[s\\](.*)\\[/s\\]"),
|
||||
"<s>\\1</s>");
|
||||
m_TagMap["sub"] = std::make_pair(QRegExp("\\[sub\\](.*)\\[/sub\\]"),
|
||||
"<sub>\\1</sub>");
|
||||
m_TagMap["sup"] = std::make_pair(QRegExp("\\[sup\\](.*)\\[/sup\\]"),
|
||||
"<sup>\\1</sup>");
|
||||
m_TagMap["size="] = std::make_pair(QRegExp("\\[size=([^\\]]*)\\](.*)\\[/size\\]"),
|
||||
"<font size=\"\\1\">\\2</font>");
|
||||
m_TagMap["color="] = std::make_pair(QRegExp("\\[color=([^\\]]*)\\](.*)\\[/color\\]"),
|
||||
"<font style=\"color: #\\1;\">\\2</font>");
|
||||
m_TagMap["font="] = std::make_pair(QRegExp("\\[font=([^\\]]*)\\](.*)\\[/font\\]"),
|
||||
"<font face=\\1>\\2</font>");
|
||||
m_TagMap["center"] = std::make_pair(QRegExp("\\[center\\](.*)\\[/center\\]"),
|
||||
"<div align=\"center\">\\1</div>");
|
||||
m_TagMap["quote"] = std::make_pair(QRegExp("\\[quote\\](.*)\\[/quote\\]"),
|
||||
"<blockquote>\"\\1\"</blockquote>");
|
||||
m_TagMap["quote="] = std::make_pair(QRegExp("\\[quote=([^\\]]*)\\](.*)\\[/quote\\]"),
|
||||
"<blockquote>\"\\2\"<br/><span>--\\1</span></blockquote></p>");
|
||||
m_TagMap["code"] = std::make_pair(QRegExp("\\[code\\](.*)\\[/code\\]"),
|
||||
"<pre>\\1</pre>");
|
||||
m_TagMap["heading"]= std::make_pair(QRegExp("\\[heading\\](.*)\\[/heading\\]"),
|
||||
"<h2><strong>\\1</strong></h2>");
|
||||
|
||||
// lists
|
||||
m_TagMap["list"] = std::make_pair(QRegExp("\\[list\\](.*)\\[/list\\]"),
|
||||
"<ul>\\1</ul>");
|
||||
m_TagMap["list="] = std::make_pair(QRegExp("\\[list.*\\](.*)\\[/list\\]"),
|
||||
"<ol>\\1</ol>");
|
||||
m_TagMap["ul"] = std::make_pair(QRegExp("\\[ul\\](.*)\\[/ul\\]"),
|
||||
"<ul>\\1</ul>");
|
||||
m_TagMap["ol"] = std::make_pair(QRegExp("\\[ol\\](.*)\\[/ol\\]"),
|
||||
"<ol>\\1</ol>");
|
||||
m_TagMap["li"] = std::make_pair(QRegExp("\\[li\\](.*)\\[/li\\]"),
|
||||
"<li>\\1</li>");
|
||||
m_TagMap["*"] = std::make_pair(QRegExp("\\[\\*\\](.*)<br/>"),
|
||||
"<li>\\1</li>");
|
||||
|
||||
// tables
|
||||
m_TagMap["table"] = std::make_pair(QRegExp("\\[table\\](.*)\\[/table\\]"),
|
||||
"<table>\\1</table>");
|
||||
m_TagMap["tr"] = std::make_pair(QRegExp("\\[tr\\](.*)\\[/tr\\]"),
|
||||
"<tr>\\1</tr>");
|
||||
m_TagMap["th"] = std::make_pair(QRegExp("\\[th\\](.*)\\[/th\\]"),
|
||||
"<th>\\1</th>");
|
||||
m_TagMap["td"] = std::make_pair(QRegExp("\\[td\\](.*)\\[/td\\]"),
|
||||
"<td>\\1</td>");
|
||||
|
||||
// web content
|
||||
m_TagMap["url"] = std::make_pair(QRegExp("\\[url\\](.*)\\[/url\\]"),
|
||||
"<a href=\"\\1\">\\1</a>");
|
||||
m_TagMap["url="] = std::make_pair(QRegExp("\\[url=([^\\]]*)\\](.*)\\[/url\\]"),
|
||||
"<a href=\"\\1\">\\2</a>");
|
||||
/* m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"),
|
||||
"<img src=\"\\1\"/>");
|
||||
m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"),
|
||||
"<img src=\"\\2\" align=\"\\1\" />");*/
|
||||
m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"), "");
|
||||
m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"), "");
|
||||
m_TagMap["email="] = std::make_pair(QRegExp("\\[email=\"?([^\\]]*)\"?\\](.*)\\[/email\\]"),
|
||||
"<a href=\"mailto:\\1\">\\2</a>");
|
||||
m_TagMap["youtube"] = std::make_pair(QRegExp("\\[youtube\\](.*)\\[/youtube\\]"),
|
||||
"<a href=\"http://www.youtube.com/v/\\1\">http://www.youtube.com/v/\\1</a>");
|
||||
|
||||
// make all patterns non-greedy and case-insensitive
|
||||
for (TagMap::iterator iter = m_TagMap.begin(); iter != m_TagMap.end(); ++iter) {
|
||||
iter->second.first.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
iter->second.first.setMinimal(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
QRegExp m_TagNameExp;
|
||||
TagMap m_TagMap;
|
||||
};
|
||||
|
||||
|
||||
QString convertToHTML(const QString &inputParam)
|
||||
{
|
||||
// this code goes over the input string once and replaces all bbtags
|
||||
// it encounters. This function is called recursively for every replaced
|
||||
// string to convert nested tags.
|
||||
//
|
||||
// This could be implemented simpler by applying a set of regular expressions
|
||||
// for each recognized bb-tag one after the other but that would probably be
|
||||
// very inefficient (O(n^2)).
|
||||
|
||||
QString input = inputParam.mid(0).replace("\r\n", "<br/>");
|
||||
input.replace("\\\"", "\"").replace("\\'", "'");
|
||||
|
||||
QString result;
|
||||
int lastBlock = 0;
|
||||
int pos = 0;
|
||||
|
||||
// iterate over the input buffer
|
||||
while ((pos = input.indexOf('[', lastBlock)) != -1) {
|
||||
// append everything between the previous tag-block and the current one
|
||||
result.append(input.midRef(lastBlock, pos - lastBlock));
|
||||
|
||||
// convert the tag and content if necessary
|
||||
int length = -1;
|
||||
QString replacement = BBCodeMap::instance().convertTag(input.mid(pos), length);
|
||||
if (length != 0) {
|
||||
QString temp = convertToHTML(replacement);
|
||||
result.append(temp);
|
||||
// length contains the number of characters in the original tag
|
||||
pos += length;
|
||||
} else {
|
||||
// nothing replaced
|
||||
result.append('[');
|
||||
++pos;
|
||||
}
|
||||
lastBlock = pos;
|
||||
}
|
||||
|
||||
// append the remainder (everything after the last tag)
|
||||
result.append(input.midRef(lastBlock));
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace BBCode
|
||||
|
||||
|
||||
+21
-21
@@ -17,24 +17,24 @@ You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BBCODE_H
|
||||
#define BBCODE_H
|
||||
|
||||
|
||||
#include <QString>
|
||||
|
||||
|
||||
namespace BBCode {
|
||||
|
||||
/**
|
||||
* @brief convert a string with BB Code-Tags to HTML
|
||||
* @param input the input string with BB tags
|
||||
* @param replaceOccured if not NULL, this parameter will be set to true if any bb tags were replaced
|
||||
* @return the same string in html representation
|
||||
**/
|
||||
QString convertToHTML(const QString &input);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BBCODE_H
|
||||
#ifndef BBCODE_H
|
||||
#define BBCODE_H
|
||||
|
||||
|
||||
#include <QString>
|
||||
|
||||
|
||||
namespace BBCode {
|
||||
|
||||
/**
|
||||
* @brief convert a string with BB Code-Tags to HTML
|
||||
* @param input the input string with BB tags
|
||||
* @param replaceOccured if not NULL, this parameter will be set to true if any bb tags were replaced
|
||||
* @return the same string in html representation
|
||||
**/
|
||||
QString convertToHTML(const QString &input);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BBCODE_H
|
||||
|
||||
+21
-2
@@ -25,6 +25,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QList>
|
||||
#include <QCoreApplication>
|
||||
|
||||
|
||||
using namespace MOBase;
|
||||
@@ -34,11 +35,17 @@ using namespace MOShared;
|
||||
CategoryFactory* CategoryFactory::s_Instance = NULL;
|
||||
|
||||
|
||||
QString CategoryFactory::categoriesFilePath()
|
||||
{
|
||||
return QCoreApplication::applicationDirPath() + "/categories.dat";
|
||||
}
|
||||
|
||||
|
||||
CategoryFactory::CategoryFactory()
|
||||
{
|
||||
reset();
|
||||
|
||||
QFile categoryFile(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())).append("/categories.dat"));
|
||||
QFile categoryFile(categoriesFilePath());
|
||||
|
||||
if (!categoryFile.open(QIODevice::ReadOnly)) {
|
||||
loadDefaultCategories();
|
||||
@@ -120,7 +127,7 @@ void CategoryFactory::setParents()
|
||||
|
||||
void CategoryFactory::saveCategories()
|
||||
{
|
||||
QFile categoryFile(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())).append("/categories.dat"));
|
||||
QFile categoryFile(categoriesFilePath());
|
||||
|
||||
if (!categoryFile.open(QIODevice::WriteOnly)) {
|
||||
reportError(QObject::tr("Failed to save custom categories"));
|
||||
@@ -144,6 +151,18 @@ void CategoryFactory::saveCategories()
|
||||
}
|
||||
|
||||
|
||||
unsigned int CategoryFactory::countCategories(std::tr1::function<bool (const Category &category)> filter)
|
||||
{
|
||||
unsigned int result = 0;
|
||||
for (auto iter = m_Categories.begin(); iter != m_Categories.end(); ++iter) {
|
||||
if (filter(*iter)) {
|
||||
++result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void CategoryFactory::addCategory(int id, const QString &name, const std::vector<int> &nexusIDs, int parentID)
|
||||
{
|
||||
int index = m_Categories.size();
|
||||
|
||||
+175
-161
@@ -17,164 +17,178 @@ You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CATEGORIES_H
|
||||
#define CATEGORIES_H
|
||||
|
||||
|
||||
#include <QString>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Manage the available mod categories
|
||||
* @warning member functions of this class currently use a wild mix of ids and indexes to look up categories,
|
||||
* optimized to where the request comes from. Therefore be very careful which of the two you have available
|
||||
**/
|
||||
class CategoryFactory {
|
||||
|
||||
friend class CategoriesDialog;
|
||||
|
||||
public:
|
||||
|
||||
static const int CATEGORY_NONE = 0;
|
||||
|
||||
static const int CATEGORY_SPECIAL_FIRST = 10000;
|
||||
static const int CATEGORY_SPECIAL_CHECKED = CATEGORY_SPECIAL_FIRST;
|
||||
static const int CATEGORY_SPECIAL_UNCHECKED = 10001;
|
||||
static const int CATEGORY_SPECIAL_UPDATEAVAILABLE = 10002;
|
||||
static const int CATEGORY_SPECIAL_NOCATEGORY = 10003;
|
||||
static const int CATEGORY_SPECIAL_CONFLICT = 10004;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief reset the list of categories
|
||||
**/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* @brief save the categories to the categories.dat file
|
||||
**/
|
||||
void saveCategories();
|
||||
|
||||
/**
|
||||
* @brief retrieve the number of available categories
|
||||
*
|
||||
* @return unsigned int number of categories
|
||||
**/
|
||||
unsigned numCategories() const { return m_Categories.size(); }
|
||||
|
||||
/**
|
||||
* @brief get the id of the parent category
|
||||
*
|
||||
* @param index the index to look up
|
||||
* @return int id of the parent category
|
||||
**/
|
||||
int getParentID(unsigned int index) const;
|
||||
|
||||
/**
|
||||
* @brief determine if a category exists (by id)
|
||||
*
|
||||
* @param id the id to check for existance
|
||||
* @return true if the category exists, false otherwise
|
||||
**/
|
||||
bool categoryExists(int id) const;
|
||||
|
||||
/**
|
||||
* @brief test if a category is child of a second one
|
||||
* @param id the presumed child id
|
||||
* @param parentID the parent id to test for
|
||||
* @return true if id is a child of parentID
|
||||
**/
|
||||
bool isDecendantOf(int id, int parentID) const;
|
||||
|
||||
/**
|
||||
* @brief test if the specified category has child categories
|
||||
*
|
||||
* @param index index of the category to look up
|
||||
* @return bool true if the category has child categories
|
||||
**/
|
||||
bool hasChildren(unsigned int index) const;
|
||||
|
||||
/**
|
||||
* @brief retrieve the name of a category
|
||||
*
|
||||
* @param index index of the category to look up
|
||||
* @return QString name of the category
|
||||
**/
|
||||
QString getCategoryName(unsigned int index) const;
|
||||
|
||||
/**
|
||||
* @brief look up the id of a category by its index
|
||||
*
|
||||
* @param index index of the category to look up
|
||||
* @return int id of the category
|
||||
**/
|
||||
int getCategoryID(unsigned int index) const;
|
||||
|
||||
/**
|
||||
* @brief look up the index of a category by its id
|
||||
*
|
||||
* @param id index of the category to look up
|
||||
* @return unsigned int index of the category
|
||||
**/
|
||||
int getCategoryIndex(int ID) const;
|
||||
|
||||
/**
|
||||
* @brief retrieve the index of a category by its nexus id
|
||||
*
|
||||
* @param nexusID nexus id of the category to look up
|
||||
* @return unsigned int index of the category or 0 if no category matches
|
||||
**/
|
||||
unsigned int resolveNexusID(int nexusID) const;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief retrieve a reference to the singleton instance
|
||||
*
|
||||
* @return the reference to the singleton
|
||||
**/
|
||||
static CategoryFactory &instance();
|
||||
|
||||
private:
|
||||
|
||||
struct Category {
|
||||
Category(int sortValue, int id, const QString &name, const std::vector<int> &nexusIDs, int parentID)
|
||||
: m_SortValue(sortValue), m_ID(id), m_Name(name), m_HasChildren(false),
|
||||
m_NexusIDs(nexusIDs), m_ParentID(parentID) {}
|
||||
int m_SortValue;
|
||||
int m_ID;
|
||||
int m_ParentID;
|
||||
bool m_HasChildren;
|
||||
QString m_Name;
|
||||
std::vector<int> m_NexusIDs;
|
||||
|
||||
friend bool operator<(const Category &LHS, const Category &RHS) {
|
||||
return LHS.m_SortValue < RHS.m_SortValue;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
CategoryFactory();
|
||||
|
||||
void loadDefaultCategories();
|
||||
|
||||
void addCategory(int id, const QString &name, const std::vector<int> &nexusID, int parentID);
|
||||
|
||||
void setParents();
|
||||
|
||||
private:
|
||||
|
||||
static CategoryFactory *s_Instance;
|
||||
|
||||
std::vector<Category> m_Categories;
|
||||
std::map<int, unsigned int> m_IDMap;
|
||||
std::map<int, unsigned int> m_NexusMap;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // CATEGORIES_H
|
||||
#ifndef CATEGORIES_H
|
||||
#define CATEGORIES_H
|
||||
|
||||
|
||||
#include <QString>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Manage the available mod categories
|
||||
* @warning member functions of this class currently use a wild mix of ids and indexes to look up categories,
|
||||
* optimized to where the request comes from. Therefore be very careful which of the two you have available
|
||||
**/
|
||||
class CategoryFactory {
|
||||
|
||||
friend class CategoriesDialog;
|
||||
|
||||
public:
|
||||
|
||||
static const int CATEGORY_NONE = 0;
|
||||
|
||||
static const int CATEGORY_SPECIAL_FIRST = 10000;
|
||||
static const int CATEGORY_SPECIAL_CHECKED = CATEGORY_SPECIAL_FIRST;
|
||||
static const int CATEGORY_SPECIAL_UNCHECKED = 10001;
|
||||
static const int CATEGORY_SPECIAL_UPDATEAVAILABLE = 10002;
|
||||
static const int CATEGORY_SPECIAL_NOCATEGORY = 10003;
|
||||
static const int CATEGORY_SPECIAL_CONFLICT = 10004;
|
||||
static const int CATEGORY_SPECIAL_NOTENDORSED = 10005;
|
||||
|
||||
public:
|
||||
|
||||
struct Category {
|
||||
Category(int sortValue, int id, const QString &name, const std::vector<int> &nexusIDs, int parentID)
|
||||
: m_SortValue(sortValue), m_ID(id), m_Name(name), m_HasChildren(false),
|
||||
m_NexusIDs(nexusIDs), m_ParentID(parentID) {}
|
||||
int m_SortValue;
|
||||
int m_ID;
|
||||
int m_ParentID;
|
||||
bool m_HasChildren;
|
||||
QString m_Name;
|
||||
std::vector<int> m_NexusIDs;
|
||||
|
||||
friend bool operator<(const Category &LHS, const Category &RHS) {
|
||||
return LHS.m_SortValue < RHS.m_SortValue;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief reset the list of categories
|
||||
**/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* @brief save the categories to the categories.dat file
|
||||
**/
|
||||
void saveCategories();
|
||||
|
||||
/**
|
||||
* @brief retrieve the number of available categories
|
||||
*
|
||||
* @return unsigned int number of categories
|
||||
**/
|
||||
unsigned numCategories() const { return m_Categories.size(); }
|
||||
|
||||
/**
|
||||
* @brief count all categories that match a specified filter
|
||||
* @param filter the filter to test
|
||||
* @return number of matching categories
|
||||
*/
|
||||
unsigned int countCategories(std::tr1::function<bool (const Category &category)> filter);
|
||||
|
||||
/**
|
||||
* @brief get the id of the parent category
|
||||
*
|
||||
* @param index the index to look up
|
||||
* @return int id of the parent category
|
||||
**/
|
||||
int getParentID(unsigned int index) const;
|
||||
|
||||
/**
|
||||
* @brief determine if a category exists (by id)
|
||||
*
|
||||
* @param id the id to check for existance
|
||||
* @return true if the category exists, false otherwise
|
||||
**/
|
||||
bool categoryExists(int id) const;
|
||||
|
||||
/**
|
||||
* @brief test if a category is child of a second one
|
||||
* @param id the presumed child id
|
||||
* @param parentID the parent id to test for
|
||||
* @return true if id is a child of parentID
|
||||
**/
|
||||
bool isDecendantOf(int id, int parentID) const;
|
||||
|
||||
/**
|
||||
* @brief test if the specified category has child categories
|
||||
*
|
||||
* @param index index of the category to look up
|
||||
* @return bool true if the category has child categories
|
||||
**/
|
||||
bool hasChildren(unsigned int index) const;
|
||||
|
||||
/**
|
||||
* @brief retrieve the name of a category
|
||||
*
|
||||
* @param index index of the category to look up
|
||||
* @return QString name of the category
|
||||
**/
|
||||
QString getCategoryName(unsigned int index) const;
|
||||
|
||||
/**
|
||||
* @brief look up the id of a category by its index
|
||||
*
|
||||
* @param index index of the category to look up
|
||||
* @return int id of the category
|
||||
**/
|
||||
int getCategoryID(unsigned int index) const;
|
||||
|
||||
/**
|
||||
* @brief look up the index of a category by its id
|
||||
*
|
||||
* @param id index of the category to look up
|
||||
* @return unsigned int index of the category
|
||||
**/
|
||||
int getCategoryIndex(int ID) const;
|
||||
|
||||
/**
|
||||
* @brief retrieve the index of a category by its nexus id
|
||||
*
|
||||
* @param nexusID nexus id of the category to look up
|
||||
* @return unsigned int index of the category or 0 if no category matches
|
||||
**/
|
||||
unsigned int resolveNexusID(int nexusID) const;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief retrieve a reference to the singleton instance
|
||||
*
|
||||
* @return the reference to the singleton
|
||||
**/
|
||||
static CategoryFactory &instance();
|
||||
|
||||
/**
|
||||
* @return path to the file that contains the categories list
|
||||
*/
|
||||
static QString categoriesFilePath();
|
||||
|
||||
private:
|
||||
|
||||
CategoryFactory();
|
||||
|
||||
void loadDefaultCategories();
|
||||
|
||||
void addCategory(int id, const QString &name, const std::vector<int> &nexusID, int parentID);
|
||||
|
||||
void setParents();
|
||||
|
||||
private:
|
||||
|
||||
static CategoryFactory *s_Instance;
|
||||
|
||||
std::vector<Category> m_Categories;
|
||||
std::map<int, unsigned int> m_IDMap;
|
||||
std::map<int, unsigned int> m_NexusMap;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // CATEGORIES_H
|
||||
|
||||
@@ -164,7 +164,7 @@ void CategoriesDialog::fillTable()
|
||||
CategoryFactory &categories = CategoryFactory::instance();
|
||||
QTableWidget *table = ui->categoriesTable;
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
|
||||
table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||
table->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
|
||||
|
||||
@@ -33,6 +33,11 @@ DirectoryRefresher::DirectoryRefresher()
|
||||
{
|
||||
}
|
||||
|
||||
DirectoryRefresher::~DirectoryRefresher()
|
||||
{
|
||||
delete m_DirectoryStructure;
|
||||
}
|
||||
|
||||
DirectoryEntry *DirectoryRefresher::getDirectoryStructure()
|
||||
{
|
||||
QMutexLocker locker(&m_RefreshLock);
|
||||
|
||||
@@ -21,10 +21,10 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define DIRECTORYREFRESHER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <directoryentry.h>
|
||||
#include <vector>
|
||||
#include <QMutex>
|
||||
#include <tuple>
|
||||
#include <directoryentry.h>
|
||||
|
||||
|
||||
/**
|
||||
@@ -43,6 +43,8 @@ public:
|
||||
**/
|
||||
DirectoryRefresher();
|
||||
|
||||
~DirectoryRefresher();
|
||||
|
||||
/**
|
||||
* @brief retrieve the updated directory structure
|
||||
*
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="dlls" version="1.0.0.0" processorArchitecture="x86"/>
|
||||
<file name="icuin49.dll"/>
|
||||
<file name="icuuc49.dll"/>
|
||||
<file name="icudt49.dll"/>
|
||||
<file name="Qt5Cored.dll"/>
|
||||
<file name="Qt5Declaratived.dll"/>
|
||||
<file name="Qt5Guid.dll"/>
|
||||
<file name="Qt5Networkd.dll"/>
|
||||
<file name="Qt5Scriptd.dll"/>
|
||||
<file name="Qt5Sqld.dll"/>
|
||||
<file name="Qt5Widgetsd.dll"/>
|
||||
<file name="Qt5XmlPatternsd.dll"/>
|
||||
</assembly>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="dlls" version="1.0.0.0" processorArchitecture="x86"/>
|
||||
<file name="icuin49.dll"/>
|
||||
<file name="icuuc49.dll"/>
|
||||
<file name="icudt49.dll"/>
|
||||
<file name="Qt5Core.dll"/>
|
||||
<file name="Qt5Declarative.dll"/>
|
||||
<file name="Qt5Gui.dll"/>
|
||||
<file name="Qt5Network.dll"/>
|
||||
<file name="Qt5Script.dll"/>
|
||||
<file name="Qt5Sql.dll"/>
|
||||
<file name="Qt5Svg.dll"/>
|
||||
<file name="Qt5Widgets.dll"/>
|
||||
<file name="Qt5Xml.dll"/>
|
||||
<file name="Qt5XmlPatterns.dll"/>
|
||||
</assembly>
|
||||
+88
-87
@@ -17,90 +17,91 @@ You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "downloadlist.h"
|
||||
#include "downloadmanager.h"
|
||||
#include <QEvent>
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
|
||||
DownloadList::DownloadList(DownloadManager *manager, QObject *parent)
|
||||
: QAbstractTableModel(parent), m_Manager(manager)
|
||||
{
|
||||
connect(m_Manager, SIGNAL(update(int)), this, SLOT(update(int)));
|
||||
connect(m_Manager, SIGNAL(aboutToUpdate()), this, SLOT(aboutToUpdate()));
|
||||
}
|
||||
|
||||
|
||||
int DownloadList::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return m_Manager->numTotalDownloads();
|
||||
}
|
||||
|
||||
int DownloadList::columnCount(const QModelIndex&) const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
QModelIndex DownloadList::index(int row, int column, const QModelIndex&) const
|
||||
{
|
||||
return createIndex(row, column, row);
|
||||
}
|
||||
|
||||
|
||||
QModelIndex DownloadList::parent(const QModelIndex&) const
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
|
||||
QVariant DownloadList::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if ((role == Qt::DisplayRole) &&
|
||||
(orientation == Qt::Horizontal)) {
|
||||
switch (section) {
|
||||
case 0: return tr("Name");
|
||||
case 1: return tr("Filetime");
|
||||
default: return tr("Done");
|
||||
}
|
||||
} else {
|
||||
return QAbstractItemModel::headerData(section, orientation, role);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QVariant DownloadList::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
return index.row();
|
||||
} else if (role == Qt::ToolTipRole) {
|
||||
if (m_Manager->isInfoIncomplete(index.row())) {
|
||||
return tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve.");
|
||||
} else {
|
||||
NexusInfo info = m_Manager->getNexusInfo(index.row());
|
||||
return QString("%1 (ID %2) %3").arg(info.m_ModName).arg(m_Manager->getModID(index.row())).arg(info.m_Version);
|
||||
}
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DownloadList::aboutToUpdate()
|
||||
{
|
||||
emit beginResetModel();
|
||||
}
|
||||
|
||||
|
||||
void DownloadList::update(int row)
|
||||
{
|
||||
if (row < 0) {
|
||||
emit endResetModel();
|
||||
} else if (row < this->rowCount()) {
|
||||
emit dataChanged(this->index(row, 0, QModelIndex()), this->index(row, 1, QModelIndex()));
|
||||
} else {
|
||||
qCritical("invalid row %d in download list, update failed", row);
|
||||
}
|
||||
}
|
||||
|
||||
#include "downloadlist.h"
|
||||
#include "downloadmanager.h"
|
||||
#include <QEvent>
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
|
||||
DownloadList::DownloadList(DownloadManager *manager, QObject *parent)
|
||||
: QAbstractTableModel(parent), m_Manager(manager)
|
||||
{
|
||||
connect(m_Manager, SIGNAL(update(int)), this, SLOT(update(int)));
|
||||
connect(m_Manager, SIGNAL(aboutToUpdate()), this, SLOT(aboutToUpdate()));
|
||||
}
|
||||
|
||||
|
||||
int DownloadList::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return m_Manager->numTotalDownloads();
|
||||
}
|
||||
|
||||
int DownloadList::columnCount(const QModelIndex&) const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
QModelIndex DownloadList::index(int row, int column, const QModelIndex&) const
|
||||
{
|
||||
return createIndex(row, column, row);
|
||||
}
|
||||
|
||||
|
||||
QModelIndex DownloadList::parent(const QModelIndex&) const
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
|
||||
QVariant DownloadList::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if ((role == Qt::DisplayRole) &&
|
||||
(orientation == Qt::Horizontal)) {
|
||||
switch (section) {
|
||||
case COL_NAME: return tr("Name");
|
||||
case COL_FILETIME: return tr("Filetime");
|
||||
default: return tr("Done");
|
||||
}
|
||||
} else {
|
||||
return QAbstractItemModel::headerData(section, orientation, role);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QVariant DownloadList::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
return index.row();
|
||||
} else if (role == Qt::ToolTipRole) {
|
||||
if (m_Manager->isInfoIncomplete(index.row())) {
|
||||
return tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve.");
|
||||
} else {
|
||||
NexusInfo info = m_Manager->getNexusInfo(index.row());
|
||||
return QString("%1 (ID %2) %3").arg(info.m_ModName).arg(m_Manager->getModID(index.row())).arg(info.m_Version);
|
||||
}
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DownloadList::aboutToUpdate()
|
||||
{
|
||||
emit beginResetModel();
|
||||
}
|
||||
|
||||
|
||||
void DownloadList::update(int row)
|
||||
{
|
||||
if (row < 0) {
|
||||
emit endResetModel();
|
||||
} else if (row < this->rowCount()) {
|
||||
#pragma message("updating only the one column is a hack")
|
||||
emit dataChanged(this->index(row, 2, QModelIndex()), this->index(row, 2, QModelIndex()));
|
||||
} else {
|
||||
qCritical("invalid row %d in download list, update failed", row);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+77
-73
@@ -17,76 +17,80 @@ You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DOWNLOADLIST_H
|
||||
#define DOWNLOADLIST_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
|
||||
class DownloadManager;
|
||||
|
||||
|
||||
/**
|
||||
* @brief model of the list of active and completed downloads
|
||||
**/
|
||||
class DownloadList : public QAbstractTableModel
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
*
|
||||
* @param manager the download manager processing downloads
|
||||
* @param parent parent object Defaults to 0.
|
||||
**/
|
||||
explicit DownloadList(DownloadManager *manager, QObject *parent = 0);
|
||||
|
||||
/**
|
||||
* @brief retrieve the number of rows to display. Invoked by Qt
|
||||
*
|
||||
* @param parent not relevant for this implementation
|
||||
* @return number of rows to display
|
||||
**/
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
|
||||
virtual int columnCount(const QModelIndex &parent) const;
|
||||
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const;
|
||||
QModelIndex parent(const QModelIndex &child) const;
|
||||
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||
|
||||
/**
|
||||
* @brief retrieve the data to display in a specific row. Invoked by Qt
|
||||
*
|
||||
* @param index location to look up
|
||||
* @param role ... Defaults to Qt::DisplayRole.
|
||||
* @return this implementation only returns the row, the QItemDelegate implementation is expected to fetch its information from the DownloadManager
|
||||
**/
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* @brief used to inform the model that data has changed
|
||||
*
|
||||
* @param row the row that changed. This can be negative to update the whole view
|
||||
**/
|
||||
void update(int row);
|
||||
|
||||
void aboutToUpdate();
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
|
||||
DownloadManager *m_Manager;
|
||||
|
||||
};
|
||||
|
||||
#endif // DOWNLOADLIST_H
|
||||
#ifndef DOWNLOADLIST_H
|
||||
#define DOWNLOADLIST_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
|
||||
class DownloadManager;
|
||||
|
||||
|
||||
/**
|
||||
* @brief model of the list of active and completed downloads
|
||||
**/
|
||||
class DownloadList : public QAbstractTableModel
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
enum EColumn {
|
||||
COL_NAME = 0,
|
||||
COL_FILETIME,
|
||||
COL_STATUS
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
*
|
||||
* @param manager the download manager processing downloads
|
||||
* @param parent parent object Defaults to 0.
|
||||
**/
|
||||
explicit DownloadList(DownloadManager *manager, QObject *parent = 0);
|
||||
|
||||
/**
|
||||
* @brief retrieve the number of rows to display. Invoked by Qt
|
||||
*
|
||||
* @param parent not relevant for this implementation
|
||||
* @return number of rows to display
|
||||
**/
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
|
||||
virtual int columnCount(const QModelIndex &parent) const;
|
||||
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const;
|
||||
QModelIndex parent(const QModelIndex &child) const;
|
||||
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||
|
||||
/**
|
||||
* @brief retrieve the data to display in a specific row. Invoked by Qt
|
||||
*
|
||||
* @param index location to look up
|
||||
* @param role ... Defaults to Qt::DisplayRole.
|
||||
* @return this implementation only returns the row, the QItemDelegate implementation is expected to fetch its information from the DownloadManager
|
||||
**/
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* @brief used to inform the model that data has changed
|
||||
*
|
||||
* @param row the row that changed. This can be negative to update the whole view
|
||||
**/
|
||||
void update(int row);
|
||||
|
||||
void aboutToUpdate();
|
||||
|
||||
private:
|
||||
|
||||
DownloadManager *m_Manager;
|
||||
|
||||
};
|
||||
|
||||
#endif // DOWNLOADLIST_H
|
||||
|
||||
@@ -18,6 +18,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "downloadlistsortproxy.h"
|
||||
#include "downloadlist.h"
|
||||
|
||||
DownloadListSortProxy::DownloadListSortProxy(const DownloadManager *manager, QObject *parent)
|
||||
: QSortFilterProxyModel(parent), m_Manager(manager), m_CurrentFilter()
|
||||
@@ -30,18 +31,21 @@ void DownloadListSortProxy::updateFilter(const QString &filter)
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
|
||||
bool DownloadListSortProxy::lessThan(const QModelIndex &left,
|
||||
const QModelIndex &right) const
|
||||
{
|
||||
int leftIndex = sourceModel()->data(left).toInt();
|
||||
int rightIndex = sourceModel()->data(right).toInt();
|
||||
|
||||
if (left.column() == 0) {
|
||||
if (left.column() == DownloadList::COL_NAME) {
|
||||
return m_Manager->getFileName(leftIndex).compare(m_Manager->getFileName(rightIndex), Qt::CaseInsensitive) < 0;
|
||||
} else if (left.column() == 1) {
|
||||
return leftIndex < rightIndex;
|
||||
} else {
|
||||
} else if (left.column() == DownloadList::COL_FILETIME) {
|
||||
return m_Manager->getFileTime(leftIndex) < m_Manager->getFileTime(rightIndex);
|
||||
} else if (left.column() == DownloadList::COL_STATUS) {
|
||||
return m_Manager->getState(leftIndex) < m_Manager->getState(rightIndex);
|
||||
} else {
|
||||
return leftIndex < rightIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+69
-13
@@ -30,7 +30,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
DownloadListWidget::DownloadListWidget(QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::DownloadListWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,10 +44,14 @@ DownloadListWidgetDelegate::DownloadListWidgetDelegate(DownloadManager *manager,
|
||||
: QItemDelegate(parent), m_Manager(manager), m_ItemWidget(new DownloadListWidget), m_ContextRow(0), m_View(view)
|
||||
{
|
||||
m_NameLabel = m_ItemWidget->findChild<QLabel*>("nameLabel");
|
||||
m_SizeLabel = m_ItemWidget->findChild<QLabel*>("sizeLabel");
|
||||
m_Progress = m_ItemWidget->findChild<QProgressBar*>("downloadProgress");
|
||||
m_InstallLabel = m_ItemWidget->findChild<QLabel*>("installLabel");
|
||||
|
||||
m_InstallLabel->setVisible(false);
|
||||
|
||||
connect(manager, SIGNAL(stateChanged(int,DownloadManager::DownloadState)), this, SLOT(stateChanged(int,DownloadManager::DownloadState)));
|
||||
connect(manager, SIGNAL(downloadRemoved(int)), this, SLOT(resetCache(int)));
|
||||
}
|
||||
|
||||
|
||||
@@ -57,9 +61,36 @@ DownloadListWidgetDelegate::~DownloadListWidgetDelegate()
|
||||
}
|
||||
|
||||
|
||||
void DownloadListWidgetDelegate::stateChanged(int row,DownloadManager::DownloadState)
|
||||
{
|
||||
m_Cache.remove(row);
|
||||
}
|
||||
|
||||
|
||||
void DownloadListWidgetDelegate::resetCache(int)
|
||||
{
|
||||
m_Cache.clear();
|
||||
}
|
||||
|
||||
|
||||
void DownloadListWidgetDelegate::drawCache(QPainter *painter, const QStyleOptionViewItem &option, const QPixmap &cache) const
|
||||
{
|
||||
QRect rect = option.rect;
|
||||
rect.setLeft(0);
|
||||
rect.setWidth(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2));
|
||||
painter->drawPixmap(rect, cache);
|
||||
}
|
||||
|
||||
|
||||
void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
try {
|
||||
auto iter = m_Cache.find(index.row());
|
||||
if (iter != m_Cache.end()) {
|
||||
drawCache(painter, option, *iter);
|
||||
return;
|
||||
}
|
||||
|
||||
m_ItemWidget->resize(QSize(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2), option.rect.height()));
|
||||
|
||||
int downloadIndex = index.data().toInt();
|
||||
@@ -70,18 +101,25 @@ void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionView
|
||||
name.append("...");
|
||||
}
|
||||
m_NameLabel->setText(name);
|
||||
m_SizeLabel->setText(QString::number(m_Manager->getFileSize(downloadIndex) / 1024));
|
||||
DownloadManager::DownloadState state = m_Manager->getState(downloadIndex);
|
||||
if (state == DownloadManager::STATE_PAUSED) {
|
||||
if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
|
||||
QPalette labelPalette;
|
||||
m_InstallLabel->setVisible(true);
|
||||
m_Progress->setVisible(false);
|
||||
#if QT_VERSION >= 0x050000
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Paused - Double Click to resume", 0));
|
||||
#else
|
||||
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Paused - Double Click to resume", 0, QApplication::UnicodeUTF8));
|
||||
#endif
|
||||
labelPalette.setColor(QPalette::WindowText, Qt::darkRed);
|
||||
m_InstallLabel->setPalette(labelPalette);
|
||||
} else if (state == DownloadManager::STATE_FETCHINGMODINFO) {
|
||||
m_InstallLabel->setText(tr("Fetching Info 1"));
|
||||
m_Progress->setVisible(false);
|
||||
} else if (state == DownloadManager::STATE_FETCHINGFILEINFO) {
|
||||
m_InstallLabel->setText(tr("Fetching Info 2"));
|
||||
m_Progress->setVisible(false);
|
||||
} else if (state >= DownloadManager::STATE_READY) {
|
||||
QPalette labelPalette;
|
||||
m_InstallLabel->setVisible(true);
|
||||
@@ -89,16 +127,21 @@ void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionView
|
||||
if (state == DownloadManager::STATE_INSTALLED) {
|
||||
// the tr-macro doesn't work here, maybe because the translation is actually associated with DownloadListWidget instead
|
||||
// of DownloadListWidgetDelegate?
|
||||
#if QT_VERSION >= 0x050000
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Installed - Double Click to re-install", 0));
|
||||
#else
|
||||
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Installed - Double Click to re-install", 0, QApplication::UnicodeUTF8));
|
||||
#endif
|
||||
labelPalette.setColor(QPalette::WindowText, Qt::darkGray);
|
||||
} else if (state == DownloadManager::STATE_UNINSTALLED) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Uninstalled - Double Click to re-install", 0));
|
||||
#else
|
||||
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Uninstalled - Double Click to re-install", 0, QApplication::UnicodeUTF8));
|
||||
#endif
|
||||
labelPalette.setColor(QPalette::WindowText, Qt::lightGray);
|
||||
} else {
|
||||
// the tr-macro doesn't work here, maybe because the translation is actually associated with DownloadListWidget instead
|
||||
// of DownloadListWidgetDelegate?
|
||||
#if QT_VERSION >= 0x050000
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0));
|
||||
#else
|
||||
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0, QApplication::UnicodeUTF8));
|
||||
@@ -107,7 +150,7 @@ void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionView
|
||||
}
|
||||
m_InstallLabel->setPalette(labelPalette);
|
||||
if (m_Manager->isInfoIncomplete(downloadIndex)) {
|
||||
m_NameLabel->setText("<img src=\":/MO/gui/resources/dialog-warning_16.png\" /> " + m_NameLabel->text());
|
||||
m_NameLabel->setText("<img src=\":/MO/gui/warning_16\" /> " + m_NameLabel->text());
|
||||
}
|
||||
} else {
|
||||
m_InstallLabel->setVisible(false);
|
||||
@@ -115,10 +158,23 @@ void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionView
|
||||
m_Progress->setValue(m_Manager->getProgress(downloadIndex));
|
||||
}
|
||||
|
||||
painter->save();
|
||||
painter->translate(QPoint(0, option.rect.topLeft().y()));
|
||||
m_ItemWidget->render(painter);
|
||||
painter->restore();
|
||||
#pragma message("caching disabled because changes in the list (including resorting) doesn't work correctly")
|
||||
// if (state >= DownloadManager::STATE_READY) {
|
||||
if (false) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
QPixmap cache = m_ItemWidget->grab();
|
||||
#else
|
||||
QPixmap cache = QPixmap::grabWidget(m_ItemWidget);
|
||||
#endif
|
||||
m_Cache[index.row()] = cache;
|
||||
drawCache(painter, option, cache);
|
||||
} else {
|
||||
painter->save();
|
||||
painter->translate(QPoint(0, option.rect.topLeft().y()));
|
||||
|
||||
m_ItemWidget->render(painter);
|
||||
painter->restore();
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
qCritical("failed to paint download list: %s", e.what());
|
||||
}
|
||||
@@ -231,7 +287,7 @@ bool DownloadListWidgetDelegate::editorEvent(QEvent *event, QAbstractItemModel *
|
||||
} else if (state == DownloadManager::STATE_DOWNLOADING){
|
||||
menu.addAction(tr("Cancel"), this, SLOT(issueCancel()));
|
||||
menu.addAction(tr("Pause"), this, SLOT(issuePause()));
|
||||
} else if (state == DownloadManager::STATE_PAUSED) {
|
||||
} else if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
|
||||
menu.addAction(tr("Remove"), this, SLOT(issueDelete()));
|
||||
menu.addAction(tr("Resume"), this, SLOT(issueResume()));
|
||||
}
|
||||
|
||||
+95
-83
@@ -17,86 +17,98 @@ 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 DOWNLOADLISTWIDGET_H
|
||||
#define DOWNLOADLISTWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QItemDelegate>
|
||||
#include <QLabel>
|
||||
#include <QProgressBar>
|
||||
#include <QTreeView>
|
||||
|
||||
namespace Ui {
|
||||
class DownloadListWidget;
|
||||
}
|
||||
|
||||
class DownloadListWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DownloadListWidget(QWidget *parent = 0);
|
||||
~DownloadListWidget();
|
||||
|
||||
|
||||
private:
|
||||
Ui::DownloadListWidget *ui;
|
||||
};
|
||||
|
||||
class DownloadManager;
|
||||
|
||||
class DownloadListWidgetDelegate : public QItemDelegate
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
DownloadListWidgetDelegate(DownloadManager *manager, QTreeView *view, QObject *parent = 0);
|
||||
~DownloadListWidgetDelegate();
|
||||
|
||||
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
|
||||
signals:
|
||||
|
||||
void installDownload(int index);
|
||||
void queryInfo(int index);
|
||||
void removeDownload(int index, bool deleteFile);
|
||||
void cancelDownload(int index);
|
||||
void pauseDownload(int index);
|
||||
void resumeDownload(int index);
|
||||
|
||||
protected:
|
||||
|
||||
bool editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||
const QStyleOptionViewItem &option, const QModelIndex &index);
|
||||
|
||||
private slots:
|
||||
|
||||
void issueInstall();
|
||||
void issueDelete();
|
||||
void issueRemoveFromView();
|
||||
void issueCancel();
|
||||
void issuePause();
|
||||
void issueResume();
|
||||
void issueDeleteAll();
|
||||
void issueDeleteCompleted();
|
||||
void issueRemoveFromViewAll();
|
||||
void issueRemoveFromViewCompleted();
|
||||
void issueQueryInfo();
|
||||
|
||||
private:
|
||||
|
||||
DownloadListWidget *m_ItemWidget;
|
||||
DownloadManager *m_Manager;
|
||||
|
||||
QLabel *m_NameLabel;
|
||||
QProgressBar *m_Progress;
|
||||
QLabel *m_InstallLabel;
|
||||
int m_ContextRow;
|
||||
|
||||
QTreeView *m_View;
|
||||
};
|
||||
|
||||
#endif // DOWNLOADLISTWIDGET_H
|
||||
#ifndef DOWNLOADLISTWIDGET_H
|
||||
#define DOWNLOADLISTWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QItemDelegate>
|
||||
#include <QLabel>
|
||||
#include <QProgressBar>
|
||||
#include <QTreeView>
|
||||
|
||||
#include "downloadmanager.h"
|
||||
|
||||
namespace Ui {
|
||||
class DownloadListWidget;
|
||||
}
|
||||
|
||||
class DownloadListWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DownloadListWidget(QWidget *parent = 0);
|
||||
~DownloadListWidget();
|
||||
|
||||
|
||||
private:
|
||||
Ui::DownloadListWidget *ui;
|
||||
};
|
||||
|
||||
class DownloadManager;
|
||||
|
||||
class DownloadListWidgetDelegate : public QItemDelegate
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
DownloadListWidgetDelegate(DownloadManager *manager, QTreeView *view, QObject *parent = 0);
|
||||
~DownloadListWidgetDelegate();
|
||||
|
||||
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
|
||||
signals:
|
||||
|
||||
void installDownload(int index);
|
||||
void queryInfo(int index);
|
||||
void removeDownload(int index, bool deleteFile);
|
||||
void cancelDownload(int index);
|
||||
void pauseDownload(int index);
|
||||
void resumeDownload(int index);
|
||||
|
||||
protected:
|
||||
|
||||
bool editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||
const QStyleOptionViewItem &option, const QModelIndex &index);
|
||||
|
||||
private:
|
||||
|
||||
void drawCache(QPainter *painter, const QStyleOptionViewItem &option, const QPixmap &cache) const;
|
||||
|
||||
private slots:
|
||||
|
||||
void issueInstall();
|
||||
void issueDelete();
|
||||
void issueRemoveFromView();
|
||||
void issueCancel();
|
||||
void issuePause();
|
||||
void issueResume();
|
||||
void issueDeleteAll();
|
||||
void issueDeleteCompleted();
|
||||
void issueRemoveFromViewAll();
|
||||
void issueRemoveFromViewCompleted();
|
||||
void issueQueryInfo();
|
||||
|
||||
void stateChanged(int row, DownloadManager::DownloadState);
|
||||
void resetCache(int);
|
||||
|
||||
private:
|
||||
|
||||
DownloadListWidget *m_ItemWidget;
|
||||
DownloadManager *m_Manager;
|
||||
|
||||
QLabel *m_NameLabel;
|
||||
QLabel *m_SizeLabel;
|
||||
QProgressBar *m_Progress;
|
||||
QLabel *m_InstallLabel;
|
||||
int m_ContextRow;
|
||||
|
||||
QTreeView *m_View;
|
||||
|
||||
mutable QMap<int, QPixmap> m_Cache;
|
||||
};
|
||||
|
||||
#endif // DOWNLOADLISTWIDGET_H
|
||||
|
||||
+48
-17
@@ -42,23 +42,54 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="nameLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>323</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Placeholder</string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="nameLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>323</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Placeholder</string>
|
||||
</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="sizeLabel">
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>KB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user