From 84c66727bff954fd0820fc9f33833848496e9531 Mon Sep 17 00:00:00 2001
From: Tannin
Date: Mon, 14 Jul 2014 21:22:44 +0200
Subject: - when highlighting a mod the overwritten and overwriting mods are
now highlighted in the list - when starting an external application MO now
wraps the process in a job and waits on that instead. This way MO is not
unlocked early when skyrim is started through skse - mod info dialog no
longer offers the esp tab for foreign mods because that caused confusion -
updated translation files - download directory and mod directory are now
created if necessary - bugfix: staging script created unnecessary copies of
translation files - bugfix: potential invalid array access when trying to
determine best mod order - bugfix: deleter file wasn't removed after esp
hiding was disabled - bugfix: potential access to to un-initialized login
reply - bugfix: changed the initialization order to allow more ui controls to
be localized
---
src/modinfodialog.cpp | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
(limited to 'src/modinfodialog.cpp')
diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp
index db6c7123..02ba0d38 100644
--- a/src/modinfodialog.cpp
+++ b/src/modinfodialog.cpp
@@ -99,17 +99,20 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo
ui->tabWidget->setTabEnabled(TAB_NEXUS, false);
ui->tabWidget->setTabEnabled(TAB_FILETREE, false);
ui->tabWidget->setTabEnabled(TAB_NOTES, false);
+ ui->tabWidget->setTabEnabled(TAB_ESPS, false);
+ ui->tabWidget->setTabEnabled(TAB_TEXTFILES, false);
+ ui->tabWidget->setTabEnabled(TAB_IMAGES, false);
} else {
initFiletree(modInfo);
initINITweaks();
addCategories(CategoryFactory::instance(), modInfo->getCategories(), ui->categoriesTree->invisibleRootItem(), 0);
refreshPrimaryCategoriesBox();
+ ui->tabWidget->setTabEnabled(TAB_TEXTFILES, ui->textFileList->count() != 0);
+ ui->tabWidget->setTabEnabled(TAB_IMAGES, ui->thumbnailArea->count() != 0);
+ ui->tabWidget->setTabEnabled(TAB_ESPS, (ui->inactiveESPList->count() != 0) || (ui->activeESPList->count() != 0));
}
refreshLists();
- ui->tabWidget->setTabEnabled(TAB_TEXTFILES, ui->textFileList->count() != 0);
- ui->tabWidget->setTabEnabled(TAB_IMAGES, ui->thumbnailArea->count() != 0);
- ui->tabWidget->setTabEnabled(TAB_ESPS, (ui->inactiveESPList->count() != 0) || (ui->activeESPList->count() != 0));
ui->tabWidget->setTabEnabled(TAB_CONFLICTS, m_Origin != NULL);
if (ui->tabWidget->currentIndex() == TAB_NEXUS) {
--
cgit v1.3.1
From e24f3fef770d250a40290a65bebd17f66121fc29 Mon Sep 17 00:00:00 2001
From: Tannin
Date: Thu, 17 Jul 2014 20:04:22 +0200
Subject: - bugfix: broke qt4 compatibility in trying to support qt5 - bugfix:
overwrite dialog displayed system drives if the overwrite directory didn't
exist - bugfix: ini tweak activation wasn't saved
---
src/mainwindow.cpp | 22 ++++++++++++++--------
src/modinfodialog.cpp | 2 +-
src/overwriteinfodialog.cpp | 18 +++++++++++++-----
src/overwriteinfodialog.h | 2 ++
src/shared/directoryentry.cpp | 2 +-
5 files changed, 31 insertions(+), 15 deletions(-)
(limited to 'src/modinfodialog.cpp')
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 19cefa89..cf283b49 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -3221,14 +3221,20 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index,
std::vector flags = modInfo->getFlags();
if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) {
QDialog *dialog = this->findChild("__overwriteDialog");
- if (dialog == NULL) {
- dialog = new OverwriteInfoDialog(modInfo, this);
- dialog->setObjectName("__overwriteDialog");
- }
- dialog->show();
- dialog->raise();
- dialog->activateWindow();
- connect(dialog, SIGNAL(finished(int)), this, SLOT(overwriteClosed(int)));
+ try {
+ if (dialog == NULL) {
+ dialog = new OverwriteInfoDialog(modInfo, this);
+ dialog->setObjectName("__overwriteDialog");
+ } else {
+ qobject_cast(dialog)->setModInfo(modInfo);
+ }
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+ connect(dialog, SIGNAL(finished(int)), this, SLOT(overwriteClosed(int)));
+ } catch (const std::exception &e) {
+ reportError(tr("Failed to display overwrite dialog: %1").arg(e.what()));
+ }
} else {
modInfo->saveMeta();
ModInfoDialog dialog(modInfo, m_DirectoryStructure, modInfo->hasFlag(ModInfo::FLAG_FOREIGN), this);
diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp
index 02ba0d38..96a575a0 100644
--- a/src/modinfodialog.cpp
+++ b/src/modinfodialog.cpp
@@ -104,7 +104,6 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo
ui->tabWidget->setTabEnabled(TAB_IMAGES, false);
} else {
initFiletree(modInfo);
- initINITweaks();
addCategories(CategoryFactory::instance(), modInfo->getCategories(), ui->categoriesTree->invisibleRootItem(), 0);
refreshPrimaryCategoriesBox();
ui->tabWidget->setTabEnabled(TAB_TEXTFILES, ui->textFileList->count() != 0);
@@ -112,6 +111,7 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo
ui->tabWidget->setTabEnabled(TAB_ESPS, (ui->inactiveESPList->count() != 0) || (ui->activeESPList->count() != 0));
}
refreshLists();
+ initINITweaks();
ui->tabWidget->setTabEnabled(TAB_CONFLICTS, m_Origin != NULL);
diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp
index 2ba81633..16242506 100644
--- a/src/overwriteinfodialog.cpp
+++ b/src/overwriteinfodialog.cpp
@@ -72,19 +72,17 @@ private:
OverwriteInfoDialog::OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget *parent)
: QDialog(parent), ui(new Ui::OverwriteInfoDialog), m_FileSystemModel(NULL),
- m_DeleteAction(NULL), m_RenameAction(NULL), m_OpenAction(NULL),
- m_ModInfo(modInfo)
+ m_DeleteAction(NULL), m_RenameAction(NULL), m_OpenAction(NULL)
{
ui->setupUi(this);
this->setWindowModality(Qt::NonModal);
- QString path = modInfo->absolutePath();
m_FileSystemModel = new MyFileSystemModel(this);
m_FileSystemModel->setReadOnly(false);
- m_FileSystemModel->setRootPath(path);
+ setModInfo(modInfo);
ui->filesView->setModel(m_FileSystemModel);
- ui->filesView->setRootIndex(m_FileSystemModel->index(path));
+ ui->filesView->setRootIndex(m_FileSystemModel->index(modInfo->absolutePath()));
ui->filesView->setColumnWidth(0, 250);
m_DeleteAction = new QAction(tr("&Delete"), ui->filesView);
@@ -102,6 +100,16 @@ OverwriteInfoDialog::~OverwriteInfoDialog()
delete ui;
}
+void OverwriteInfoDialog::setModInfo(ModInfo::Ptr modInfo)
+{
+ m_ModInfo = modInfo;
+ if (QDir(modInfo->absolutePath()).exists()) {
+ m_FileSystemModel->setRootPath(modInfo->absolutePath());
+ } else {
+ throw MyException(tr("%1 not found").arg(modInfo->absolutePath()));
+ }
+}
+
bool OverwriteInfoDialog::recursiveDelete(const QModelIndex &index)
{
for (int childRow = 0; childRow < m_FileSystemModel->rowCount(index); ++childRow) {
diff --git a/src/overwriteinfodialog.h b/src/overwriteinfodialog.h
index 34e86219..0726f1f9 100644
--- a/src/overwriteinfodialog.h
+++ b/src/overwriteinfodialog.h
@@ -39,6 +39,8 @@ public:
ModInfo::Ptr modInfo() const { return m_ModInfo; }
+ void setModInfo(ModInfo::Ptr modInfo);
+
private:
void openFile(const QModelIndex &index);
diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp
index 87431ea8..aead0cca 100644
--- a/src/shared/directoryentry.cpp
+++ b/src/shared/directoryentry.cpp
@@ -499,7 +499,7 @@ static bool SupportOptimizedFind()
::VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL),
VER_MINORVERSION, VER_GREATER_EQUAL);
- bool res = ::VerifyVersionInfo(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, mask);
+ bool res = ::VerifyVersionInfo(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, mask) == TRUE;
return res;
}
--
cgit v1.3.1
From f6ef5477e718b14af99bd22436f66dee0b9d22cd Mon Sep 17 00:00:00 2001
From: Tannin
Date: Thu, 17 Jul 2014 22:02:15 +0200
Subject: normalized eol style (all files should now have windows line endings)
---
src/activatemodsdialog.cpp | 194 +-
src/activatemodsdialog.h | 140 +-
src/bbcode.cpp | 468 +-
src/bbcode.h | 80 +-
src/browserdialog.cpp | 540 +-
src/browserdialog.h | 248 +-
src/browserview.cpp | 152 +-
src/browserview.h | 160 +-
src/categories.cpp | 602 +-
src/categories.h | 400 +-
src/categoriesdialog.cpp | 486 +-
src/categoriesdialog.h | 142 +-
src/credentialsdialog.cpp | 38 +-
src/credentialsdialog.h | 38 +-
src/directoryrefresher.cpp | 312 +-
src/directoryrefresher.h | 294 +-
src/downloadlist.cpp | 228 +-
src/downloadlist.h | 192 +-
src/downloadlistsortproxy.cpp | 130 +-
src/downloadlistsortproxy.h | 84 +-
src/downloadlistwidget.cpp | 702 +--
src/downloadlistwidget.h | 242 +-
src/downloadlistwidgetcompact.cpp | 682 +--
src/downloadlistwidgetcompact.h | 244 +-
src/downloadmanager.cpp | 2942 ++++-----
src/downloadmanager.h | 984 +--
src/dummybsa.cpp | 488 +-
src/dummybsa.h | 38 +-
src/editexecutablesdialog.cpp | 578 +-
src/editexecutablesdialog.h | 196 +-
src/executableslist.cpp | 406 +-
src/executableslist.h | 310 +-
src/filedialogmemory.cpp | 188 +-
src/filedialogmemory.h | 38 +-
src/gameinfoimpl.cpp | 108 +-
src/gameinfoimpl.h | 78 +-
src/helper.cpp | 38 +-
src/helper.h | 38 +-
src/icondelegate.cpp | 140 +-
src/icondelegate.h | 104 +-
src/installationmanager.cpp | 1604 ++---
src/installationmanager.h | 432 +-
src/json.cpp | 1044 ++--
src/json.h | 188 +-
src/loadmechanism.cpp | 580 +-
src/loadmechanism.h | 38 +-
src/lockeddialog.cpp | 150 +-
src/lockeddialog.h | 134 +-
src/logbuffer.cpp | 522 +-
src/logbuffer.h | 198 +-
src/loghighlighter.cpp | 38 +-
src/loghighlighter.h | 38 +-
src/main.cpp | 1162 ++--
src/mainwindow.cpp | 11202 +++++++++++++++++------------------
src/mainwindow.h | 1230 ++--
src/messagedialog.cpp | 184 +-
src/messagedialog.h | 134 +-
src/moapplication.cpp | 296 +-
src/moapplication.h | 102 +-
src/modeltest.cpp | 1166 ++--
src/modeltest.h | 188 +-
src/modinfo.cpp | 2006 +++----
src/modinfo.h | 2056 +++----
src/modinfodialog.cpp | 2512 ++++----
src/modinfodialog.h | 474 +-
src/modlist.cpp | 1986 +++----
src/modlist.h | 586 +-
src/modlistsortproxy.cpp | 752 +--
src/modlistsortproxy.h | 242 +-
src/motddialog.cpp | 98 +-
src/motddialog.h | 66 +-
src/nexusinterface.cpp | 1244 ++--
src/nexusinterface.h | 644 +-
src/nxmaccessmanager.cpp | 424 +-
src/nxmaccessmanager.h | 206 +-
src/overwriteinfodialog.cpp | 520 +-
src/overwriteinfodialog.h | 146 +-
src/pluginlist.cpp | 2318 ++++----
src/pluginlist.h | 688 +--
src/pluginlistsortproxy.cpp | 304 +-
src/pluginlistsortproxy.h | 142 +-
src/profile.cpp | 1564 ++---
src/profile.h | 660 +--
src/profileinputdialog.cpp | 96 +-
src/profileinputdialog.h | 38 +-
src/profilesdialog.cpp | 640 +-
src/profilesdialog.h | 192 +-
src/queryoverwritedialog.cpp | 38 +-
src/queryoverwritedialog.h | 38 +-
src/report.cpp | 106 +-
src/report.h | 38 +-
src/savegame.cpp | 212 +-
src/savegame.h | 262 +-
src/savegamegamebryo.cpp | 676 +--
src/savegamegamebyro.h | 204 +-
src/savegameinfowidget.cpp | 124 +-
src/savegameinfowidget.h | 38 +-
src/savegameinfowidgetgamebryo.cpp | 146 +-
src/savegameinfowidgetgamebryo.h | 38 +-
src/selectiondialog.cpp | 166 +-
src/selectiondialog.h | 136 +-
src/selfupdater.cpp | 932 +--
src/selfupdater.h | 290 +-
src/settings.cpp | 1542 ++---
src/settings.h | 626 +-
src/settingsdialog.cpp | 346 +-
src/settingsdialog.h | 168 +-
src/shared/appconfig.cpp | 2 +-
src/shared/inject.h | 62 +-
src/singleinstance.cpp | 214 +-
src/singleinstance.h | 38 +-
src/spawn.cpp | 422 +-
src/spawn.h | 136 +-
src/syncoverwritedialog.cpp | 332 +-
src/syncoverwritedialog.h | 110 +-
src/transfersavesdialog.cpp | 656 +-
src/transfersavesdialog.h | 164 +-
117 files changed, 31484 insertions(+), 31484 deletions(-)
(limited to 'src/modinfodialog.cpp')
diff --git a/src/activatemodsdialog.cpp b/src/activatemodsdialog.cpp
index 8d463fba..be6eef54 100644
--- a/src/activatemodsdialog.cpp
+++ b/src/activatemodsdialog.cpp
@@ -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 .
-*/
-
-#include "activatemodsdialog.h"
-#include "ui_activatemodsdialog.h"
-
-#include
-#include
-
-ActivateModsDialog::ActivateModsDialog(const std::map > &missingPlugins, QWidget *parent)
- : TutorableDialog("ActivateMods", parent), ui(new Ui::ActivateModsDialog)
-{
- ui->setupUi(this);
-
- QTableWidget *modsTable = findChild("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 >::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::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 ActivateModsDialog::getModsToActivate()
-{
- std::set result;
- QTableWidget *modsTable = findChild("modsTable");
-
- for (int row = 0; row < modsTable->rowCount(); ++row) {
- QComboBox *comboBox = dynamic_cast(modsTable->cellWidget(row, 1));
- if (comboBox != NULL) {
- result.insert(comboBox->currentText());
- }
- }
- return result;
-}
-
-
-std::set ActivateModsDialog::getESPsToActivate()
-{
- std::set result;
- QTableWidget *modsTable = findChild("modsTable");
-
- for (int row = 0; row < modsTable->rowCount(); ++row) {
- QComboBox *comboBox = dynamic_cast(modsTable->cellWidget(row, 1));
- if (comboBox != NULL) {
- QLabel *espName = dynamic_cast(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 .
+*/
+
+#include "activatemodsdialog.h"
+#include "ui_activatemodsdialog.h"
+
+#include
+#include
+
+ActivateModsDialog::ActivateModsDialog(const std::map > &missingPlugins, QWidget *parent)
+ : TutorableDialog("ActivateMods", parent), ui(new Ui::ActivateModsDialog)
+{
+ ui->setupUi(this);
+
+ QTableWidget *modsTable = findChild("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 >::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::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 ActivateModsDialog::getModsToActivate()
+{
+ std::set result;
+ QTableWidget *modsTable = findChild("modsTable");
+
+ for (int row = 0; row < modsTable->rowCount(); ++row) {
+ QComboBox *comboBox = dynamic_cast(modsTable->cellWidget(row, 1));
+ if (comboBox != NULL) {
+ result.insert(comboBox->currentText());
+ }
+ }
+ return result;
+}
+
+
+std::set ActivateModsDialog::getESPsToActivate()
+{
+ std::set result;
+ QTableWidget *modsTable = findChild("modsTable");
+
+ for (int row = 0; row < modsTable->rowCount(); ++row) {
+ QComboBox *comboBox = dynamic_cast(modsTable->cellWidget(row, 1));
+ if (comboBox != NULL) {
+ QLabel *espName = dynamic_cast(modsTable->cellWidget(row, 0));
+
+ result.insert(espName->text());
+ }
+ }
+ return result;
+}
diff --git a/src/activatemodsdialog.h b/src/activatemodsdialog.h
index 845167aa..08dbad8d 100644
--- a/src/activatemodsdialog.h
+++ b/src/activatemodsdialog.h
@@ -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 .
-*/
-
-#ifndef ACTIVATEMODSDIALOG_H
-#define ACTIVATEMODSDIALOG_H
-
-#include "tutorabledialog.h"
-#include
");
- m_TagMap["code"] = std::make_pair(QRegExp("\\[code\\](.*)\\[/code\\]"),
- "\\1
");
- m_TagMap["heading"]= std::make_pair(QRegExp("\\[heading\\](.*)\\[/heading\\]"),
- "\\1
");
-
- // lists
- m_TagMap["list"] = std::make_pair(QRegExp("\\[list\\](.*)\\[/list\\]"),
- "");
- m_TagMap["list="] = std::make_pair(QRegExp("\\[list.*\\](.*)\\[/list\\]"),
- "\\1
");
- m_TagMap["ul"] = std::make_pair(QRegExp("\\[ul\\](.*)\\[/ul\\]"),
- "");
- m_TagMap["ol"] = std::make_pair(QRegExp("\\[ol\\](.*)\\[/ol\\]"),
- "\\1
");
- m_TagMap["li"] = std::make_pair(QRegExp("\\[li\\](.*)\\[/li\\]"),
- "\\1");
- m_TagMap["*"] = std::make_pair(QRegExp("\\[\\*\\](.*)
"),
- "\\1");
-
- // tables
- m_TagMap["table"] = std::make_pair(QRegExp("\\[table\\](.*)\\[/table\\]"),
- "");
- m_TagMap["tr"] = std::make_pair(QRegExp("\\[tr\\](.*)\\[/tr\\]"),
- "\\1
");
- m_TagMap["th"] = std::make_pair(QRegExp("\\[th\\](.*)\\[/th\\]"),
- "\\1 | ");
- m_TagMap["td"] = std::make_pair(QRegExp("\\[td\\](.*)\\[/td\\]"),
- "\\1 | ");
-
- // web content
- m_TagMap["url"] = std::make_pair(QRegExp("\\[url\\](.*)\\[/url\\]"),
- "\\1");
- m_TagMap["url="] = std::make_pair(QRegExp("\\[url=([^\\]]*)\\](.*)\\[/url\\]"),
- "\\2");
- 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\\]"),
- "\\2");
- m_TagMap["youtube"] = std::make_pair(QRegExp("\\[youtube\\](.*)\\[/youtube\\]"),
- "http://www.youtube.com/v/\\1");
-
- m_ColorMap.insert(std::make_pair("red", "FF0000"));
- m_ColorMap.insert(std::make_pair("green", "00FF00"));
- m_ColorMap.insert(std::make_pair("blue", "0000FF"));
- m_ColorMap.insert(std::make_pair("black", "000000"));
- m_ColorMap.insert(std::make_pair("gray", "7F7F7F"));
- m_ColorMap.insert(std::make_pair("white", "FFFFFF"));
- m_ColorMap.insert(std::make_pair("yellow", "FFFF00"));
- m_ColorMap.insert(std::make_pair("cyan", "00FFFF"));
- m_ColorMap.insert(std::make_pair("magenta", "FF00FF"));
- m_ColorMap.insert(std::make_pair("brown", "A52A2A"));
- m_ColorMap.insert(std::make_pair("orange", "FFCC00"));
-
- // make all patterns non-greedy and case-insensitive
- for (TagMap::iterator iter = m_TagMap.begin(); iter != m_TagMap.end(); ++iter) {
- iter->second.first.setCaseSensitivity(Qt::CaseInsensitive);
- iter->second.first.setMinimal(true);
- }
- }
-
-private:
-
- QRegExp m_TagNameExp;
- TagMap m_TagMap;
- std::map 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", "
");
- 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 .
+*/
+
+#include "bbcode.h"
+
+#include
+#include
+#include
+#include
+
+
+namespace BBCode {
+
+
+class BBCodeMap {
+
+ typedef std::map > 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();
+ TagMap::iterator tagIter = m_TagMap.find(tagName);
+ if (tagIter != m_TagMap.end()) {
+ // recognized tag
+ if (tagName.endsWith('=')) {
+ tagName.chop(1);
+ }
+ QString closeTag = tagName == "*" ? "
"
+ : 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) {
+ if (tagIter->second.second.isEmpty()) {
+ if (tagName == "color") {
+ QString color = tagIter->second.first.cap(1);
+ QString content = tagIter->second.first.cap(2);
+ auto colIter = m_ColorMap.find(color.toLower());
+ if (colIter != m_ColorMap.end()) {
+ color = colIter->second;
+ }
+ return temp.replace(tagIter->second.first, QString("%2").arg(color, content));
+ } else {
+ qWarning("don't know how to deal with tag %s", qPrintable(tagName));
+ }
+ } else {
+ return temp.replace(tagIter->second.first, tagIter->second.second);
+ }
+ } else {
+ // expression doesn't match. either the input string is invalid
+ // or the expression is
+ 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\\]"),
+ "\\1");
+ m_TagMap["i"] = std::make_pair(QRegExp("\\[i\\](.*)\\[/i\\]"),
+ "\\1");
+ m_TagMap["u"] = std::make_pair(QRegExp("\\[u\\](.*)\\[/u\\]"),
+ "\\1");
+ m_TagMap["s"] = std::make_pair(QRegExp("\\[s\\](.*)\\[/s\\]"),
+ "\\1");
+ m_TagMap["sub"] = std::make_pair(QRegExp("\\[sub\\](.*)\\[/sub\\]"),
+ "\\1");
+ m_TagMap["sup"] = std::make_pair(QRegExp("\\[sup\\](.*)\\[/sup\\]"),
+ "\\1");
+ m_TagMap["size="] = std::make_pair(QRegExp("\\[size=([^\\]]*)\\](.*)\\[/size\\]"),
+ "\\2");
+ m_TagMap["color="] = std::make_pair(QRegExp("\\[color=([^\\]]*)\\](.*)\\[/color\\]"),
+ "");
+ m_TagMap["font="] = std::make_pair(QRegExp("\\[font=([^\\]]*)\\](.*)\\[/font\\]"),
+ "\\2");
+ m_TagMap["center"] = std::make_pair(QRegExp("\\[center\\](.*)\\[/center\\]"),
+ "\\1
");
+ m_TagMap["quote"] = std::make_pair(QRegExp("\\[quote\\](.*)\\[/quote\\]"),
+ "\"\\1\"
");
+ m_TagMap["quote="] = std::make_pair(QRegExp("\\[quote=([^\\]]*)\\](.*)\\[/quote\\]"),
+ "\"\\2\"
--\\1
");
+ m_TagMap["code"] = std::make_pair(QRegExp("\\[code\\](.*)\\[/code\\]"),
+ "\\1
");
+ m_TagMap["heading"]= std::make_pair(QRegExp("\\[heading\\](.*)\\[/heading\\]"),
+ "\\1
");
+
+ // lists
+ m_TagMap["list"] = std::make_pair(QRegExp("\\[list\\](.*)\\[/list\\]"),
+ "");
+ m_TagMap["list="] = std::make_pair(QRegExp("\\[list.*\\](.*)\\[/list\\]"),
+ "\\1
");
+ m_TagMap["ul"] = std::make_pair(QRegExp("\\[ul\\](.*)\\[/ul\\]"),
+ "");
+ m_TagMap["ol"] = std::make_pair(QRegExp("\\[ol\\](.*)\\[/ol\\]"),
+ "\\1
");
+ m_TagMap["li"] = std::make_pair(QRegExp("\\[li\\](.*)\\[/li\\]"),
+ "\\1");
+ m_TagMap["*"] = std::make_pair(QRegExp("\\[\\*\\](.*)
"),
+ "\\1");
+
+ // tables
+ m_TagMap["table"] = std::make_pair(QRegExp("\\[table\\](.*)\\[/table\\]"),
+ "");
+ m_TagMap["tr"] = std::make_pair(QRegExp("\\[tr\\](.*)\\[/tr\\]"),
+ "\\1
");
+ m_TagMap["th"] = std::make_pair(QRegExp("\\[th\\](.*)\\[/th\\]"),
+ "\\1 | ");
+ m_TagMap["td"] = std::make_pair(QRegExp("\\[td\\](.*)\\[/td\\]"),
+ "\\1 | ");
+
+ // web content
+ m_TagMap["url"] = std::make_pair(QRegExp("\\[url\\](.*)\\[/url\\]"),
+ "\\1");
+ m_TagMap["url="] = std::make_pair(QRegExp("\\[url=([^\\]]*)\\](.*)\\[/url\\]"),
+ "\\2");
+ 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\\]"),
+ "\\2");
+ m_TagMap["youtube"] = std::make_pair(QRegExp("\\[youtube\\](.*)\\[/youtube\\]"),
+ "http://www.youtube.com/v/\\1");
+
+ m_ColorMap.insert(std::make_pair("red", "FF0000"));
+ m_ColorMap.insert(std::make_pair("green", "00FF00"));
+ m_ColorMap.insert(std::make_pair("blue", "0000FF"));
+ m_ColorMap.insert(std::make_pair("black", "000000"));
+ m_ColorMap.insert(std::make_pair("gray", "7F7F7F"));
+ m_ColorMap.insert(std::make_pair("white", "FFFFFF"));
+ m_ColorMap.insert(std::make_pair("yellow", "FFFF00"));
+ m_ColorMap.insert(std::make_pair("cyan", "00FFFF"));
+ m_ColorMap.insert(std::make_pair("magenta", "FF00FF"));
+ m_ColorMap.insert(std::make_pair("brown", "A52A2A"));
+ m_ColorMap.insert(std::make_pair("orange", "FFCC00"));
+
+ // make all patterns non-greedy and case-insensitive
+ for (TagMap::iterator iter = m_TagMap.begin(); iter != m_TagMap.end(); ++iter) {
+ iter->second.first.setCaseSensitivity(Qt::CaseInsensitive);
+ iter->second.first.setMinimal(true);
+ }
+ }
+
+private:
+
+ QRegExp m_TagNameExp;
+ TagMap m_TagMap;
+ std::map 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", "
");
+ 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
+
diff --git a/src/bbcode.h b/src/bbcode.h
index 0d4d8003..f88e9a6c 100644
--- a/src/bbcode.h
+++ b/src/bbcode.h
@@ -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 .
-*/
-
-#ifndef BBCODE_H
-#define BBCODE_H
-
-
-#include
-
-
-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 .
+*/
+
+#ifndef BBCODE_H
+#define BBCODE_H
+
+
+#include
+
+
+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
diff --git a/src/browserdialog.cpp b/src/browserdialog.cpp
index 4aa4e969..4897ea4f 100644
--- a/src/browserdialog.cpp
+++ b/src/browserdialog.cpp
@@ -1,270 +1,270 @@
-/*
-Copyright (C) 2012 Sebastian Herbord. All rights reserved.
-
-This file is part of Mod Organizer.
-
-Mod Organizer is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Mod Organizer is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Mod Organizer. If not, see .
-*/
-
-#include "browserdialog.h"
-#include "ui_browserdialog.h"
-
-#include "messagedialog.h"
-#include "report.h"
-#include "json.h"
-#include "persistentcookiejar.h"
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-
-
-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(MOBase::ToQString(MOShared::GameInfo::instance().getCacheDir())) + "/cookies.dat", this));
-
- Qt::WindowFlags flags = windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint;
- Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint;
- flags = flags & (~helpFlag);
- setWindowFlags(flags);
-
- m_Tabs = this->findChild("browserTabWidget");
-
- connect(m_Tabs, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseRequested(int)));
-}
-
-
-BrowserDialog::~BrowserDialog()
-{
- delete ui;
-}
-
-void BrowserDialog::closeEvent(QCloseEvent *event)
-{
-// m_AccessManager->showCookies();
- QDialog::closeEvent(event);
-}
-
-void BrowserDialog::initTab(BrowserView *newView)
-{
- newView->page()->setNetworkAccessManager(m_AccessManager);
- newView->page()->setForwardUnsupportedContent(true);
-
- connect(newView, SIGNAL(loadProgress(int)), this, SLOT(progress(int)));
- connect(newView, SIGNAL(titleChanged(QString)), this, SLOT(titleChanged(QString)));
- connect(newView, SIGNAL(initTab(BrowserView*)), this, SLOT(initTab(BrowserView*)));
- connect(newView, SIGNAL(startFind()), this, SLOT(startSearch()));
- connect(newView, SIGNAL(urlChanged(QUrl)), this, SLOT(urlChanged(QUrl)));
- connect(newView, SIGNAL(openUrlInNewTab(QUrl)), this, SLOT(openInNewTab(QUrl)));
- connect(newView->page(), SIGNAL(downloadRequested(QNetworkRequest)), this, SLOT(downloadRequested(QNetworkRequest)));
- connect(newView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*)));
-
- ui->backBtn->setEnabled(false);
- ui->fwdBtn->setEnabled(false);
- m_Tabs->addTab(newView, tr("new"));
- newView->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
- newView->settings()->setAttribute(QWebSettings::AutoLoadImages, true);
-}
-
-
-void BrowserDialog::openInNewTab(const QUrl &url)
-{
- BrowserView *newView = new BrowserView(this);
- initTab(newView);
- newView->setUrl(url);
-}
-
-
-BrowserView *BrowserDialog::getCurrentView()
-{
- return qobject_cast(m_Tabs->currentWidget());
-}
-
-
-void BrowserDialog::urlChanged(const QUrl&)
-{
- BrowserView *currentView = getCurrentView();
- if (currentView != NULL) {
- ui->backBtn->setEnabled(currentView->history()->canGoBack());
- ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
- }
-}
-
-
-void BrowserDialog::openUrl(const QUrl &url)
-{
- if (isHidden()) {
- show();
- }
- openInNewTab(url);
-}
-
-
-void BrowserDialog::maximizeWidth()
-{
- int viewportWidth = getCurrentView()->page()->viewportSize().width();
- int frameWidth = width() - viewportWidth;
-
- int contentWidth = getCurrentView()->page()->mainFrame()->contentsSize().width();
-
- QDesktopWidget screen;
- int currentScreen = screen.screenNumber(this);
- int screenWidth = screen.screenGeometry(currentScreen).size().width();
-
- int targetWidth = std::min(std::max(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(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(sender());
- if (page == NULL) {
- qCritical("sender not a page");
- return;
- }
- BrowserView *view = qobject_cast(page->view());
- if (view == NULL) {
- qCritical("no view?");
- return;
- }
-
- qDebug("unsupported: %s - %s", view->url().toString().toUtf8().constData(), reply->url().toString().toUtf8().constData());
- emit requestDownload(view->url(), reply);
- } catch (const std::exception &e) {
- if (isVisible()) {
- MessageDialog::showMessage(tr("failed to start download"), this);
- }
- qCritical("exception downloading unsupported content: %s", e.what());
- }
-}
-
-
-void BrowserDialog::downloadRequested(const QNetworkRequest &request)
-{
- qCritical("download request %s ignored", request.url().toString().toUtf8().constData());
-}
-
-
-void BrowserDialog::tabCloseRequested(int index)
-{
- if (m_Tabs->count() == 1) {
- this->close();
- } else {
- m_Tabs->widget(index)->deleteLater();
- m_Tabs->removeTab(index);
- }
-}
-
-void BrowserDialog::on_backBtn_clicked()
-{
- BrowserView *currentView = getCurrentView();
- if (currentView != NULL) {
- currentView->back();
- }
-}
-
-void BrowserDialog::on_fwdBtn_clicked()
-{
- BrowserView *currentView = getCurrentView();
- if (currentView != NULL) {
- currentView->forward();
- }
-}
-
-
-void BrowserDialog::startSearch()
-{
- ui->searchEdit->setFocus();
-}
-
-
-void BrowserDialog::on_searchEdit_returnPressed()
-{
- BrowserView *currentView = getCurrentView();
- if (currentView != NULL) {
- currentView->findText(ui->searchEdit->text(), QWebPage::FindWrapsAroundDocument);
- }
-}
-
-void BrowserDialog::on_refreshBtn_clicked()
-{
- getCurrentView()->reload();
-}
-
-void BrowserDialog::on_browserTabWidget_currentChanged(int index)
-{
- BrowserView *currentView = qobject_cast(ui->browserTabWidget->widget(index));
- if (currentView != NULL) {
- ui->backBtn->setEnabled(currentView->history()->canGoBack());
- ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
- }
-}
+/*
+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 .
+*/
+
+#include "browserdialog.h"
+#include "ui_browserdialog.h"
+
+#include "messagedialog.h"
+#include "report.h"
+#include "json.h"
+#include "persistentcookiejar.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+
+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(MOBase::ToQString(MOShared::GameInfo::instance().getCacheDir())) + "/cookies.dat", this));
+
+ Qt::WindowFlags flags = windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint;
+ Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint;
+ flags = flags & (~helpFlag);
+ setWindowFlags(flags);
+
+ m_Tabs = this->findChild("browserTabWidget");
+
+ connect(m_Tabs, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseRequested(int)));
+}
+
+
+BrowserDialog::~BrowserDialog()
+{
+ delete ui;
+}
+
+void BrowserDialog::closeEvent(QCloseEvent *event)
+{
+// m_AccessManager->showCookies();
+ QDialog::closeEvent(event);
+}
+
+void BrowserDialog::initTab(BrowserView *newView)
+{
+ newView->page()->setNetworkAccessManager(m_AccessManager);
+ newView->page()->setForwardUnsupportedContent(true);
+
+ connect(newView, SIGNAL(loadProgress(int)), this, SLOT(progress(int)));
+ connect(newView, SIGNAL(titleChanged(QString)), this, SLOT(titleChanged(QString)));
+ connect(newView, SIGNAL(initTab(BrowserView*)), this, SLOT(initTab(BrowserView*)));
+ connect(newView, SIGNAL(startFind()), this, SLOT(startSearch()));
+ connect(newView, SIGNAL(urlChanged(QUrl)), this, SLOT(urlChanged(QUrl)));
+ connect(newView, SIGNAL(openUrlInNewTab(QUrl)), this, SLOT(openInNewTab(QUrl)));
+ connect(newView->page(), SIGNAL(downloadRequested(QNetworkRequest)), this, SLOT(downloadRequested(QNetworkRequest)));
+ connect(newView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*)));
+
+ ui->backBtn->setEnabled(false);
+ ui->fwdBtn->setEnabled(false);
+ m_Tabs->addTab(newView, tr("new"));
+ newView->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
+ newView->settings()->setAttribute(QWebSettings::AutoLoadImages, true);
+}
+
+
+void BrowserDialog::openInNewTab(const QUrl &url)
+{
+ BrowserView *newView = new BrowserView(this);
+ initTab(newView);
+ newView->setUrl(url);
+}
+
+
+BrowserView *BrowserDialog::getCurrentView()
+{
+ return qobject_cast(m_Tabs->currentWidget());
+}
+
+
+void BrowserDialog::urlChanged(const QUrl&)
+{
+ BrowserView *currentView = getCurrentView();
+ if (currentView != NULL) {
+ ui->backBtn->setEnabled(currentView->history()->canGoBack());
+ ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
+ }
+}
+
+
+void BrowserDialog::openUrl(const QUrl &url)
+{
+ if (isHidden()) {
+ show();
+ }
+ openInNewTab(url);
+}
+
+
+void BrowserDialog::maximizeWidth()
+{
+ int viewportWidth = getCurrentView()->page()->viewportSize().width();
+ int frameWidth = width() - viewportWidth;
+
+ int contentWidth = getCurrentView()->page()->mainFrame()->contentsSize().width();
+
+ QDesktopWidget screen;
+ int currentScreen = screen.screenNumber(this);
+ int screenWidth = screen.screenGeometry(currentScreen).size().width();
+
+ int targetWidth = std::min(std::max(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(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(sender());
+ if (page == NULL) {
+ qCritical("sender not a page");
+ return;
+ }
+ BrowserView *view = qobject_cast(page->view());
+ if (view == NULL) {
+ qCritical("no view?");
+ return;
+ }
+
+ qDebug("unsupported: %s - %s", view->url().toString().toUtf8().constData(), reply->url().toString().toUtf8().constData());
+ emit requestDownload(view->url(), reply);
+ } catch (const std::exception &e) {
+ if (isVisible()) {
+ MessageDialog::showMessage(tr("failed to start download"), this);
+ }
+ qCritical("exception downloading unsupported content: %s", e.what());
+ }
+}
+
+
+void BrowserDialog::downloadRequested(const QNetworkRequest &request)
+{
+ qCritical("download request %s ignored", request.url().toString().toUtf8().constData());
+}
+
+
+void BrowserDialog::tabCloseRequested(int index)
+{
+ if (m_Tabs->count() == 1) {
+ this->close();
+ } else {
+ m_Tabs->widget(index)->deleteLater();
+ m_Tabs->removeTab(index);
+ }
+}
+
+void BrowserDialog::on_backBtn_clicked()
+{
+ BrowserView *currentView = getCurrentView();
+ if (currentView != NULL) {
+ currentView->back();
+ }
+}
+
+void BrowserDialog::on_fwdBtn_clicked()
+{
+ BrowserView *currentView = getCurrentView();
+ if (currentView != NULL) {
+ currentView->forward();
+ }
+}
+
+
+void BrowserDialog::startSearch()
+{
+ ui->searchEdit->setFocus();
+}
+
+
+void BrowserDialog::on_searchEdit_returnPressed()
+{
+ BrowserView *currentView = getCurrentView();
+ if (currentView != NULL) {
+ currentView->findText(ui->searchEdit->text(), QWebPage::FindWrapsAroundDocument);
+ }
+}
+
+void BrowserDialog::on_refreshBtn_clicked()
+{
+ getCurrentView()->reload();
+}
+
+void BrowserDialog::on_browserTabWidget_currentChanged(int index)
+{
+ BrowserView *currentView = qobject_cast(ui->browserTabWidget->widget(index));
+ if (currentView != NULL) {
+ ui->backBtn->setEnabled(currentView->history()->canGoBack());
+ ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
+ }
+}
diff --git a/src/browserdialog.h b/src/browserdialog.h
index bd27661b..c6e0aab6 100644
--- a/src/browserdialog.h
+++ b/src/browserdialog.h
@@ -1,124 +1,124 @@
-/*
-Copyright (C) 2012 Sebastian Herbord. All rights reserved.
-
-This file is part of Mod Organizer.
-
-Mod Organizer is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Mod Organizer is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Mod Organizer. If not, see .
-*/
-
-#ifndef BROWSERDIALOG_H
-#define BROWSERDIALOG_H
-
-#include "browserview.h"
-#include "tutorialcontrol.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-
-namespace Ui {
- class BrowserDialog;
-}
-
-
-/**
- * @brief a dialog containing a webbrowser that is intended to browse the nexus network
- **/
-class BrowserDialog : public QDialog
-{
- Q_OBJECT
-
-public:
-
- /**
- * @brief constructor
- *
- * @param accessManager the access manager to use for network requests
- * @param parent parent widget
- **/
- explicit BrowserDialog(QWidget *parent = 0);
- ~BrowserDialog();
-
- /**
- * @brief set the url to open. If automatic login is enabled, the url is opened after login
- *
- * @param url the url to open
- **/
- void openUrl(const QUrl &url);
-
-signals:
-
- /**
- * @brief emitted when the user starts a download
- * @param pageUrl url of the current web site from which the download was started
- * @param reply network reply of the started download
- */
- void requestDownload(const QUrl &pageUrl, QNetworkReply *reply);
-
-protected:
-
- virtual void closeEvent(QCloseEvent *);
-
-private slots:
-
- void initTab(BrowserView *newView);
- void openInNewTab(const QUrl &url);
-
- void progress(int value);
-
- void titleChanged(const QString &title);
- void unsupportedContent(QNetworkReply *reply);
- void downloadRequested(const QNetworkRequest &request);
-
- void tabCloseRequested(int index);
-
- void urlChanged(const QUrl &url);
-
- void on_backBtn_clicked();
-
- void on_fwdBtn_clicked();
-
- void on_searchEdit_returnPressed();
-
- void startSearch();
-
- void on_refreshBtn_clicked();
-
- void on_browserTabWidget_currentChanged(int index);
-
-private:
-
- QString guessFileName(const QString &url);
-
- BrowserView *getCurrentView();
-
- void maximizeWidth();
-
-private:
-
- Ui::BrowserDialog *ui;
-
- QNetworkAccessManager *m_AccessManager;
-
- QTabWidget *m_Tabs;
-
-};
-
-#endif // BROWSERDIALOG_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 .
+*/
+
+#ifndef BROWSERDIALOG_H
+#define BROWSERDIALOG_H
+
+#include "browserview.h"
+#include "tutorialcontrol.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+namespace Ui {
+ class BrowserDialog;
+}
+
+
+/**
+ * @brief a dialog containing a webbrowser that is intended to browse the nexus network
+ **/
+class BrowserDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ * @param accessManager the access manager to use for network requests
+ * @param parent parent widget
+ **/
+ explicit BrowserDialog(QWidget *parent = 0);
+ ~BrowserDialog();
+
+ /**
+ * @brief set the url to open. If automatic login is enabled, the url is opened after login
+ *
+ * @param url the url to open
+ **/
+ void openUrl(const QUrl &url);
+
+signals:
+
+ /**
+ * @brief emitted when the user starts a download
+ * @param pageUrl url of the current web site from which the download was started
+ * @param reply network reply of the started download
+ */
+ void requestDownload(const QUrl &pageUrl, QNetworkReply *reply);
+
+protected:
+
+ virtual void closeEvent(QCloseEvent *);
+
+private slots:
+
+ void initTab(BrowserView *newView);
+ void openInNewTab(const QUrl &url);
+
+ void progress(int value);
+
+ void titleChanged(const QString &title);
+ void unsupportedContent(QNetworkReply *reply);
+ void downloadRequested(const QNetworkRequest &request);
+
+ void tabCloseRequested(int index);
+
+ void urlChanged(const QUrl &url);
+
+ void on_backBtn_clicked();
+
+ void on_fwdBtn_clicked();
+
+ void on_searchEdit_returnPressed();
+
+ void startSearch();
+
+ void on_refreshBtn_clicked();
+
+ void on_browserTabWidget_currentChanged(int index);
+
+private:
+
+ QString guessFileName(const QString &url);
+
+ BrowserView *getCurrentView();
+
+ void maximizeWidth();
+
+private:
+
+ Ui::BrowserDialog *ui;
+
+ QNetworkAccessManager *m_AccessManager;
+
+ QTabWidget *m_Tabs;
+
+};
+
+#endif // BROWSERDIALOG_H
diff --git a/src/browserview.cpp b/src/browserview.cpp
index f1b61e66..bd43a18e 100644
--- a/src/browserview.cpp
+++ b/src/browserview.cpp
@@ -1,76 +1,76 @@
-/*
-Copyright (C) 2012 Sebastian Herbord. All rights reserved.
-
-This file is part of Mod Organizer.
-
-Mod Organizer is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Mod Organizer is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Mod Organizer. If not, see .
-*/
-
-#include "browserview.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#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(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(event);
- if (mouseEvent->button() == Qt::MidButton) {
- mouseEvent->ignore();
- return true;
- }
- } else if (event->type() == QEvent::MouseButtonRelease) {
- QMouseEvent *mouseEvent = static_cast(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);
-}
+/*
+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 .
+*/
+
+#include "browserview.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#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(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(event);
+ if (mouseEvent->button() == Qt::MidButton) {
+ mouseEvent->ignore();
+ return true;
+ }
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *mouseEvent = static_cast(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);
+}
diff --git a/src/browserview.h b/src/browserview.h
index 3468276b..4f002ffc 100644
--- a/src/browserview.h
+++ b/src/browserview.h
@@ -1,80 +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 .
-*/
-
-#ifndef NEXUSVIEW_H
-#define NEXUSVIEW_H
-
-#include "finddialog.h"
-
-#include
-#include
-#include
-
-/**
- * @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
+/*
+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 .
+*/
+
+#ifndef NEXUSVIEW_H
+#define NEXUSVIEW_H
+
+#include "finddialog.h"
+
+#include
+#include
+#include
+
+/**
+ * @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
diff --git a/src/categories.cpp b/src/categories.cpp
index 27720829..79c646b3 100644
--- a/src/categories.cpp
+++ b/src/categories.cpp
@@ -1,301 +1,301 @@
-/*
-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 .
-*/
-
-#include "categories.h"
-#include
-#include "report.h"
-#include
-#include
-#include
-#include
-#include
-#include
-
-
-using namespace MOBase;
-using namespace MOShared;
-
-
-CategoryFactory* CategoryFactory::s_Instance = NULL;
-
-
-QString CategoryFactory::categoriesFilePath()
-{
- return QCoreApplication::applicationDirPath() + "/categories.dat";
-}
-
-
-CategoryFactory::CategoryFactory()
-{
- atexit(&cleanup);
- reset();
-
- QFile categoryFile(categoriesFilePath());
-
- if (!categoryFile.open(QIODevice::ReadOnly)) {
- loadDefaultCategories();
- } else {
- int lineNum = 0;
- while (!categoryFile.atEnd()) {
- QByteArray line = categoryFile.readLine();
- ++lineNum;
- QList cells = line.split('|');
- if (cells.count() != 4) {
- qCritical("invalid category line %d: %s (%d cells)",
- lineNum, line.constData(), cells.count());
- } else {
- std::vector nexusIDs;
- if (cells[2].length() > 0) {
- QList nexusIDStrings = cells[2].split(',');
- for (QList::iterator iter = nexusIDStrings.begin();
- iter != nexusIDStrings.end(); ++iter) {
- bool ok = false;
- int temp = iter->toInt(&ok);
- if (!ok) {
- qCritical("invalid id %s", iter->constData());
- }
- nexusIDs.push_back(temp);
- }
- }
- bool cell0Ok = true;
- bool cell3Ok = true;
- int id = cells[0].toInt(&cell0Ok);
- int parentID = cells[3].trimmed().toInt(&cell3Ok);
- if (!cell0Ok || !cell3Ok) {
- qCritical("invalid category line %d: %s",
- lineNum, line.constData());
- }
- addCategory(id, QString::fromUtf8(cells[1].constData()), nexusIDs, parentID);
- }
- }
- categoryFile.close();
- }
- std::sort(m_Categories.begin(), m_Categories.end());
- setParents();
-}
-
-
-CategoryFactory &CategoryFactory::instance()
-{
- if (s_Instance == NULL) {
- s_Instance = new CategoryFactory;
- }
- return *s_Instance;
-}
-
-
-void CategoryFactory::reset()
-{
- m_Categories.clear();
- m_IDMap.clear();
- addCategory(0, "None", MakeVector(2, 28, 87), 0);
-}
-
-
-void CategoryFactory::setParents()
-{
- for (std::vector::iterator iter = m_Categories.begin();
- iter != m_Categories.end(); ++iter) {
- iter->m_HasChildren = false;
- }
-
- for (std::vector::const_iterator categoryIter = m_Categories.begin();
- categoryIter != m_Categories.end(); ++categoryIter) {
- if (categoryIter->m_ParentID != 0) {
- std::map::const_iterator iter = m_IDMap.find(categoryIter->m_ParentID);
- if (iter != m_IDMap.end()) {
- m_Categories[iter->second].m_HasChildren = true;
- }
- }
- }
-}
-
-void CategoryFactory::cleanup()
-{
- delete s_Instance;
- s_Instance = NULL;
-}
-
-
-void CategoryFactory::saveCategories()
-{
- QFile categoryFile(categoriesFilePath());
-
- if (!categoryFile.open(QIODevice::WriteOnly)) {
- reportError(QObject::tr("Failed to save custom categories"));
- return;
- }
-
- categoryFile.resize(0);
- for (std::vector::const_iterator iter = m_Categories.begin();
- iter != m_Categories.end(); ++iter) {
- if (iter->m_ID == 0) {
- continue;
- }
- QByteArray line;
- line.append(QByteArray::number(iter->m_ID)).append("|")
- .append(iter->m_Name.toUtf8()).append("|")
- .append(VectorJoin(iter->m_NexusIDs, ",")).append("|")
- .append(QByteArray::number(iter->m_ParentID)).append("\n");
- categoryFile.write(line);
- }
- categoryFile.close();
-}
-
-
-unsigned int CategoryFactory::countCategories(std::tr1::function 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 &nexusIDs, int parentID)
-{
- int index = m_Categories.size();
- m_Categories.push_back(Category(index, id, name, nexusIDs, parentID));
- for (std::vector::const_iterator iter = nexusIDs.begin();
- iter != nexusIDs.end(); ++iter) {
- m_NexusMap[*iter] = index;
- }
- m_IDMap[id] = index;
-}
-
-
-void CategoryFactory::loadDefaultCategories()
-{
- // the order here is relevant as it defines the order in which the
- // mods appear in the combo box
- addCategory(1, "Animations", MakeVector(1, 51), 0);
- addCategory(2, "Armour", MakeVector(1, 54), 0);
- addCategory(3, "Audio", MakeVector(1, 61), 0);
- addCategory(5, "Clothing", MakeVector(1, 60), 0);
- addCategory(6, "Collectables", MakeVector(1, 92), 0);
- addCategory(7, "Creatures", MakeVector(2, 83, 65), 0);
- addCategory(8, "Factions", MakeVector(1, 25), 0);
- addCategory(9, "Gameplay", MakeVector(1, 24), 0);
- addCategory(10, "Hair", MakeVector(1, 26), 0);
- addCategory(11, "Items", MakeVector(2, 27, 85), 0);
- addCategory(19, "Weapons", MakeVector(2, 36, 55), 11);
- addCategory(12, "Locations", MakeVector(7, 22, 30, 70, 88, 89, 90, 91), 0);
- addCategory(4, "Cities", MakeVector(1, 53), 12);
- addCategory(20, "Magic", MakeVector(3, 75, 93, 94), 0);
- addCategory(21, "Models & Textures", MakeVector(1, 29), 0);
- addCategory(13, "NPCs", MakeVector(1, 33), 0);
- addCategory(14, "Patches", MakeVector(2, 79, 84), 0);
- addCategory(15, "Quests", MakeVector(1, 35), 0);
- addCategory(16, "Races & Classes", MakeVector(1, 34), 0);
- addCategory(22, "Skills", MakeVector(1, 73), 0);
- addCategory(17, "UI", MakeVector(1, 42), 0);
- addCategory(18, "Visuals", MakeVector(1, 62), 0);
-}
-
-
-int CategoryFactory::getParentID(unsigned int index) const
-{
- if ((index < 0) || (index >= m_Categories.size())) {
- throw MyException(QObject::tr("invalid index %1").arg(index));
- }
-
- return m_Categories[index].m_ParentID;
-}
-
-
-bool CategoryFactory::categoryExists(int id) const
-{
- return m_IDMap.find(id) != m_IDMap.end();
-}
-
-
-bool CategoryFactory::isDecendantOf(int id, int parentID) const
-{
- std::map::const_iterator iter = m_IDMap.find(id);
- if (iter != m_IDMap.end()) {
- unsigned int index = iter->second;
- if (m_Categories[index].m_ParentID == 0) {
- return false;
- } else if (m_Categories[index].m_ParentID == parentID) {
- return true;
- } else {
- return isDecendantOf(m_Categories[index].m_ParentID, parentID);
- }
- } else {
- qWarning("%d is no valid category id", id);
- return false;
- }
-}
-
-
-bool CategoryFactory::hasChildren(unsigned int index) const
-{
- if ((index < 0) || (index >= m_Categories.size())) {
- throw MyException(QObject::tr("invalid index %1").arg(index));
- }
-
- return m_Categories[index].m_HasChildren;
-}
-
-
-QString CategoryFactory::getCategoryName(unsigned int index) const
-{
- if ((index < 0) || (index >= m_Categories.size())) {
- throw MyException(QObject::tr("invalid index %1").arg(index));
- }
-
- return m_Categories[index].m_Name;
-}
-
-
-int CategoryFactory::getCategoryID(unsigned int index) const
-{
- if ((index < 0) || (index >= m_Categories.size())) {
- throw MyException(QObject::tr("invalid index %1").arg(index));
- }
-
- return m_Categories[index].m_ID;
-}
-
-
-int CategoryFactory::getCategoryIndex(int ID) const
-{
- std::map::const_iterator iter = m_IDMap.find(ID);
- if (iter == m_IDMap.end()) {
- throw MyException(QObject::tr("invalid category id %1").arg(ID));
- }
- return iter->second;
-}
-
-
-
-unsigned int CategoryFactory::resolveNexusID(int nexusID) const
-{
- std::map::const_iterator iter = m_NexusMap.find(nexusID);
- if (iter != m_NexusMap.end()) {
- qDebug("nexus category id %d maps to internal %d", nexusID, iter->second);
- return iter->second;
- } else {
- qDebug("nexus category id %d not mapped", nexusID);
- return 0U;
- }
-}
+/*
+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 .
+*/
+
+#include "categories.h"
+#include
+#include "report.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+using namespace MOBase;
+using namespace MOShared;
+
+
+CategoryFactory* CategoryFactory::s_Instance = NULL;
+
+
+QString CategoryFactory::categoriesFilePath()
+{
+ return QCoreApplication::applicationDirPath() + "/categories.dat";
+}
+
+
+CategoryFactory::CategoryFactory()
+{
+ atexit(&cleanup);
+ reset();
+
+ QFile categoryFile(categoriesFilePath());
+
+ if (!categoryFile.open(QIODevice::ReadOnly)) {
+ loadDefaultCategories();
+ } else {
+ int lineNum = 0;
+ while (!categoryFile.atEnd()) {
+ QByteArray line = categoryFile.readLine();
+ ++lineNum;
+ QList cells = line.split('|');
+ if (cells.count() != 4) {
+ qCritical("invalid category line %d: %s (%d cells)",
+ lineNum, line.constData(), cells.count());
+ } else {
+ std::vector nexusIDs;
+ if (cells[2].length() > 0) {
+ QList nexusIDStrings = cells[2].split(',');
+ for (QList::iterator iter = nexusIDStrings.begin();
+ iter != nexusIDStrings.end(); ++iter) {
+ bool ok = false;
+ int temp = iter->toInt(&ok);
+ if (!ok) {
+ qCritical("invalid id %s", iter->constData());
+ }
+ nexusIDs.push_back(temp);
+ }
+ }
+ bool cell0Ok = true;
+ bool cell3Ok = true;
+ int id = cells[0].toInt(&cell0Ok);
+ int parentID = cells[3].trimmed().toInt(&cell3Ok);
+ if (!cell0Ok || !cell3Ok) {
+ qCritical("invalid category line %d: %s",
+ lineNum, line.constData());
+ }
+ addCategory(id, QString::fromUtf8(cells[1].constData()), nexusIDs, parentID);
+ }
+ }
+ categoryFile.close();
+ }
+ std::sort(m_Categories.begin(), m_Categories.end());
+ setParents();
+}
+
+
+CategoryFactory &CategoryFactory::instance()
+{
+ if (s_Instance == NULL) {
+ s_Instance = new CategoryFactory;
+ }
+ return *s_Instance;
+}
+
+
+void CategoryFactory::reset()
+{
+ m_Categories.clear();
+ m_IDMap.clear();
+ addCategory(0, "None", MakeVector(2, 28, 87), 0);
+}
+
+
+void CategoryFactory::setParents()
+{
+ for (std::vector::iterator iter = m_Categories.begin();
+ iter != m_Categories.end(); ++iter) {
+ iter->m_HasChildren = false;
+ }
+
+ for (std::vector::const_iterator categoryIter = m_Categories.begin();
+ categoryIter != m_Categories.end(); ++categoryIter) {
+ if (categoryIter->m_ParentID != 0) {
+ std::map::const_iterator iter = m_IDMap.find(categoryIter->m_ParentID);
+ if (iter != m_IDMap.end()) {
+ m_Categories[iter->second].m_HasChildren = true;
+ }
+ }
+ }
+}
+
+void CategoryFactory::cleanup()
+{
+ delete s_Instance;
+ s_Instance = NULL;
+}
+
+
+void CategoryFactory::saveCategories()
+{
+ QFile categoryFile(categoriesFilePath());
+
+ if (!categoryFile.open(QIODevice::WriteOnly)) {
+ reportError(QObject::tr("Failed to save custom categories"));
+ return;
+ }
+
+ categoryFile.resize(0);
+ for (std::vector::const_iterator iter = m_Categories.begin();
+ iter != m_Categories.end(); ++iter) {
+ if (iter->m_ID == 0) {
+ continue;
+ }
+ QByteArray line;
+ line.append(QByteArray::number(iter->m_ID)).append("|")
+ .append(iter->m_Name.toUtf8()).append("|")
+ .append(VectorJoin(iter->m_NexusIDs, ",")).append("|")
+ .append(QByteArray::number(iter->m_ParentID)).append("\n");
+ categoryFile.write(line);
+ }
+ categoryFile.close();
+}
+
+
+unsigned int CategoryFactory::countCategories(std::tr1::function 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 &nexusIDs, int parentID)
+{
+ int index = m_Categories.size();
+ m_Categories.push_back(Category(index, id, name, nexusIDs, parentID));
+ for (std::vector::const_iterator iter = nexusIDs.begin();
+ iter != nexusIDs.end(); ++iter) {
+ m_NexusMap[*iter] = index;
+ }
+ m_IDMap[id] = index;
+}
+
+
+void CategoryFactory::loadDefaultCategories()
+{
+ // the order here is relevant as it defines the order in which the
+ // mods appear in the combo box
+ addCategory(1, "Animations", MakeVector(1, 51), 0);
+ addCategory(2, "Armour", MakeVector(1, 54), 0);
+ addCategory(3, "Audio", MakeVector(1, 61), 0);
+ addCategory(5, "Clothing", MakeVector(1, 60), 0);
+ addCategory(6, "Collectables", MakeVector(1, 92), 0);
+ addCategory(7, "Creatures", MakeVector(2, 83, 65), 0);
+ addCategory(8, "Factions", MakeVector(1, 25), 0);
+ addCategory(9, "Gameplay", MakeVector(1, 24), 0);
+ addCategory(10, "Hair", MakeVector(1, 26), 0);
+ addCategory(11, "Items", MakeVector(2, 27, 85), 0);
+ addCategory(19, "Weapons", MakeVector(2, 36, 55), 11);
+ addCategory(12, "Locations", MakeVector(7, 22, 30, 70, 88, 89, 90, 91), 0);
+ addCategory(4, "Cities", MakeVector(1, 53), 12);
+ addCategory(20, "Magic", MakeVector(3, 75, 93, 94), 0);
+ addCategory(21, "Models & Textures", MakeVector(1, 29), 0);
+ addCategory(13, "NPCs", MakeVector(1, 33), 0);
+ addCategory(14, "Patches", MakeVector(2, 79, 84), 0);
+ addCategory(15, "Quests", MakeVector(1, 35), 0);
+ addCategory(16, "Races & Classes", MakeVector(1, 34), 0);
+ addCategory(22, "Skills", MakeVector(1, 73), 0);
+ addCategory(17, "UI", MakeVector(1, 42), 0);
+ addCategory(18, "Visuals", MakeVector(1, 62), 0);
+}
+
+
+int CategoryFactory::getParentID(unsigned int index) const
+{
+ if ((index < 0) || (index >= m_Categories.size())) {
+ throw MyException(QObject::tr("invalid index %1").arg(index));
+ }
+
+ return m_Categories[index].m_ParentID;
+}
+
+
+bool CategoryFactory::categoryExists(int id) const
+{
+ return m_IDMap.find(id) != m_IDMap.end();
+}
+
+
+bool CategoryFactory::isDecendantOf(int id, int parentID) const
+{
+ std::map::const_iterator iter = m_IDMap.find(id);
+ if (iter != m_IDMap.end()) {
+ unsigned int index = iter->second;
+ if (m_Categories[index].m_ParentID == 0) {
+ return false;
+ } else if (m_Categories[index].m_ParentID == parentID) {
+ return true;
+ } else {
+ return isDecendantOf(m_Categories[index].m_ParentID, parentID);
+ }
+ } else {
+ qWarning("%d is no valid category id", id);
+ return false;
+ }
+}
+
+
+bool CategoryFactory::hasChildren(unsigned int index) const
+{
+ if ((index < 0) || (index >= m_Categories.size())) {
+ throw MyException(QObject::tr("invalid index %1").arg(index));
+ }
+
+ return m_Categories[index].m_HasChildren;
+}
+
+
+QString CategoryFactory::getCategoryName(unsigned int index) const
+{
+ if ((index < 0) || (index >= m_Categories.size())) {
+ throw MyException(QObject::tr("invalid index %1").arg(index));
+ }
+
+ return m_Categories[index].m_Name;
+}
+
+
+int CategoryFactory::getCategoryID(unsigned int index) const
+{
+ if ((index < 0) || (index >= m_Categories.size())) {
+ throw MyException(QObject::tr("invalid index %1").arg(index));
+ }
+
+ return m_Categories[index].m_ID;
+}
+
+
+int CategoryFactory::getCategoryIndex(int ID) const
+{
+ std::map::const_iterator iter = m_IDMap.find(ID);
+ if (iter == m_IDMap.end()) {
+ throw MyException(QObject::tr("invalid category id %1").arg(ID));
+ }
+ return iter->second;
+}
+
+
+
+unsigned int CategoryFactory::resolveNexusID(int nexusID) const
+{
+ std::map::const_iterator iter = m_NexusMap.find(nexusID);
+ if (iter != m_NexusMap.end()) {
+ qDebug("nexus category id %d maps to internal %d", nexusID, iter->second);
+ return iter->second;
+ } else {
+ qDebug("nexus category id %d not mapped", nexusID);
+ return 0U;
+ }
+}
diff --git a/src/categories.h b/src/categories.h
index bfebe1cb..96e436e5 100644
--- a/src/categories.h
+++ b/src/categories.h
@@ -1,200 +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 .
-*/
-
-#ifndef CATEGORIES_H
-#define CATEGORIES_H
-
-
-#include
-#include
-#include
-#include
-
-
-/**
- * @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 &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 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 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 &nexusID, int parentID);
-
- void setParents();
-
- static void cleanup();
-
-private:
-
- static CategoryFactory *s_Instance;
-
- std::vector m_Categories;
- std::map m_IDMap;
- std::map 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 .
+*/
+
+#ifndef CATEGORIES_H
+#define CATEGORIES_H
+
+
+#include
+#include
+#include
+#include
+
+
+/**
+ * @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 &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 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 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 &nexusID, int parentID);
+
+ void setParents();
+
+ static void cleanup();
+
+private:
+
+ static CategoryFactory *s_Instance;
+
+ std::vector m_Categories;
+ std::map m_IDMap;
+ std::map m_NexusMap;
+
+private:
+
+};
+
+
+#endif // CATEGORIES_H
diff --git a/src/categoriesdialog.cpp b/src/categoriesdialog.cpp
index 793ece66..881179a4 100644
--- a/src/categoriesdialog.cpp
+++ b/src/categoriesdialog.cpp
@@ -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 .
-*/
-
-#include "categoriesdialog.h"
-#include "ui_categoriesdialog.h"
-#include "categories.h"
-#include "utility.h"
-#include
-#include
-#include
-#include
-
-
-class NewIDValidator : public QIntValidator {
-public:
- NewIDValidator(const std::set &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 &m_UsedIDs;
-};
-
-
-class ExistingIDValidator : public QIntValidator {
-public:
- ExistingIDValidator(const std::set &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 &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(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 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::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 idItem(new QTableWidgetItem());
- idItem->setData(Qt::DisplayRole, category.m_ID);
-
- QScopedPointer nameItem(new QTableWidgetItem(category.m_Name));
- QScopedPointer nexusIDItem(new QTableWidgetItem(MOBase::VectorJoin(category.m_NexusIDs, ",")));
- QScopedPointer 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 .
+*/
+
+#include "categoriesdialog.h"
+#include "ui_categoriesdialog.h"
+#include "categories.h"
+#include "utility.h"
+#include
+#include
+#include
+#include
+
+
+class NewIDValidator : public QIntValidator {
+public:
+ NewIDValidator(const std::set &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 &m_UsedIDs;
+};
+
+
+class ExistingIDValidator : public QIntValidator {
+public:
+ ExistingIDValidator(const std::set &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 &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(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 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::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 idItem(new QTableWidgetItem());
+ idItem->setData(Qt::DisplayRole, category.m_ID);
+
+ QScopedPointer nameItem(new QTableWidgetItem(category.m_Name));
+ QScopedPointer nexusIDItem(new QTableWidgetItem(MOBase::VectorJoin(category.m_NexusIDs, ",")));
+ QScopedPointer 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));
+}
diff --git a/src/categoriesdialog.h b/src/categoriesdialog.h
index 67851618..72d2154d 100644
--- a/src/categoriesdialog.h
+++ b/src/categoriesdialog.h
@@ -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