mirror of
https://github.com/ModOrganizer2/modorganizer.git
synced 2026-07-27 13:58:24 -07:00
Compare commits
25
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0eb1662a0e | ||
|
|
164ec25a75 | ||
|
|
6fb36d6c02 | ||
|
|
ea1f959ad5 | ||
|
|
7cf3b3455b | ||
|
|
84cfa95254 | ||
|
|
264da60929 | ||
|
|
2db33523a1 | ||
|
|
540747177a | ||
|
|
739c3424e7 | ||
|
|
cabed9b268 | ||
|
|
c017f4a0d5 | ||
|
|
b1f1682790 | ||
|
|
28301e7486 | ||
|
|
2d0fab4482 | ||
|
|
c19c4820d8 | ||
|
|
8ab1b47943 | ||
|
|
ff272dcbbd | ||
|
|
98354cd1e7 | ||
|
|
129b76d7d2 | ||
|
|
a82b7e9949 | ||
|
|
0f8f7bf777 | ||
|
|
f4cf992700 | ||
|
|
bec644bac3 | ||
|
|
98e5e57a84 |
@@ -13,12 +13,12 @@ SUBDIRS = bsatk \
|
||||
nxmhandler \
|
||||
BossDummy \
|
||||
pythonRunner \
|
||||
boss_modified \
|
||||
esptk
|
||||
esptk \
|
||||
loot_cli
|
||||
|
||||
plugins.depends = pythonRunner
|
||||
hookdll.depends = shared
|
||||
organizer.depends = shared uibase plugins boss_modified
|
||||
organizer.depends = shared uibase plugins loot_cli
|
||||
|
||||
CONFIG(debug, debug|release) {
|
||||
DESTDIR = outputd
|
||||
|
||||
+24
-8
@@ -22,6 +22,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <QRegExp>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <boost/assign.hpp>
|
||||
|
||||
|
||||
namespace BBCode {
|
||||
@@ -43,7 +44,6 @@ public:
|
||||
// extract the tag name
|
||||
m_TagNameExp.indexIn(input, 1, QRegExp::CaretAtOffset);
|
||||
QString tagName = m_TagNameExp.cap(0).toLower();
|
||||
//qDebug("tag name %s", tagName.toUtf8().constData());
|
||||
TagMap::iterator tagIter = m_TagMap.find(tagName);
|
||||
if (tagIter != m_TagMap.end()) {
|
||||
// recognized tag
|
||||
@@ -60,7 +60,21 @@ public:
|
||||
length = closeTagPos + closeTag.length();
|
||||
QString temp = input.mid(0, length);
|
||||
if (tagIter->second.first.indexIn(temp) == 0) {
|
||||
return temp.replace(tagIter->second.first, tagIter->second.second);
|
||||
if (tagIter->second.second.isEmpty()) {
|
||||
if (tagName == "color") {
|
||||
QString color = tagIter->second.first.cap(1);
|
||||
QString content = tagIter->second.first.cap(2);
|
||||
auto colIter = m_ColorMap.find(color.toLower());
|
||||
if (colIter != m_ColorMap.end()) {
|
||||
color = colIter->second;
|
||||
}
|
||||
return temp.replace(tagIter->second.first, QString("<font style=\"color: #%1;\">%2</font>").arg(color, content));
|
||||
} else {
|
||||
qWarning("don't know how to deal with tag %s", qPrintable(tagName));
|
||||
}
|
||||
} else {
|
||||
return temp.replace(tagIter->second.first, tagIter->second.second);
|
||||
}
|
||||
} else {
|
||||
// expression doesn't match. either the input string is invalid
|
||||
// or the expression is
|
||||
@@ -96,7 +110,7 @@ private:
|
||||
m_TagMap["size="] = std::make_pair(QRegExp("\\[size=([^\\]]*)\\](.*)\\[/size\\]"),
|
||||
"<font size=\"\\1\">\\2</font>");
|
||||
m_TagMap["color="] = std::make_pair(QRegExp("\\[color=([^\\]]*)\\](.*)\\[/color\\]"),
|
||||
"<font style=\"color: #\\1;\">\\2</font>");
|
||||
"");
|
||||
m_TagMap["font="] = std::make_pair(QRegExp("\\[font=([^\\]]*)\\](.*)\\[/font\\]"),
|
||||
"<font face=\\1>\\2</font>");
|
||||
m_TagMap["center"] = std::make_pair(QRegExp("\\[center\\](.*)\\[/center\\]"),
|
||||
@@ -139,10 +153,6 @@ private:
|
||||
"<a href=\"\\1\">\\1</a>");
|
||||
m_TagMap["url="] = std::make_pair(QRegExp("\\[url=([^\\]]*)\\](.*)\\[/url\\]"),
|
||||
"<a href=\"\\1\">\\2</a>");
|
||||
/* m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"),
|
||||
"<img src=\"\\1\"/>");
|
||||
m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"),
|
||||
"<img src=\"\\2\" align=\"\\1\" />");*/
|
||||
m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"), "");
|
||||
m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"), "");
|
||||
m_TagMap["email="] = std::make_pair(QRegExp("\\[email=\"?([^\\]]*)\"?\\](.*)\\[/email\\]"),
|
||||
@@ -150,6 +160,11 @@ private:
|
||||
m_TagMap["youtube"] = std::make_pair(QRegExp("\\[youtube\\](.*)\\[/youtube\\]"),
|
||||
"<a href=\"http://www.youtube.com/v/\\1\">http://www.youtube.com/v/\\1</a>");
|
||||
|
||||
m_ColorMap = boost::assign::map_list_of("red", "FF0000")("green", "00FF00")("blue", "0000FF")
|
||||
("black", "000000")("gray", "7F7F7F")("white", "FFFFFF")
|
||||
("yellow", "FFFF00")("cyan", "00FFFF")("magenta", "FF00FF")
|
||||
("brown", "A52A2A")("orange", "FFCC00");
|
||||
|
||||
// make all patterns non-greedy and case-insensitive
|
||||
for (TagMap::iterator iter = m_TagMap.begin(); iter != m_TagMap.end(); ++iter) {
|
||||
iter->second.first.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
@@ -157,10 +172,11 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
QRegExp m_TagNameExp;
|
||||
TagMap m_TagMap;
|
||||
std::map<QString, QString> m_ColorMap;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
|
||||
|
||||
This file is part of Mod Organizer.
|
||||
|
||||
Mod Organizer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Mod Organizer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "browserdialog.h"
|
||||
#include "ui_browserdialog.h"
|
||||
|
||||
#include "messagedialog.h"
|
||||
#include "report.h"
|
||||
#include "json.h"
|
||||
#include "persistentcookiejar.h"
|
||||
|
||||
#include <gameinfo.h>
|
||||
|
||||
#include <utility.h>
|
||||
#include <gameinfo.h>
|
||||
#include <QNetworkCookieJar>
|
||||
#include <QNetworkCookie>
|
||||
#include <QMenu>
|
||||
#include <QInputDialog>
|
||||
#include <QWebHistory>
|
||||
#include <QDir>
|
||||
#include <QWebFrame>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
|
||||
|
||||
BrowserDialog::BrowserDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::BrowserDialog)
|
||||
, m_AccessManager(new QNetworkAccessManager)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_AccessManager->setCookieJar(new PersistentCookieJar(
|
||||
QDir::fromNativeSeparators(MOBase::ToQString(MOShared::GameInfo::instance().getCacheDir())) + "/cookies.dat", this));
|
||||
|
||||
Qt::WindowFlags flags = windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint;
|
||||
Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint;
|
||||
flags = flags & (~helpFlag);
|
||||
setWindowFlags(flags);
|
||||
|
||||
m_Tabs = this->findChild<QTabWidget*>("browserTabWidget");
|
||||
|
||||
connect(m_Tabs, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseRequested(int)));
|
||||
}
|
||||
|
||||
|
||||
BrowserDialog::~BrowserDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void BrowserDialog::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
// m_AccessManager->showCookies();
|
||||
QDialog::closeEvent(event);
|
||||
}
|
||||
|
||||
void BrowserDialog::initTab(BrowserView *newView)
|
||||
{
|
||||
newView->page()->setNetworkAccessManager(m_AccessManager);
|
||||
newView->page()->setForwardUnsupportedContent(true);
|
||||
|
||||
connect(newView, SIGNAL(loadProgress(int)), this, SLOT(progress(int)));
|
||||
connect(newView, SIGNAL(titleChanged(QString)), this, SLOT(titleChanged(QString)));
|
||||
connect(newView, SIGNAL(initTab(BrowserView*)), this, SLOT(initTab(BrowserView*)));
|
||||
connect(newView, SIGNAL(startFind()), this, SLOT(startSearch()));
|
||||
connect(newView, SIGNAL(urlChanged(QUrl)), this, SLOT(urlChanged(QUrl)));
|
||||
connect(newView, SIGNAL(openUrlInNewTab(QUrl)), this, SLOT(openInNewTab(QUrl)));
|
||||
connect(newView->page(), SIGNAL(downloadRequested(QNetworkRequest)), this, SLOT(downloadRequested(QNetworkRequest)));
|
||||
connect(newView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*)));
|
||||
|
||||
ui->backBtn->setEnabled(false);
|
||||
ui->fwdBtn->setEnabled(false);
|
||||
m_Tabs->addTab(newView, tr("new"));
|
||||
newView->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
|
||||
newView->settings()->setAttribute(QWebSettings::AutoLoadImages, true);
|
||||
}
|
||||
|
||||
|
||||
void BrowserDialog::openInNewTab(const QUrl &url)
|
||||
{
|
||||
BrowserView *newView = new BrowserView(this);
|
||||
initTab(newView);
|
||||
newView->setUrl(url);
|
||||
}
|
||||
|
||||
|
||||
BrowserView *BrowserDialog::getCurrentView()
|
||||
{
|
||||
return qobject_cast<BrowserView*>(m_Tabs->currentWidget());
|
||||
}
|
||||
|
||||
|
||||
void BrowserDialog::urlChanged(const QUrl&)
|
||||
{
|
||||
BrowserView *currentView = getCurrentView();
|
||||
if (currentView != NULL) {
|
||||
ui->backBtn->setEnabled(currentView->history()->canGoBack());
|
||||
ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BrowserDialog::openUrl(const QUrl &url)
|
||||
{
|
||||
if (isHidden()) {
|
||||
show();
|
||||
}
|
||||
openInNewTab(url);
|
||||
}
|
||||
|
||||
|
||||
void BrowserDialog::maximizeWidth()
|
||||
{
|
||||
int viewportWidth = getCurrentView()->page()->viewportSize().width();
|
||||
int frameWidth = width() - viewportWidth;
|
||||
|
||||
int contentWidth = getCurrentView()->page()->mainFrame()->contentsSize().width();
|
||||
|
||||
QDesktopWidget screen;
|
||||
int currentScreen = screen.screenNumber(this);
|
||||
int screenWidth = screen.screenGeometry(currentScreen).size().width();
|
||||
|
||||
int targetWidth = std::min<int>(std::max<int>(viewportWidth, contentWidth) + frameWidth, screenWidth);
|
||||
this->resize(targetWidth, height());
|
||||
}
|
||||
|
||||
|
||||
void BrowserDialog::progress(int value)
|
||||
{
|
||||
ui->loadProgress->setValue(value);
|
||||
if (value == 100) {
|
||||
maximizeWidth();
|
||||
ui->loadProgress->setVisible(false);
|
||||
} else {
|
||||
ui->loadProgress->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BrowserDialog::titleChanged(const QString &title)
|
||||
{
|
||||
BrowserView *view = qobject_cast<BrowserView*>(sender());
|
||||
for (int i = 0; i < m_Tabs->count(); ++i) {
|
||||
if (m_Tabs->widget(i) == view) {
|
||||
m_Tabs->setTabText(i, title.mid(0, 15));
|
||||
m_Tabs->setTabToolTip(i, title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QString BrowserDialog::guessFileName(const QString &url)
|
||||
{
|
||||
QRegExp uploadsExp(QString("http://.+/uploads/([^/]+)$"));
|
||||
if (uploadsExp.indexIn(url) != -1) {
|
||||
// these seem to be premium downloads
|
||||
return uploadsExp.cap(1);
|
||||
}
|
||||
|
||||
QRegExp filesExp(QString("http://.+\\?file=([^&]+)"));
|
||||
if (filesExp.indexIn(url) != -1) {
|
||||
// a regular manual download?
|
||||
return filesExp.cap(1);
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
void BrowserDialog::unsupportedContent(QNetworkReply *reply)
|
||||
{
|
||||
try {
|
||||
QWebPage *page = qobject_cast<QWebPage*>(sender());
|
||||
if (page == NULL) {
|
||||
qCritical("sender not a page");
|
||||
return;
|
||||
}
|
||||
BrowserView *view = qobject_cast<BrowserView*>(page->view());
|
||||
if (view == NULL) {
|
||||
qCritical("no view?");
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug("unsupported: %s - %s", view->url().toString().toUtf8().constData(), reply->url().toString().toUtf8().constData());
|
||||
emit requestDownload(view->url(), reply);
|
||||
} catch (const std::exception &e) {
|
||||
if (isVisible()) {
|
||||
MessageDialog::showMessage(tr("failed to start download"), this);
|
||||
}
|
||||
qCritical("exception downloading unsupported content: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BrowserDialog::downloadRequested(const QNetworkRequest &request)
|
||||
{
|
||||
qCritical("download request %s ignored", request.url().toString().toUtf8().constData());
|
||||
}
|
||||
|
||||
|
||||
void BrowserDialog::tabCloseRequested(int index)
|
||||
{
|
||||
if (m_Tabs->count() == 1) {
|
||||
this->close();
|
||||
} else {
|
||||
m_Tabs->widget(index)->deleteLater();
|
||||
m_Tabs->removeTab(index);
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserDialog::on_backBtn_clicked()
|
||||
{
|
||||
BrowserView *currentView = getCurrentView();
|
||||
if (currentView != NULL) {
|
||||
currentView->back();
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserDialog::on_fwdBtn_clicked()
|
||||
{
|
||||
BrowserView *currentView = getCurrentView();
|
||||
if (currentView != NULL) {
|
||||
currentView->forward();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BrowserDialog::startSearch()
|
||||
{
|
||||
ui->searchEdit->setFocus();
|
||||
}
|
||||
|
||||
|
||||
void BrowserDialog::on_searchEdit_returnPressed()
|
||||
{
|
||||
BrowserView *currentView = getCurrentView();
|
||||
if (currentView != NULL) {
|
||||
currentView->findText(ui->searchEdit->text(), QWebPage::FindWrapsAroundDocument);
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserDialog::on_browserTabWidget_currentChanged(QWidget *current)
|
||||
{
|
||||
BrowserView *currentView = qobject_cast<BrowserView*>(current);
|
||||
if (currentView != NULL) {
|
||||
ui->backBtn->setEnabled(currentView->history()->canGoBack());
|
||||
ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserDialog::on_refreshBtn_clicked()
|
||||
{
|
||||
getCurrentView()->reload();
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
|
||||
|
||||
This file is part of Mod Organizer.
|
||||
|
||||
Mod Organizer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Mod Organizer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BROWSERDIALOG_H
|
||||
#define BROWSERDIALOG_H
|
||||
|
||||
#include "browserview.h"
|
||||
#include "tutorialcontrol.h"
|
||||
#include <QDialog>
|
||||
#include <QProgressBar>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QTimer>
|
||||
#include <QWebView>
|
||||
#include <QQueue>
|
||||
#include <QTabWidget>
|
||||
#include <QAtomicInt>
|
||||
|
||||
|
||||
namespace Ui {
|
||||
class BrowserDialog;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief a dialog containing a webbrowser that is intended to browse the nexus network
|
||||
**/
|
||||
class BrowserDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
*
|
||||
* @param accessManager the access manager to use for network requests
|
||||
* @param parent parent widget
|
||||
**/
|
||||
explicit BrowserDialog(QWidget *parent = 0);
|
||||
~BrowserDialog();
|
||||
|
||||
/**
|
||||
* @brief set the url to open. If automatic login is enabled, the url is opened after login
|
||||
*
|
||||
* @param url the url to open
|
||||
**/
|
||||
void openUrl(const QUrl &url);
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
* @brief emitted when the user starts a download
|
||||
* @param pageUrl url of the current web site from which the download was started
|
||||
* @param reply network reply of the started download
|
||||
*/
|
||||
void requestDownload(const QUrl &pageUrl, QNetworkReply *reply);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void closeEvent(QCloseEvent *);
|
||||
|
||||
private slots:
|
||||
|
||||
void initTab(BrowserView *newView);
|
||||
void openInNewTab(const QUrl &url);
|
||||
|
||||
void progress(int value);
|
||||
|
||||
void titleChanged(const QString &title);
|
||||
void unsupportedContent(QNetworkReply *reply);
|
||||
void downloadRequested(const QNetworkRequest &request);
|
||||
|
||||
void tabCloseRequested(int index);
|
||||
|
||||
void urlChanged(const QUrl &url);
|
||||
|
||||
void on_backBtn_clicked();
|
||||
|
||||
void on_fwdBtn_clicked();
|
||||
|
||||
void on_searchEdit_returnPressed();
|
||||
|
||||
void startSearch();
|
||||
|
||||
void on_browserTabWidget_currentChanged(QWidget *arg1);
|
||||
|
||||
void on_refreshBtn_clicked();
|
||||
|
||||
private:
|
||||
|
||||
QString guessFileName(const QString &url);
|
||||
|
||||
BrowserView *getCurrentView();
|
||||
|
||||
void maximizeWidth();
|
||||
|
||||
private:
|
||||
|
||||
Ui::BrowserDialog *ui;
|
||||
|
||||
QNetworkAccessManager *m_AccessManager;
|
||||
|
||||
QTabWidget *m_Tabs;
|
||||
|
||||
};
|
||||
|
||||
#endif // BROWSERDIALOG_H
|
||||
@@ -0,0 +1,289 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BrowserDialog</class>
|
||||
<widget class="QDialog" name="BrowserDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1008</width>
|
||||
<height>750</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Some Page</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="toolBar" native="true">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="palette">
|
||||
<palette>
|
||||
<active>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>226</red>
|
||||
<green>226</green>
|
||||
<blue>226</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
<colorrole role="Button">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>106</red>
|
||||
<green>106</green>
|
||||
<blue>106</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
<colorrole role="ButtonText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>199</red>
|
||||
<green>199</green>
|
||||
<blue>199</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
<colorrole role="Base">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>255</red>
|
||||
<green>255</green>
|
||||
<blue>255</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
<colorrole role="Window">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>81</red>
|
||||
<green>81</green>
|
||||
<blue>81</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</active>
|
||||
<inactive>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>226</red>
|
||||
<green>226</green>
|
||||
<blue>226</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
<colorrole role="Button">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>106</red>
|
||||
<green>106</green>
|
||||
<blue>106</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
<colorrole role="ButtonText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>199</red>
|
||||
<green>199</green>
|
||||
<blue>199</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
<colorrole role="Base">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>255</red>
|
||||
<green>255</green>
|
||||
<blue>255</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
<colorrole role="Window">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>81</red>
|
||||
<green>81</green>
|
||||
<blue>81</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</inactive>
|
||||
<disabled>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>120</red>
|
||||
<green>120</green>
|
||||
<blue>120</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
<colorrole role="Button">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>106</red>
|
||||
<green>106</green>
|
||||
<blue>106</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
<colorrole role="ButtonText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>120</red>
|
||||
<green>120</green>
|
||||
<blue>120</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
<colorrole role="Base">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>81</red>
|
||||
<green>81</green>
|
||||
<blue>81</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
<colorrole role="Window">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>81</red>
|
||||
<green>81</green>
|
||||
<blue>81</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</disabled>
|
||||
</palette>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="backBtn">
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/MO/gui/previous</normaloff>:/MO/gui/previous</iconset>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="fwdBtn">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/MO/gui/next</normaloff>:/MO/gui/next</iconset>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="refreshBtn">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/MO/gui/refresh</normaloff>:/MO/gui/refresh</iconset>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="searchEdit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="browserTabWidget">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::DefaultContextMenu</enum>
|
||||
</property>
|
||||
<property name="tabsClosable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="loadProgress">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
|
||||
|
||||
This file is part of Mod Organizer.
|
||||
|
||||
Mod Organizer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Mod Organizer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "browserview.h"
|
||||
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QWebFrame>
|
||||
#include <QWebElement>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QMenu>
|
||||
#include <Shlwapi.h>
|
||||
#include "utility.h"
|
||||
|
||||
BrowserView::BrowserView(QWidget *parent)
|
||||
: QWebView(parent)
|
||||
{
|
||||
installEventFilter(this);
|
||||
|
||||
page()->settings()->setMaximumPagesInCache(10);
|
||||
}
|
||||
|
||||
|
||||
QWebView *BrowserView::createWindow(QWebPage::WebWindowType)
|
||||
{
|
||||
BrowserView *newView = new BrowserView(parentWidget());
|
||||
emit initTab(newView);
|
||||
return newView;
|
||||
}
|
||||
|
||||
|
||||
bool BrowserView::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::ShortcutOverride) {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if (keyEvent->matches(QKeySequence::Find)) {
|
||||
emit startFind();
|
||||
} else if (keyEvent->matches(QKeySequence::FindNext)) {
|
||||
emit findAgain();
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseButtonPress) {
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
if (mouseEvent->button() == Qt::MidButton) {
|
||||
mouseEvent->ignore();
|
||||
return true;
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseButtonRelease) {
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
if (mouseEvent->button() == Qt::MidButton) {
|
||||
QWebHitTestResult hitTest = page()->frameAt(mouseEvent->pos())->hitTestContent(mouseEvent->pos());
|
||||
if (hitTest.linkUrl().isValid()) {
|
||||
emit openUrlInNewTab(hitTest.linkUrl());
|
||||
}
|
||||
mouseEvent->ignore();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QWebView::eventFilter(obj, event);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
|
||||
|
||||
This file is part of Mod Organizer.
|
||||
|
||||
Mod Organizer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Mod Organizer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NEXUSVIEW_H
|
||||
#define NEXUSVIEW_H
|
||||
|
||||
#include "finddialog.h"
|
||||
|
||||
#include <QWebView>
|
||||
#include <QWebPage>
|
||||
#include <QTabWidget>
|
||||
|
||||
/**
|
||||
* @brief web view used to display a nexus page
|
||||
**/
|
||||
class BrowserView : public QWebView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit BrowserView(QWidget *parent = 0);
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
* @brief emitted when the user opens a new window to be displayed in another tab
|
||||
*
|
||||
* @param newView the view for the newly opened window
|
||||
**/
|
||||
void initTab(BrowserView *newView);
|
||||
|
||||
/**
|
||||
* @brief emitted when the user requests a link to be opened in a new tab by middle-clicking
|
||||
*
|
||||
* @param url the url to open
|
||||
*/
|
||||
void openUrlInNewTab(const QUrl &url);
|
||||
|
||||
/**
|
||||
* @brief Ctrl-f was clicked. The containing dialog should activate its find-facility
|
||||
*/
|
||||
void startFind();
|
||||
|
||||
/**
|
||||
* @brief F3 was pressed. The containing dialog should search again
|
||||
*/
|
||||
void findAgain();
|
||||
|
||||
protected:
|
||||
|
||||
virtual QWebView *createWindow(QWebPage::WebWindowType type);
|
||||
|
||||
virtual bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
QString m_FindPattern;
|
||||
bool m_MiddleClick;
|
||||
|
||||
};
|
||||
|
||||
#endif // NEXUSVIEW_H
|
||||
@@ -81,8 +81,8 @@ QVariant DownloadList::data(const QModelIndex &index, int role) const
|
||||
if (m_Manager->isInfoIncomplete(index.row())) {
|
||||
text += tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve.");
|
||||
} else {
|
||||
NexusInfo info = m_Manager->getNexusInfo(index.row());
|
||||
text += QString("%1 (ID %2) %3").arg(info.m_ModName).arg(m_Manager->getModID(index.row())).arg(info.m_Version);
|
||||
const MOBase::ModRepositoryFileInfo *info = m_Manager->getFileInfo(index.row());
|
||||
return QString("%1 (ID %2) %3<br><span>%4</span>").arg(info->modName).arg(m_Manager->getModID(index.row())).arg(info->version.canonicalString()).arg(info->description);
|
||||
}
|
||||
return text;
|
||||
} else {
|
||||
|
||||
@@ -40,8 +40,13 @@ DownloadListWidget::~DownloadListWidget()
|
||||
}
|
||||
|
||||
|
||||
DownloadListWidgetDelegate::DownloadListWidgetDelegate(DownloadManager *manager, QTreeView *view, QObject *parent)
|
||||
: QItemDelegate(parent), m_Manager(manager), m_ItemWidget(new DownloadListWidget), m_ContextRow(0), m_View(view)
|
||||
DownloadListWidgetDelegate::DownloadListWidgetDelegate(DownloadManager *manager, bool metaDisplay, QTreeView *view, QObject *parent)
|
||||
: QItemDelegate(parent)
|
||||
, m_Manager(manager)
|
||||
, m_MetaDisplay(metaDisplay)
|
||||
, m_ItemWidget(new DownloadListWidget)
|
||||
, m_ContextRow(0)
|
||||
, m_View(view)
|
||||
{
|
||||
m_NameLabel = m_ItemWidget->findChild<QLabel*>("nameLabel");
|
||||
m_SizeLabel = m_ItemWidget->findChild<QLabel*>("sizeLabel");
|
||||
@@ -95,7 +100,7 @@ void DownloadListWidgetDelegate::paintPendingDownload(int downloadIndex) const
|
||||
|
||||
void DownloadListWidgetDelegate::paintRegularDownload(int downloadIndex) const
|
||||
{
|
||||
QString name = m_Manager->getFileName(downloadIndex);
|
||||
QString name = m_MetaDisplay ? m_Manager->getDisplayName(downloadIndex) : m_Manager->getFileName(downloadIndex);
|
||||
if (name.length() > 53) {
|
||||
name.truncate(50);
|
||||
name.append("...");
|
||||
|
||||
@@ -54,7 +54,7 @@ class DownloadListWidgetDelegate : public QItemDelegate
|
||||
|
||||
public:
|
||||
|
||||
DownloadListWidgetDelegate(DownloadManager *manager, QTreeView *view, QObject *parent = 0);
|
||||
DownloadListWidgetDelegate(DownloadManager *manager, bool metaDisplay, QTreeView *view, QObject *parent = 0);
|
||||
~DownloadListWidgetDelegate();
|
||||
|
||||
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
@@ -105,6 +105,8 @@ private:
|
||||
DownloadListWidget *m_ItemWidget;
|
||||
DownloadManager *m_Manager;
|
||||
|
||||
bool m_MetaDisplay;
|
||||
|
||||
QLabel *m_NameLabel;
|
||||
QLabel *m_SizeLabel;
|
||||
QProgressBar *m_Progress;
|
||||
|
||||
@@ -40,8 +40,12 @@ DownloadListWidgetCompact::~DownloadListWidgetCompact()
|
||||
}
|
||||
|
||||
|
||||
DownloadListWidgetCompactDelegate::DownloadListWidgetCompactDelegate(DownloadManager *manager, QTreeView *view, QObject *parent)
|
||||
: QItemDelegate(parent), m_Manager(manager), m_ItemWidget(new DownloadListWidgetCompact), m_View(view)
|
||||
DownloadListWidgetCompactDelegate::DownloadListWidgetCompactDelegate(DownloadManager *manager, bool metaDisplay, QTreeView *view, QObject *parent)
|
||||
: QItemDelegate(parent)
|
||||
, m_Manager(manager)
|
||||
, m_MetaDisplay(metaDisplay)
|
||||
, m_ItemWidget(new DownloadListWidgetCompact)
|
||||
, m_View(view)
|
||||
{
|
||||
m_NameLabel = m_ItemWidget->findChild<QLabel*>("nameLabel");
|
||||
m_SizeLabel = m_ItemWidget->findChild<QLabel*>("sizeLabel");
|
||||
@@ -97,7 +101,7 @@ void DownloadListWidgetCompactDelegate::paintPendingDownload(int downloadIndex)
|
||||
|
||||
void DownloadListWidgetCompactDelegate::paintRegularDownload(int downloadIndex) const
|
||||
{
|
||||
QString name = m_Manager->getFileName(downloadIndex);
|
||||
QString name = m_MetaDisplay ? m_Manager->getDisplayName(downloadIndex) : m_Manager->getFileName(downloadIndex);
|
||||
if (name.length() > 53) {
|
||||
name.truncate(50);
|
||||
name.append("...");
|
||||
|
||||
@@ -54,7 +54,7 @@ class DownloadListWidgetCompactDelegate : public QItemDelegate
|
||||
|
||||
public:
|
||||
|
||||
DownloadListWidgetCompactDelegate(DownloadManager *manager, QTreeView *view, QObject *parent = 0);
|
||||
DownloadListWidgetCompactDelegate(DownloadManager *manager, bool metaDisplay, QTreeView *view, QObject *parent = 0);
|
||||
~DownloadListWidgetCompactDelegate();
|
||||
|
||||
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
@@ -103,6 +103,8 @@ private:
|
||||
DownloadListWidgetCompact *m_ItemWidget;
|
||||
DownloadManager *m_Manager;
|
||||
|
||||
bool m_MetaDisplay;
|
||||
|
||||
QLabel *m_NameLabel;
|
||||
QLabel *m_SizeLabel;
|
||||
QProgressBar *m_Progress;
|
||||
|
||||
+168
-79
@@ -27,6 +27,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "json.h"
|
||||
#include "selectiondialog.h"
|
||||
#include <utility.h>
|
||||
#include <bbcode.h>
|
||||
#include <QTimer>
|
||||
#include <QFileInfo>
|
||||
#include <QRegExp>
|
||||
@@ -49,7 +50,7 @@ static const char UNFINISHED[] = ".unfinished";
|
||||
unsigned int DownloadManager::DownloadInfo::s_NextDownloadID = 1U;
|
||||
|
||||
|
||||
DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createNew(const NexusInfo &nexusInfo, int modID, int fileID, const QStringList &URLs)
|
||||
DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createNew(const ModRepositoryFileInfo *fileInfo, const QStringList &URLs)
|
||||
{
|
||||
DownloadInfo *info = new DownloadInfo;
|
||||
info->m_DownloadID = s_NextDownloadID++;
|
||||
@@ -57,9 +58,7 @@ DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createNew(const Ne
|
||||
info->m_PreResumeSize = 0LL;
|
||||
info->m_Progress = 0;
|
||||
info->m_ResumePos = 0;
|
||||
info->m_ModID = modID;
|
||||
info->m_FileID = fileID;
|
||||
info->m_NexusInfo = nexusInfo;
|
||||
info->m_FileInfo = new ModRepositoryFileInfo(*fileInfo);
|
||||
info->m_Urls = URLs;
|
||||
info->m_CurrentUrl = 0;
|
||||
info->m_Tries = AUTOMATIC_RETRIES;
|
||||
@@ -104,17 +103,28 @@ DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createFromMeta(con
|
||||
info->m_Output.setFileName(filePath);
|
||||
info->m_TotalSize = QFileInfo(filePath).size();
|
||||
info->m_PreResumeSize = info->m_TotalSize;
|
||||
info->m_ModID = metaFile.value("modID", 0).toInt();
|
||||
info->m_FileID = metaFile.value("fileID", 0).toInt();
|
||||
info->m_CurrentUrl = 0;
|
||||
info->m_Urls = metaFile.value("url", "").toString().split(";");
|
||||
info->m_Tries = 0;
|
||||
info->m_TaskProgressId = TaskProgressManager::instance().getId();
|
||||
info->m_NexusInfo.m_Name = metaFile.value("name", 0).toString();
|
||||
info->m_NexusInfo.m_ModName = metaFile.value("modName", "").toString();
|
||||
info->m_NexusInfo.m_Version = metaFile.value("version", 0).toString();
|
||||
info->m_NexusInfo.m_NewestVersion = metaFile.value("newestVersion", "").toString();
|
||||
info->m_NexusInfo.m_Category = metaFile.value("category", 0).toInt();
|
||||
int modID = metaFile.value("modID", 0).toInt();
|
||||
int fileID = metaFile.value("fileID", 0).toInt();
|
||||
info->m_FileInfo = new ModRepositoryFileInfo(modID, fileID);
|
||||
info->m_FileInfo->name = metaFile.value("name", "").toString();
|
||||
if (info->m_FileInfo->name == "0") {
|
||||
// bug in earlier version
|
||||
info->m_FileInfo->name = "";
|
||||
}
|
||||
info->m_FileInfo->modName = metaFile.value("modName", "").toString();
|
||||
info->m_FileInfo->modID = modID;
|
||||
info->m_FileInfo->fileID = fileID;
|
||||
info->m_FileInfo->description = metaFile.value("description").toString();
|
||||
info->m_FileInfo->version.parse(metaFile.value("version", "0").toString());
|
||||
info->m_FileInfo->newestVersion.parse(metaFile.value("newestVersion", "0").toString());
|
||||
info->m_FileInfo->categoryID = metaFile.value("category", 0).toInt();
|
||||
info->m_FileInfo->fileCategory = metaFile.value("fileCategory", 0).toInt();
|
||||
info->m_FileInfo->repository = metaFile.value("repository", "Nexus").toString();
|
||||
info->m_FileInfo->userData = metaFile.value("userData").toMap();
|
||||
|
||||
return info;
|
||||
}
|
||||
@@ -308,7 +318,7 @@ void DownloadManager::refreshList()
|
||||
|
||||
|
||||
bool DownloadManager::addDownload(const QStringList &URLs,
|
||||
int modID, int fileID, const NexusInfo &nexusInfo)
|
||||
int modID, int fileID, const ModRepositoryFileInfo *fileInfo)
|
||||
{
|
||||
QString fileName = QFileInfo(URLs.first()).fileName();
|
||||
if (fileName.isEmpty()) {
|
||||
@@ -316,20 +326,31 @@ bool DownloadManager::addDownload(const QStringList &URLs,
|
||||
}
|
||||
|
||||
QNetworkRequest request(URLs.first());
|
||||
return addDownload(m_NexusInterface->getAccessManager()->get(request), URLs, fileName, modID, fileID, nexusInfo);
|
||||
return addDownload(m_NexusInterface->getAccessManager()->get(request), URLs, fileName, modID, fileID, fileInfo);
|
||||
}
|
||||
|
||||
|
||||
bool DownloadManager::addDownload(QNetworkReply *reply, const ModRepositoryFileInfo *fileInfo)
|
||||
{
|
||||
QString fileName = getFileNameFromNetworkReply(reply);
|
||||
if (fileName.isEmpty()) {
|
||||
fileName = "unknown";
|
||||
}
|
||||
|
||||
return addDownload(reply, QStringList(reply->url().toString()), fileName, fileInfo->modID, fileInfo->fileID, fileInfo);
|
||||
}
|
||||
|
||||
|
||||
bool DownloadManager::addDownload(QNetworkReply *reply, const QStringList &URLs, const QString &fileName,
|
||||
int modID, int fileID, const NexusInfo &nexusInfo)
|
||||
int modID, int fileID, const ModRepositoryFileInfo *fileInfo)
|
||||
{
|
||||
// download invoked from an already open network reply (i.e. download link in the browser)
|
||||
DownloadInfo *newDownload = DownloadInfo::createNew(nexusInfo, modID, fileID, URLs);
|
||||
DownloadInfo *newDownload = DownloadInfo::createNew(fileInfo, URLs);
|
||||
|
||||
QString baseName = fileName;
|
||||
|
||||
if (!nexusInfo.m_FileName.isEmpty()) {
|
||||
baseName = nexusInfo.m_FileName;
|
||||
if (!fileInfo->fileName.isEmpty()) {
|
||||
baseName = fileInfo->fileName;
|
||||
} else {
|
||||
QString dispoName = getFileNameFromNetworkReply(reply);
|
||||
|
||||
@@ -397,8 +418,7 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl
|
||||
|
||||
if (!resume) {
|
||||
newDownload->m_PreResumeSize = newDownload->m_Output.size();
|
||||
|
||||
removePending(newDownload->m_ModID, newDownload->m_FileID);
|
||||
removePending(newDownload->m_FileInfo->modID, newDownload->m_FileInfo->fileID);
|
||||
|
||||
emit aboutToUpdate();
|
||||
|
||||
@@ -424,7 +444,6 @@ void DownloadManager::addNXMDownload(const QString &url)
|
||||
}
|
||||
|
||||
emit aboutToUpdate();
|
||||
|
||||
m_PendingDownloads.append(std::make_pair(nxmInfo.modId(), nxmInfo.fileId()));
|
||||
|
||||
emit update(-1);
|
||||
@@ -635,16 +654,21 @@ void DownloadManager::queryInfo(int index)
|
||||
}
|
||||
DownloadInfo *info = m_ActiveDownloads[index];
|
||||
|
||||
if (info->m_FileInfo->repository != "Nexus") {
|
||||
qWarning("re-querying file info is currently only possible with Nexus");
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->m_State < DownloadManager::STATE_READY) {
|
||||
// UI shouldn't allow this
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->m_ModID == 0UL) {
|
||||
if (info->m_FileInfo->modID == 0UL) {
|
||||
QString fileName = getFileName(index);
|
||||
QString ignore;
|
||||
NexusInterface::interpretNexusFileName(fileName, ignore, info->m_ModID, true);
|
||||
if (info->m_ModID < 0) {
|
||||
NexusInterface::interpretNexusFileName(fileName, ignore, info->m_FileInfo->modID, true);
|
||||
if (info->m_FileInfo->modID < 0) {
|
||||
QString modIDString;
|
||||
while (modIDString.isEmpty()) {
|
||||
modIDString = QInputDialog::getText(NULL, tr("Please enter the nexus mod id"), tr("Mod ID:"), QLineEdit::Normal,
|
||||
@@ -657,12 +681,11 @@ void DownloadManager::queryInfo(int index)
|
||||
modIDString.clear();
|
||||
}
|
||||
}
|
||||
info->m_ModID = modIDString.toInt(NULL, 10);
|
||||
info->m_FileInfo->modID = modIDString.toInt(NULL, 10);
|
||||
}
|
||||
}
|
||||
info->m_ReQueried = true;
|
||||
setState(info, STATE_FETCHINGMODINFO);
|
||||
// m_RequestIDs.insert(m_NexusInterface->requestFiles(info->m_ModID, this, qVariantFromValue(static_cast<void*>(info))));
|
||||
}
|
||||
|
||||
|
||||
@@ -694,6 +717,34 @@ QString DownloadManager::getFilePath(int index) const
|
||||
return m_OutputDirectory + "/" + m_ActiveDownloads.at(index)->m_FileName;
|
||||
}
|
||||
|
||||
QString DownloadManager::getFileTypeString(int fileType)
|
||||
{
|
||||
switch (fileType) {
|
||||
case 1: return tr("Main");
|
||||
case 2: return tr("Update");
|
||||
case 3: return tr("Optional");
|
||||
case 4: return tr("Old");
|
||||
case 5: return tr("Misc");
|
||||
default: return tr("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
QString DownloadManager::getDisplayName(int index) const
|
||||
{
|
||||
if ((index < 0) || (index >= m_ActiveDownloads.size())) {
|
||||
throw MyException(tr("invalid index"));
|
||||
}
|
||||
|
||||
DownloadInfo *info = m_ActiveDownloads.at(index);
|
||||
|
||||
if (!info->m_FileInfo->name.isEmpty()) {
|
||||
return QString("%1 (%2, v%3)").arg(info->m_FileInfo->name)
|
||||
.arg(getFileTypeString(info->m_FileInfo->fileCategory))
|
||||
.arg(info->m_FileInfo->version.displayString());
|
||||
} else {
|
||||
return info->m_FileName;
|
||||
}
|
||||
}
|
||||
|
||||
QString DownloadManager::getFileName(int index) const
|
||||
{
|
||||
@@ -755,7 +806,11 @@ bool DownloadManager::isInfoIncomplete(int index) const
|
||||
}
|
||||
|
||||
DownloadInfo *info = m_ActiveDownloads.at(index);
|
||||
return (info->m_FileID == 0) || (info->m_ModID == 0) || info->m_NexusInfo.m_Version.isEmpty();
|
||||
if (info->m_FileInfo->repository != "Nexus") {
|
||||
// other repositories currently don't support re-querying info anyway
|
||||
return false;
|
||||
}
|
||||
return (info->m_FileInfo->fileID == 0) || (info->m_FileInfo->modID == 0) || !info->m_FileInfo->version.isValid();
|
||||
}
|
||||
|
||||
|
||||
@@ -764,7 +819,7 @@ int DownloadManager::getModID(int index) const
|
||||
if ((index < 0) || (index >= m_ActiveDownloads.size())) {
|
||||
throw MyException(tr("invalid index"));
|
||||
}
|
||||
return m_ActiveDownloads.at(index)->m_ModID;
|
||||
return m_ActiveDownloads.at(index)->m_FileInfo->modID;
|
||||
}
|
||||
|
||||
bool DownloadManager::isHidden(int index) const
|
||||
@@ -776,13 +831,13 @@ bool DownloadManager::isHidden(int index) const
|
||||
}
|
||||
|
||||
|
||||
NexusInfo DownloadManager::getNexusInfo(int index) const
|
||||
const ModRepositoryFileInfo *DownloadManager::getFileInfo(int index) const
|
||||
{
|
||||
if ((index < 0) || (index >= m_ActiveDownloads.size())) {
|
||||
throw MyException(tr("invalid index"));
|
||||
}
|
||||
|
||||
return m_ActiveDownloads.at(index)->m_NexusInfo;
|
||||
return m_ActiveDownloads.at(index)->m_FileInfo;
|
||||
}
|
||||
|
||||
|
||||
@@ -864,10 +919,10 @@ void DownloadManager::setState(DownloadManager::DownloadInfo *info, DownloadMana
|
||||
info->m_Reply->abort();
|
||||
} break;
|
||||
case STATE_FETCHINGMODINFO: {
|
||||
m_RequestIDs.insert(m_NexusInterface->requestDescription(info->m_ModID, this, info->m_DownloadID));
|
||||
m_RequestIDs.insert(m_NexusInterface->requestDescription(info->m_FileInfo->modID, this, info->m_DownloadID));
|
||||
} break;
|
||||
case STATE_FETCHINGFILEINFO: {
|
||||
m_RequestIDs.insert(m_NexusInterface->requestFiles(info->m_ModID, this, info->m_DownloadID));
|
||||
m_RequestIDs.insert(m_NexusInterface->requestFiles(info->m_FileInfo->modID, this, info->m_DownloadID));
|
||||
} break;
|
||||
case STATE_READY: {
|
||||
createMetaFile(info);
|
||||
@@ -933,16 +988,19 @@ void DownloadManager::downloadReadyRead()
|
||||
void DownloadManager::createMetaFile(DownloadInfo *info)
|
||||
{
|
||||
QSettings metaFile(QString("%1.meta").arg(info->m_Output.fileName()), QSettings::IniFormat);
|
||||
metaFile.setValue("modID", info->m_ModID);
|
||||
metaFile.setValue("fileID", info->m_FileID);
|
||||
metaFile.setValue("modID", info->m_FileInfo->modID);
|
||||
metaFile.setValue("fileID", info->m_FileInfo->fileID);
|
||||
metaFile.setValue("url", info->m_Urls.join(";"));
|
||||
metaFile.setValue("name", info->m_NexusInfo.m_Name);
|
||||
metaFile.setValue("modName", info->m_NexusInfo.m_ModName);
|
||||
metaFile.setValue("version", info->m_NexusInfo.m_Version);
|
||||
metaFile.setValue("fileTime", info->m_NexusInfo.m_FileTime);
|
||||
metaFile.setValue("fileCategory", info->m_NexusInfo.m_FileCategory);
|
||||
metaFile.setValue("newestVersion", info->m_NexusInfo.m_NewestVersion);
|
||||
metaFile.setValue("category", info->m_NexusInfo.m_Category);
|
||||
metaFile.setValue("name", info->m_FileInfo->name);
|
||||
metaFile.setValue("description", info->m_FileInfo->description);
|
||||
metaFile.setValue("modName", info->m_FileInfo->modName);
|
||||
metaFile.setValue("version", info->m_FileInfo->version.canonicalString());
|
||||
metaFile.setValue("newestVersion", info->m_FileInfo->newestVersion.canonicalString());
|
||||
metaFile.setValue("fileTime", info->m_FileInfo->fileTime);
|
||||
metaFile.setValue("fileCategory", info->m_FileInfo->fileCategory);
|
||||
metaFile.setValue("category", info->m_FileInfo->categoryID);
|
||||
metaFile.setValue("repository", info->m_FileInfo->repository);
|
||||
metaFile.setValue("userData", info->m_FileInfo->userData);
|
||||
metaFile.setValue("installed", info->m_State == DownloadManager::STATE_INSTALLED);
|
||||
metaFile.setValue("uninstalled", info->m_State == DownloadManager::STATE_UNINSTALLED);
|
||||
metaFile.setValue("paused", (info->m_State == DownloadManager::STATE_PAUSED) ||
|
||||
@@ -971,10 +1029,10 @@ void DownloadManager::nxmDescriptionAvailable(int, QVariant userData, QVariant r
|
||||
|
||||
DownloadInfo *info = downloadInfoByID(userData.toInt());
|
||||
if (info == NULL) return;
|
||||
info->m_NexusInfo.m_Category = result["category_id"].toInt();
|
||||
info->m_NexusInfo.m_ModName = result["name"].toString().trimmed();
|
||||
info->m_NexusInfo.m_NewestVersion = result["version"].toString();
|
||||
if (info->m_FileID != 0) {
|
||||
info->m_FileInfo->categoryID = result["category_id"].toInt();
|
||||
info->m_FileInfo->modName = result["name"].toString().trimmed();
|
||||
info->m_FileInfo->newestVersion.parse(result["version"].toString());
|
||||
if (info->m_FileInfo->fileID != 0) {
|
||||
setState(info, STATE_READY);
|
||||
} else {
|
||||
setState(info, STATE_FETCHINGFILEINFO);
|
||||
@@ -993,6 +1051,18 @@ QDateTime DownloadManager::matchDate(const QString &timeString)
|
||||
}
|
||||
|
||||
|
||||
EFileCategory convertFileCategory(int id)
|
||||
{
|
||||
// TODO: need to handle file categories in the mod page plugin
|
||||
switch (id) {
|
||||
case 0: return TYPE_MAIN;
|
||||
case 1: return TYPE_UPDATE;
|
||||
case 2: return TYPE_OPTION;
|
||||
default: return TYPE_MAIN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DownloadManager::nxmFilesAvailable(int, QVariant userData, QVariant resultData, int requestID)
|
||||
{
|
||||
std::set<int>::iterator idIter = m_RequestIDs.find(requestID);
|
||||
@@ -1024,14 +1094,14 @@ void DownloadManager::nxmFilesAvailable(int, QVariant userData, QVariant resultD
|
||||
QString fileNameVariant = fileName.mid(0).replace(' ', '_');
|
||||
if ((fileName == info->m_FileName) || (fileName == alternativeLocalName) ||
|
||||
(fileNameVariant == info->m_FileName) || (fileNameVariant == alternativeLocalName)) {
|
||||
info->m_NexusInfo.m_Name = fileInfo["name"].toString();
|
||||
info->m_NexusInfo.m_Version = fileInfo["version"].toString();
|
||||
if (info->m_NexusInfo.m_Version.isEmpty()) {
|
||||
info->m_NexusInfo.m_Version = info->m_NexusInfo.m_NewestVersion;
|
||||
info->m_FileInfo->name = fileInfo["name"].toString();
|
||||
info->m_FileInfo->version.parse(fileInfo["version"].toString());
|
||||
if (!info->m_FileInfo->version.isValid()) {
|
||||
info->m_FileInfo->version = info->m_FileInfo->newestVersion;
|
||||
}
|
||||
info->m_NexusInfo.m_FileCategory = fileInfo["category_id"].toInt();
|
||||
info->m_NexusInfo.m_FileTime = matchDate(fileInfo["date"].toString());
|
||||
info->m_FileID = fileInfo["id"].toInt();
|
||||
info->m_FileInfo->fileCategory = convertFileCategory(fileInfo["category_id"].toInt());
|
||||
info->m_FileInfo->fileTime = matchDate(fileInfo["date"].toString());
|
||||
info->m_FileInfo->fileID = fileInfo["id"].toInt();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -1050,16 +1120,16 @@ void DownloadManager::nxmFilesAvailable(int, QVariant userData, QVariant resultD
|
||||
}
|
||||
if (selection.exec() == QDialog::Accepted) {
|
||||
QVariantMap fileInfo = selection.getChoiceData().toMap();
|
||||
info->m_NexusInfo.m_Name = fileInfo["name"].toString();
|
||||
info->m_NexusInfo.m_Version = fileInfo["version"].toString();
|
||||
info->m_NexusInfo.m_FileCategory = fileInfo["category_id"].toInt();
|
||||
info->m_FileID = fileInfo["id"].toInt();
|
||||
info->m_FileInfo->name = fileInfo["name"].toString();
|
||||
info->m_FileInfo->version.parse(fileInfo["version"].toString());
|
||||
info->m_FileInfo->fileCategory = convertFileCategory(fileInfo["category_id"].toInt());
|
||||
info->m_FileInfo->fileID = fileInfo["id"].toInt();
|
||||
} else {
|
||||
emit showMessage(tr("No matching file found on Nexus! Maybe this file is no longer available or it was renamed?"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (info->m_FileID == 0) {
|
||||
if (info->m_FileInfo->fileID == 0) {
|
||||
qWarning("could not determine file id for %s (state %d)",
|
||||
info->m_FileName.toUtf8().constData(), info->m_State);
|
||||
}
|
||||
@@ -1078,19 +1148,26 @@ void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant userD
|
||||
m_RequestIDs.erase(idIter);
|
||||
}
|
||||
|
||||
NexusInfo info;
|
||||
ModRepositoryFileInfo *info = new ModRepositoryFileInfo();
|
||||
|
||||
QVariantMap result = resultData.toMap();
|
||||
info.m_Name = result["name"].toString();
|
||||
qDebug("file info received for %s", qPrintable(info.m_Name));
|
||||
info.m_Version = result["version"].toString();
|
||||
if (info.m_Version.isEmpty()) {
|
||||
info.m_Version = info.m_NewestVersion;
|
||||
info->name = result["name"].toString();
|
||||
qDebug("file info received for %s", qPrintable(info->name));
|
||||
info->version.parse(result["version"].toString());
|
||||
if (!info->version.isValid()) {
|
||||
info->version = info->newestVersion;
|
||||
}
|
||||
info.m_FileName = result["uri"].toString();
|
||||
info.m_FileTime = matchDate(result["date"].toString());
|
||||
info->fileName = result["uri"].toString();
|
||||
info->fileCategory = result["category_id"].toInt();
|
||||
info->fileTime = matchDate(result["date"].toString());
|
||||
info->description = BBCode::convertToHTML(result["description"].toString());
|
||||
|
||||
m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, QVariant::fromValue(info)));
|
||||
info->repository = "Nexus";
|
||||
info->modID = modID;
|
||||
info->fileID = fileID;
|
||||
|
||||
QObject *test = info;
|
||||
m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, qVariantFromValue(test)));
|
||||
}
|
||||
|
||||
|
||||
@@ -1138,7 +1215,7 @@ bool DownloadManager::ServerByPreference(const std::map<QString, int> &preferred
|
||||
|
||||
int DownloadManager::startDownloadURLs(const QStringList &urls)
|
||||
{
|
||||
addDownload(urls, -1);
|
||||
addDownload(urls, -1, -1, nullptr);
|
||||
return m_ActiveDownloads.size() - 1;
|
||||
}
|
||||
|
||||
@@ -1173,7 +1250,7 @@ void DownloadManager::nxmDownloadURLsAvailable(int modID, int fileID, QVariant u
|
||||
m_RequestIDs.erase(idIter);
|
||||
}
|
||||
|
||||
NexusInfo info = userData.value<NexusInfo>();
|
||||
ModRepositoryFileInfo *info = qobject_cast<ModRepositoryFileInfo*>(qvariant_cast<QObject*>(userData));
|
||||
QVariantList resultList = resultData.toList();
|
||||
if (resultList.length() == 0) {
|
||||
removePending(modID, fileID);
|
||||
@@ -1183,7 +1260,7 @@ void DownloadManager::nxmDownloadURLsAvailable(int modID, int fileID, QVariant u
|
||||
|
||||
std::sort(resultList.begin(), resultList.end(), boost::bind(&DownloadManager::ServerByPreference, m_PreferredServers, _1, _2));
|
||||
|
||||
info.m_DownloadMap = resultList;
|
||||
info->userData["downloadMap"] = resultList;
|
||||
|
||||
QStringList URLs;
|
||||
|
||||
@@ -1208,7 +1285,7 @@ void DownloadManager::nxmRequestFailed(int modID, int fileID, QVariant userData,
|
||||
|
||||
for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter, ++index) {
|
||||
DownloadInfo *info = *iter;
|
||||
if (info->m_ModID == modID) {
|
||||
if (info->m_FileInfo->modID == modID) {
|
||||
if (info->m_State < STATE_FETCHINGMODINFO) {
|
||||
m_ActiveDownloads.erase(iter);
|
||||
delete info;
|
||||
@@ -1246,7 +1323,7 @@ void DownloadManager::downloadFinished()
|
||||
textData) {
|
||||
if (info->m_Tries == 0) {
|
||||
if (textData && (reply->error() == QNetworkReply::NoError)) {
|
||||
emit showMessage(tr("Download failed. Server reported: %1").arg(readFileText(info->m_Output.fileName())));
|
||||
emit showMessage(tr("Download failed. Server reported: %1").arg(QString(data)));
|
||||
} else {
|
||||
emit showMessage(tr("Download failed: %1 (%2)").arg(reply->errorString()).arg(reply->error()));
|
||||
}
|
||||
@@ -1281,18 +1358,26 @@ void DownloadManager::downloadFinished()
|
||||
} else {
|
||||
|
||||
QString url = info->m_Urls[info->m_CurrentUrl];
|
||||
foreach (const QVariant &server, info->m_NexusInfo.m_DownloadMap) {
|
||||
QVariantMap serverMap = server.toMap();
|
||||
if (serverMap["URI"].toString() == url) {
|
||||
int deltaTime = info->m_StartTime.secsTo(QTime::currentTime());
|
||||
if (deltaTime > 5) {
|
||||
emit downloadSpeed(serverMap["Name"].toString(), (info->m_TotalSize - info->m_PreResumeSize) / deltaTime);
|
||||
} // no division by zero please! Also, if the download is shorter than a few seconds, the result is way to inprecise
|
||||
break;
|
||||
if (info->m_FileInfo->userData.contains("downloadMap")) {
|
||||
foreach (const QVariant &server, info->m_FileInfo->userData["downloadMap"].toList()) {
|
||||
QVariantMap serverMap = server.toMap();
|
||||
if (serverMap["URI"].toString() == url) {
|
||||
int deltaTime = info->m_StartTime.secsTo(QTime::currentTime());
|
||||
if (deltaTime > 5) {
|
||||
emit downloadSpeed(serverMap["Name"].toString(), (info->m_TotalSize - info->m_PreResumeSize) / deltaTime);
|
||||
} // no division by zero please! Also, if the download is shorter than a few seconds, the result is way to inprecise
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setState(info, STATE_FETCHINGMODINFO); // need to set this state before changing the file name, otherwise .unfinished is appended
|
||||
bool isNexus = info->m_FileInfo->repository == "Nexus";
|
||||
// need to change state before changing the file name, otherwise .unfinished is appended
|
||||
if (isNexus) {
|
||||
setState(info, STATE_FETCHINGMODINFO);
|
||||
} else {
|
||||
setState(info, STATE_NOFETCH);
|
||||
}
|
||||
|
||||
QString newName = getFileNameFromNetworkReply(reply);
|
||||
QString oldName = QFileInfo(info->m_Output).fileName();
|
||||
@@ -1302,6 +1387,10 @@ void DownloadManager::downloadFinished()
|
||||
info->setName(m_OutputDirectory + "/" + info->m_FileName, true); // don't rename but remove the ".unfinished" extension
|
||||
}
|
||||
|
||||
if (!isNexus) {
|
||||
setState(info, STATE_READY);
|
||||
}
|
||||
|
||||
emit update(index);
|
||||
}
|
||||
reply->close();
|
||||
|
||||
+29
-31
@@ -36,22 +36,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <QSettings>
|
||||
|
||||
|
||||
struct NexusInfo {
|
||||
NexusInfo() : m_Category(0), m_FileCategory(0), m_Set(false) {}
|
||||
int m_Category;
|
||||
int m_FileCategory;
|
||||
QString m_Name;
|
||||
QString m_ModName;
|
||||
QString m_Version;
|
||||
QString m_NewestVersion;
|
||||
QString m_FileName;
|
||||
QVariantList m_DownloadMap;
|
||||
QDateTime m_FileTime;
|
||||
bool m_Set;
|
||||
};
|
||||
Q_DECLARE_METATYPE(NexusInfo)
|
||||
|
||||
|
||||
/*!
|
||||
* \brief manages downloading of files and provides progress information for gui elements
|
||||
**/
|
||||
@@ -71,6 +55,7 @@ public:
|
||||
STATE_ERROR,
|
||||
STATE_FETCHINGMODINFO,
|
||||
STATE_FETCHINGFILEINFO,
|
||||
STATE_NOFETCH,
|
||||
STATE_READY,
|
||||
STATE_INSTALLED,
|
||||
STATE_UNINSTALLED
|
||||
@@ -79,6 +64,7 @@ public:
|
||||
private:
|
||||
|
||||
struct DownloadInfo {
|
||||
~DownloadInfo() { delete m_FileInfo; }
|
||||
unsigned int m_DownloadID;
|
||||
QString m_FileName;
|
||||
QFile m_Output;
|
||||
@@ -86,14 +72,11 @@ private:
|
||||
QTime m_StartTime;
|
||||
qint64 m_PreResumeSize;
|
||||
int m_Progress;
|
||||
int m_ModID;
|
||||
int m_FileID;
|
||||
DownloadState m_State;
|
||||
int m_CurrentUrl;
|
||||
QStringList m_Urls;
|
||||
qint64 m_ResumePos;
|
||||
qint64 m_TotalSize;
|
||||
|
||||
QDateTime m_Created; // used as a cache in DownloadManager::getFileTime, may not be valid elsewhere
|
||||
|
||||
int m_Tries;
|
||||
@@ -101,11 +84,11 @@ private:
|
||||
|
||||
quint32 m_TaskProgressId;
|
||||
|
||||
NexusInfo m_NexusInfo;
|
||||
MOBase::ModRepositoryFileInfo *m_FileInfo;
|
||||
|
||||
bool m_Hidden;
|
||||
|
||||
static DownloadInfo *createNew(const NexusInfo &nexusInfo, int modID, int fileID, const QStringList &URLs);
|
||||
static DownloadInfo *createNew(const MOBase::ModRepositoryFileInfo *fileInfo, const QStringList &URLs);
|
||||
static DownloadInfo *createFromMeta(const QString &filePath, bool showHidden);
|
||||
|
||||
/**
|
||||
@@ -180,13 +163,20 @@ public:
|
||||
* @brief download from an already open network connection
|
||||
*
|
||||
* @param reply the network reply to download from
|
||||
* @param fileName the name to use for the file. This may be overridden by the name in the nexusInfo-structure or if the http stream specifies a name
|
||||
* @param modID the nexus mod id this download belongs to
|
||||
* @param fileID the nexus file id this download belongs to, if known. Defaults to 0.
|
||||
* @param nexusInfo information previously retrieved from the nexus network
|
||||
* @param fileInfo information about the file, like mod id, file id, version, ...
|
||||
* @return true if the download was started, false if it wasn't. The latter currently only happens if there is a duplicate and the user decides not to download again
|
||||
**/
|
||||
bool addDownload(QNetworkReply *reply, const QStringList &URLs, const QString &fileName, int modID, int fileID = 0, const NexusInfo &nexusInfo = NexusInfo());
|
||||
bool addDownload(QNetworkReply *reply, const MOBase::ModRepositoryFileInfo *fileInfo);
|
||||
|
||||
/**
|
||||
* @brief download from an already open network connection
|
||||
*
|
||||
* @param reply the network reply to download from
|
||||
* @param fileName the name to use for the file. This may be overridden by the name in the fileInfo-structure or if the http stream specifies a name
|
||||
* @param fileInfo information previously retrieved from the nexus network
|
||||
* @return true if the download was started, false if it wasn't. The latter currently only happens if there is a duplicate and the user decides not to download again
|
||||
**/
|
||||
bool addDownload(QNetworkReply *reply, const QStringList &URLs, const QString &fileName, int modID, int fileID = 0, const MOBase::ModRepositoryFileInfo *fileInfo = new MOBase::ModRepositoryFileInfo());
|
||||
|
||||
/**
|
||||
* @brief start a download using a nxm-link
|
||||
@@ -226,6 +216,14 @@ public:
|
||||
**/
|
||||
QString getFilePath(int index) const;
|
||||
|
||||
/**
|
||||
* @brief retrieve a descriptive name of the download specified by index
|
||||
*
|
||||
* @param index index of the file to look up
|
||||
* @return display name of the file
|
||||
**/
|
||||
QString getDisplayName(int index) const;
|
||||
|
||||
/**
|
||||
* @brief retrieve the filename of the download specified by index
|
||||
*
|
||||
@@ -297,7 +295,7 @@ public:
|
||||
* @param index index of the file to look up
|
||||
* @return the nexus mod information
|
||||
**/
|
||||
NexusInfo getNexusInfo(int index) const;
|
||||
const MOBase::ModRepositoryFileInfo *getFileInfo(int index) const;
|
||||
|
||||
/**
|
||||
* @brief mark a download as installed
|
||||
@@ -434,12 +432,10 @@ private:
|
||||
* @brief start a download from a url
|
||||
*
|
||||
* @param url the url to download from
|
||||
* @param modID the nexus mod id this download belongs to
|
||||
* @param fileID the nexus file id this download belongs to, if known. Defaults to 0.
|
||||
* @param nexusInfo information previously retrieved from the nexus network
|
||||
* @param fileInfo information previously retrieved from the mod page
|
||||
* @return true if the download was started, false if it wasn't. The latter currently only happens if there is a duplicate and the user decides not to download again
|
||||
**/
|
||||
bool addDownload(const QStringList &URLs, int modID, int fileID = 0, const NexusInfo &nexusInfo = NexusInfo());
|
||||
bool addDownload(const QStringList &URLs, int modID, int fileID, const MOBase::ModRepositoryFileInfo *fileInfo);
|
||||
|
||||
// important: the caller has to lock the list-mutex, otherwise the DownloadInfo-pointer might get invalidated at any time
|
||||
DownloadInfo *findDownload(QObject *reply, int *index = NULL) const;
|
||||
@@ -460,6 +456,8 @@ private:
|
||||
|
||||
void removePending(int modID, int fileID);
|
||||
|
||||
static QString getFileTypeString(int fileType);
|
||||
|
||||
private:
|
||||
|
||||
static const int AUTOMATIC_RETRIES = 3;
|
||||
|
||||
@@ -68,7 +68,6 @@ void ExecutablesList::init()
|
||||
{
|
||||
std::vector<ExecutableInfo> executables = GameInfo::instance().getExecutables();
|
||||
for (std::vector<ExecutableInfo>::const_iterator iter = executables.begin(); iter != executables.end(); ++iter) {
|
||||
ExecutableInfo test = *iter;
|
||||
addExecutableInternal(ToQString(iter->title),
|
||||
QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())).append("/").append(ToQString(iter->binary)),
|
||||
ToQString(iter->arguments), ToQString(iter->workingDirectory),
|
||||
|
||||
@@ -69,7 +69,7 @@ template <typename T> T resolveFunction(QLibrary &lib, const char *name)
|
||||
|
||||
InstallationManager::InstallationManager(QWidget *parent)
|
||||
: QObject(parent), m_ParentWidget(parent),
|
||||
m_InstallationProgress(parent), m_SupportedExtensions(boost::assign::list_of("zip")("rar")("7z")("fomod"))
|
||||
m_InstallationProgress(parent), m_SupportedExtensions(boost::assign::list_of("zip")("rar")("7z")("fomod")("001"))
|
||||
{
|
||||
QLibrary archiveLib("dlls\\archive.dll");
|
||||
if (!archiveLib.load()) {
|
||||
@@ -522,9 +522,10 @@ bool InstallationManager::doInstall(GuessedValue<QString> &modName, int modID,
|
||||
return false;
|
||||
}
|
||||
|
||||
QString targetDirectory = QDir::fromNativeSeparators(m_ModsDirectory.mid(0).append("\\").append(modName));
|
||||
QString targetDirectoryNative = m_ModsDirectory.mid(0).append("\\").append(modName);
|
||||
QString targetDirectory = QDir::fromNativeSeparators(targetDirectoryNative);
|
||||
|
||||
qDebug("installing to \"%s\"", targetDirectory.toUtf8().constData());
|
||||
qDebug("installing to \"%s\"", targetDirectoryNative.toUtf8().constData());
|
||||
|
||||
m_InstallationProgress.setWindowTitle(tr("Extracting files"));
|
||||
m_InstallationProgress.setLabelText(QString());
|
||||
@@ -659,7 +660,9 @@ bool InstallationManager::install(const QString &fileName, GuessedValue<QString>
|
||||
// open the archive and construct the directory tree the installers work on
|
||||
bool archiveOpen = m_CurrentArchive->open(ToWString(QDir::toNativeSeparators(fileName)).c_str(),
|
||||
new MethodCallback<InstallationManager, void, LPSTR>(this, &InstallationManager::queryPassword));
|
||||
|
||||
if (!archiveOpen) {
|
||||
qDebug("integrated archiver can't open %s. errorcode %d", qPrintable(fileName), m_CurrentArchive->getLastError());
|
||||
}
|
||||
ON_BLOCK_EXIT(std::bind(&InstallationManager::postInstallCleanup, this));
|
||||
|
||||
QScopedPointer<DirectoryTree> filesTree(archiveOpen ? createFilesTree() : NULL);
|
||||
@@ -676,8 +679,12 @@ bool InstallationManager::install(const QString &fileName, GuessedValue<QString>
|
||||
}
|
||||
|
||||
// try only manual installers if that was requested
|
||||
if ((installResult == IPluginInstaller::RESULT_MANUALREQUESTED) && !installer->isManualInstaller()) {
|
||||
continue;
|
||||
if (installResult == IPluginInstaller::RESULT_MANUALREQUESTED) {
|
||||
if (!installer->isManualInstaller()) {
|
||||
continue;
|
||||
}
|
||||
} else if (installResult != IPluginInstaller::RESULT_NOTATTEMPTED) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -719,7 +726,8 @@ bool InstallationManager::install(const QString &fileName, GuessedValue<QString>
|
||||
case IPluginInstaller::RESULT_FAILED: {
|
||||
return false;
|
||||
} break;
|
||||
case IPluginInstaller::RESULT_SUCCESS: {
|
||||
case IPluginInstaller::RESULT_SUCCESS:
|
||||
case IPluginInstaller::RESULT_SUCCESSCANCEL: {
|
||||
if (filesTree != NULL) {
|
||||
DirectoryTree::node_iterator iniTweakNode = filesTree->nodeFind(DirectoryTreeInformation("INI Tweaks"));
|
||||
hasIniTweaks = (iniTweakNode != filesTree->nodesEnd()) &&
|
||||
|
||||
+79
-3
@@ -29,7 +29,7 @@ QMutex LogBuffer::s_Mutex;
|
||||
|
||||
|
||||
LogBuffer::LogBuffer(int messageCount, QtMsgType minMsgType, const QString &outputFileName)
|
||||
: QObject(NULL), m_OutFileName(outputFileName), m_ShutDown(false),
|
||||
: QAbstractItemModel(NULL), m_OutFileName(outputFileName), m_ShutDown(false),
|
||||
m_MinMsgType(minMsgType), m_NumMessages(0)
|
||||
{
|
||||
m_Messages.resize(messageCount);
|
||||
@@ -51,7 +51,16 @@ LogBuffer::~LogBuffer()
|
||||
void LogBuffer::logMessage(QtMsgType type, const QString &message)
|
||||
{
|
||||
if (type >= m_MinMsgType) {
|
||||
m_Messages.at(m_NumMessages % m_Messages.size()) = message;
|
||||
Message msg = { type, QTime::currentTime(), message };
|
||||
if (m_NumMessages < m_Messages.size()) {
|
||||
beginInsertRows(QModelIndex(), m_NumMessages, m_NumMessages + 1);
|
||||
}
|
||||
m_Messages.at(m_NumMessages % m_Messages.size()) = msg;
|
||||
if (m_NumMessages < m_Messages.size()) {
|
||||
endInsertRows();
|
||||
} else {
|
||||
emit dataChanged(createIndex(0, 0), createIndex(m_Messages.size(), 0));
|
||||
}
|
||||
++m_NumMessages;
|
||||
if (type >= QtCriticalMsg) {
|
||||
write();
|
||||
@@ -77,7 +86,7 @@ void LogBuffer::write() const
|
||||
unsigned int i = (m_NumMessages > m_Messages.size()) ? m_NumMessages - m_Messages.size()
|
||||
: 0U;
|
||||
for (; i < m_NumMessages; ++i) {
|
||||
file.write(m_Messages.at(i % m_Messages.size()).toUtf8());
|
||||
file.write(m_Messages.at(i % m_Messages.size()).toString().toUtf8());
|
||||
file.write("\r\n");
|
||||
}
|
||||
::SetLastError(lastError);
|
||||
@@ -125,6 +134,67 @@ char LogBuffer::msgTypeID(QtMsgType type)
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex LogBuffer::index(int row, int column, const QModelIndex&) const
|
||||
{
|
||||
return createIndex(row, column, row);
|
||||
}
|
||||
|
||||
QModelIndex LogBuffer::parent(const QModelIndex&) const
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
int LogBuffer::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
else
|
||||
return std::min(m_NumMessages, m_Messages.size());
|
||||
}
|
||||
|
||||
int LogBuffer::columnCount(const QModelIndex&) const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
QVariant LogBuffer::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
unsigned offset = m_NumMessages < m_Messages.size() ? 0
|
||||
: m_NumMessages - m_Messages.size();
|
||||
unsigned int msgIndex = (offset + index.row()) % m_Messages.size();
|
||||
switch (role) {
|
||||
case Qt::DisplayRole: {
|
||||
if (index.column() == 0) {
|
||||
return m_Messages.at(msgIndex).time;
|
||||
} else if (index.column() == 1) {
|
||||
return m_Messages.at(msgIndex).message;
|
||||
}
|
||||
} break;
|
||||
case Qt::DecorationRole: {
|
||||
if (index.column() == 1) {
|
||||
switch (m_Messages.at(msgIndex).type) {
|
||||
case QtDebugMsg: return QIcon(":/MO/gui/information");
|
||||
case QtWarningMsg: return QIcon(":/MO/gui/warning");
|
||||
case QtCriticalMsg: return QIcon(":/MO/gui/important");
|
||||
case QtFatalMsg: return QIcon(":/MO/gui/problem");
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Qt::UserRole: {
|
||||
if (index.column() == 1) {
|
||||
switch (m_Messages.at(msgIndex).type) {
|
||||
case QtDebugMsg: return "D";
|
||||
case QtWarningMsg: return "W";
|
||||
case QtCriticalMsg: return "C";
|
||||
case QtFatalMsg: return "F";
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void LogBuffer::log(QtMsgType type, const char *message)
|
||||
{
|
||||
QMutexLocker guard(&s_Mutex);
|
||||
@@ -171,3 +241,9 @@ void log(const char *format, ...)
|
||||
va_end(argList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString LogBuffer::Message::toString() const
|
||||
{
|
||||
return QString("%1 [%2] %3").arg(time.toString()).arg(msgTypeID(type)).arg(message);
|
||||
}
|
||||
|
||||
+23
-2
@@ -23,10 +23,12 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QScopedPointer>
|
||||
#include <QStringListModel>
|
||||
#include <QTime>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class LogBuffer : public QObject
|
||||
class LogBuffer : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -42,12 +44,22 @@ public:
|
||||
static void writeNow();
|
||||
static void cleanQuit();
|
||||
|
||||
static LogBuffer *instance() { return s_Instance.data(); }
|
||||
|
||||
public:
|
||||
|
||||
virtual ~LogBuffer();
|
||||
|
||||
void logMessage(QtMsgType type, const QString &message);
|
||||
|
||||
// QAbstractItemModel interface
|
||||
public:
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const;
|
||||
QModelIndex parent(const QModelIndex &child) const;
|
||||
int rowCount(const QModelIndex &parent) const;
|
||||
int columnCount(const QModelIndex &parent) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
@@ -62,6 +74,15 @@ private:
|
||||
|
||||
static char msgTypeID(QtMsgType type);
|
||||
|
||||
private:
|
||||
|
||||
struct Message {
|
||||
QtMsgType type;
|
||||
QTime time;
|
||||
QString message;
|
||||
QString toString() const;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
static QScopedPointer<LogBuffer> s_Instance;
|
||||
@@ -71,7 +92,7 @@ private:
|
||||
bool m_ShutDown;
|
||||
QtMsgType m_MinMsgType;
|
||||
unsigned int m_NumMessages;
|
||||
std::vector<QString> m_Messages;
|
||||
std::vector<Message> m_Messages;
|
||||
|
||||
};
|
||||
|
||||
|
||||
+17
-29
@@ -80,24 +80,6 @@ using namespace MOBase;
|
||||
using namespace MOShared;
|
||||
|
||||
|
||||
void removeOldLogfiles()
|
||||
{
|
||||
QFileInfoList files = QDir(ToQString(GameInfo::instance().getLogDir())).entryInfoList(QStringList("ModOrganizer*.log"),
|
||||
QDir::Files, QDir::Name);
|
||||
|
||||
if (files.count() > 5) {
|
||||
QStringList deleteFiles;
|
||||
for (int i = 0; i < files.count() - 5; ++i) {
|
||||
deleteFiles.append(files.at(i).absoluteFilePath());
|
||||
}
|
||||
|
||||
if (!shellDelete(deleteFiles)) {
|
||||
qWarning("failed to remove log files: %s", qPrintable(windowsErrorString(::GetLastError())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// set up required folders (for a first install or after an update or to fix a broken installation)
|
||||
bool bootstrap()
|
||||
{
|
||||
@@ -111,7 +93,7 @@ bool bootstrap()
|
||||
}
|
||||
|
||||
// cycle logfile
|
||||
removeOldLogfiles();
|
||||
removeOldFiles(ToQString(GameInfo::instance().getLogDir()), "ModOrganizer*.log", 5, QDir::Name);
|
||||
|
||||
// create organizer directories
|
||||
QString dirNames[] = {
|
||||
@@ -120,8 +102,7 @@ bool bootstrap()
|
||||
QDir::fromNativeSeparators(ToQString(gameInfo.getDownloadDir())),
|
||||
QDir::fromNativeSeparators(ToQString(gameInfo.getOverwriteDir())),
|
||||
QDir::fromNativeSeparators(ToQString(gameInfo.getLogDir())),
|
||||
QDir::fromNativeSeparators(ToQString(gameInfo.getTutorialDir())),
|
||||
QDir::fromNativeSeparators(ToQString(gameInfo.getOrganizerDirectory()) + "/boss")
|
||||
QDir::fromNativeSeparators(ToQString(gameInfo.getTutorialDir()))
|
||||
};
|
||||
static const int NUM_DIRECTORIES = sizeof(dirNames) / sizeof(QString);
|
||||
|
||||
@@ -158,6 +139,10 @@ bool bootstrap()
|
||||
// verify the hook-dll exists
|
||||
QString dllName = qApp->applicationDirPath() + "/" + ToQString(AppConfig::hookDLLName());
|
||||
|
||||
if (::GetModuleHandleW(ToWString(dllName).c_str()) != NULL) {
|
||||
throw std::runtime_error("hook.dll already loaded! You can't start Mod Organizer from within itself (not even indirectly)");
|
||||
}
|
||||
|
||||
HMODULE dllMod = ::LoadLibraryW(ToWString(dllName).c_str());
|
||||
if (dllMod == NULL) {
|
||||
throw windows_error("hook.dll is missing or invalid");
|
||||
@@ -210,7 +195,6 @@ bool isNxmLink(const QString &link)
|
||||
return link.left(6).toLower() == "nxm://";
|
||||
}
|
||||
|
||||
|
||||
LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs)
|
||||
{
|
||||
typedef BOOL (WINAPI *FuncMiniDumpWriteDump)(HANDLE process, DWORD pid, HANDLE file, MINIDUMP_TYPE dumpType,
|
||||
@@ -272,14 +256,11 @@ LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void registerMetaTypes()
|
||||
{
|
||||
registerExecutable();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool HaveWriteAccess(const std::wstring &path)
|
||||
{
|
||||
bool writable = false;
|
||||
@@ -329,8 +310,6 @@ bool HaveWriteAccess(const std::wstring &path)
|
||||
return writable;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
MOApplication application(argc, argv);
|
||||
@@ -545,7 +524,11 @@ int main(int argc, char *argv[])
|
||||
arguments.removeAt(profileIndex);
|
||||
arguments.removeAt(profileIndex);
|
||||
}
|
||||
qDebug("configured profile: %s", qPrintable(selectedProfileName));
|
||||
if (selectedProfileName.isEmpty()) {
|
||||
qDebug("no configured profile");
|
||||
} else {
|
||||
qDebug("configured profile: %s", qPrintable(selectedProfileName));
|
||||
}
|
||||
|
||||
// if we have a command line parameter, it is either a nxm link or
|
||||
// a binary to start
|
||||
@@ -555,7 +538,12 @@ int main(int argc, char *argv[])
|
||||
arguments.removeFirst(); // remove application name (ModOrganizer.exe)
|
||||
arguments.removeFirst(); // remove binary name
|
||||
// pass the remaining parameters to the binary
|
||||
mainWindow.startApplication(exeName, arguments, QString(), selectedProfileName);
|
||||
try {
|
||||
mainWindow.startApplication(exeName, arguments, QString(), selectedProfileName);
|
||||
} catch (const std::exception &e) {
|
||||
reportError(QObject::tr("failed to start application: %1").arg(e.what()));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+498
-155
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user