Compare commits

..
25 Commits
Author SHA1 Message Date
Tannin 0eb1662a0e - very effective optimization to findfirstfile-calls
- several configuration files are now only saved to disk if the content actually changed.
  This should also get rid of a problem where plugins.txt was re-written immediately after starting the game
  (causing a conflict with the game)
- reduced "noise" from hook.dll
- removed some debugging messages
2014-05-05 18:24:15 +02:00
Tannin 164ec25a75 - bugfix: endless loop in detection of mod order problems 2014-05-04 16:13:35 +02:00
Tannin 6fb36d6c02 - main window now has a small view displaying log messages
- mod list will now be highlighted when grouping is active is active
- download tooltip now supports bbcode markup in the description
- bbcode translator will now translate some named colors
- algorithm for detection of mod order problems is now more sophisticated
- exposed more functionality to python plugins
- updated to qt 4.8.6 dlls
- bugfix: plugin list wasn't
- bugfix: state changes in mod list wasn't always reported
- bugfix: loot client will now create necessary directory
- bugfix: NCC sometimes used wrong source path for extracting
- bugfix: removed noisy debug message
2014-05-04 14:50:01 +02:00
Tannin ea1f959ad5 - download tooltip now also includes the file description
- will now display an error message when the ini file can't be updated (in addition to what windows says)
2014-05-01 10:03:40 +02:00
Tannin 7cf3b3455b Added tag release v1.2.0 for changeset cc9f6dd8ee3f 2014-04-25 20:02:53 +02:00
Tannin 84cfa95254 - bugfix: newly installed files could be added hidden
- bugfix: registered bsas in data aren't ordered correctly
2014-04-25 19:15:12 +02:00
Tannin 264da60929 - updated installer
- prettified a few log messages
2014-04-24 22:07:42 +02:00
Tannin 2db33523a1 - added an option to show meta info on downloads instead of filenames
- MO will now cancel if user tries to run MO vfs-injected
- when saving the MO ini file it is now written to a tmp file first and then overwritten
- updated to link against boost python 1.55
2014-04-23 23:59:30 +02:00
Tannin 540747177a - loot client no longer stalls the process while waiting for masterlist update
- configurator now gives better warning messages when encountering an invalid ini file
- bugfix: crash on cleanup up browser dialog
- bugfix: GetCurrentDirectory returned wrong string length
2014-04-16 22:32:59 +02:00
Tannin 739c3424e7 - loot integration now displays the report
- fixes to the previous merge
- bugfix: cli loot didn't handle non-ascii characters correctly
2014-04-05 20:54:08 +02:00
Tannin cabed9b268 Merge with branch1.1 2014-04-05 15:36:42 +02:00
Tannin c017f4a0d5 - added buttons to backup and restore the modlist and pluginlist
- replaced boss integration with loot
2014-04-05 15:14:37 +02:00
Tannin b1f1682790 - bugfix: the add/remove categories function could fail when a filter/grouping on categories was active 2014-03-26 17:23:26 +01:00
Tannin 28301e7486 - improved NCC compatibility
- crude support for multi-volume archives
- updated imageformats plugins
- nxmhandler now puts the exe to the top of the list when registering an MO instance, even if it is already in the list
- bugfix: WritePrivateProfileString hook attempted to access lpKeyName even when it is null
2014-03-26 15:35:59 +01:00
Tannin 2d0fab4482 Merge 2014-03-18 19:18:17 +01:00
Tannin c19c4820d8 - force-enabled game esms no longer break keyboard-navigation in plugin list 2014-03-18 19:18:04 +01:00
Tannin 8ab1b47943 - bugfix: if resuming a download failed with the server sending a textual error message,
MO tried to display the whole file inside the error message
- bugfix: resuming a download didn't trigger a nexus-login when necessary
- bugfix: integrated fomod installer only used the first block of data inside a description
2014-03-18 18:29:32 +01:00
Tannin ff272dcbbd Merge 2014-03-16 20:05:13 +01:00
Tannin 98354cd1e7 some fixes towards qt5 compatibility 2014-03-16 20:04:57 +01:00
Tannin 129b76d7d2 - unpacking bsas during installation no longer overwrites loose files (since the loose files
would have taken precedence)
2014-03-13 21:57:11 +01:00
Tannin a82b7e9949 - "CreateDirectory" will no longer create directories in original data directory
- bain installer will now be less picky about the archives supported
- updated NCC to be compatible with more recent NMM code base
- hack in NCC to allow it to install arbitrary sized files even in 32-bit builds
- updated the python27.dll to one that links to msvcr100.dll to get rid of the dependency of msvcr90.dll
- bugfix: dll search order wasn't set to allow plugins to load the correct qt dlls
2014-03-13 19:00:32 +01:00
Tannin 0f8f7bf777 Added tag releease v1.1.2 for changeset 4276e1188b42 2014-02-26 22:14:06 +01:00
Tannin f4cf992700 Removed tag 1.1.2 2014-02-26 22:13:53 +01:00
Tannin bec644bac3 Added tag 1.1.2 for changeset 4276e1188b42 2014-02-26 22:13:43 +01:00
Tannin 98e5e57a84 - added support for mod page plugins
- re-introduced the integrated browser
- added a plugin to download from the tes alliance page
- the download list now contains the file description
- nexus interface now stores cookies persistently to reduce number of required log-ins
2013-09-15 15:20:00 +02:00
59 changed files with 3343 additions and 1734 deletions
+3 -3
View File
@@ -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
View File
@@ -22,6 +22,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QRegExp>
#include <map>
#include <algorithm>
#include <boost/assign.hpp>
namespace BBCode {
@@ -43,7 +44,6 @@ public:
// extract the tag name
m_TagNameExp.indexIn(input, 1, QRegExp::CaretAtOffset);
QString tagName = m_TagNameExp.cap(0).toLower();
//qDebug("tag name %s", tagName.toUtf8().constData());
TagMap::iterator tagIter = m_TagMap.find(tagName);
if (tagIter != m_TagMap.end()) {
// recognized tag
@@ -60,7 +60,21 @@ public:
length = closeTagPos + closeTag.length();
QString temp = input.mid(0, length);
if (tagIter->second.first.indexIn(temp) == 0) {
return temp.replace(tagIter->second.first, tagIter->second.second);
if (tagIter->second.second.isEmpty()) {
if (tagName == "color") {
QString color = tagIter->second.first.cap(1);
QString content = tagIter->second.first.cap(2);
auto colIter = m_ColorMap.find(color.toLower());
if (colIter != m_ColorMap.end()) {
color = colIter->second;
}
return temp.replace(tagIter->second.first, QString("<font style=\"color: #%1;\">%2</font>").arg(color, content));
} else {
qWarning("don't know how to deal with tag %s", qPrintable(tagName));
}
} else {
return temp.replace(tagIter->second.first, tagIter->second.second);
}
} else {
// expression doesn't match. either the input string is invalid
// or the expression is
@@ -96,7 +110,7 @@ private:
m_TagMap["size="] = std::make_pair(QRegExp("\\[size=([^\\]]*)\\](.*)\\[/size\\]"),
"<font size=\"\\1\">\\2</font>");
m_TagMap["color="] = std::make_pair(QRegExp("\\[color=([^\\]]*)\\](.*)\\[/color\\]"),
"<font style=\"color: #\\1;\">\\2</font>");
"");
m_TagMap["font="] = std::make_pair(QRegExp("\\[font=([^\\]]*)\\](.*)\\[/font\\]"),
"<font face=\\1>\\2</font>");
m_TagMap["center"] = std::make_pair(QRegExp("\\[center\\](.*)\\[/center\\]"),
@@ -139,10 +153,6 @@ private:
"<a href=\"\\1\">\\1</a>");
m_TagMap["url="] = std::make_pair(QRegExp("\\[url=([^\\]]*)\\](.*)\\[/url\\]"),
"<a href=\"\\1\">\\2</a>");
/* m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"),
"<img src=\"\\1\"/>");
m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"),
"<img src=\"\\2\" align=\"\\1\" />");*/
m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"), "");
m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"), "");
m_TagMap["email="] = std::make_pair(QRegExp("\\[email=\"?([^\\]]*)\"?\\](.*)\\[/email\\]"),
@@ -150,6 +160,11 @@ private:
m_TagMap["youtube"] = std::make_pair(QRegExp("\\[youtube\\](.*)\\[/youtube\\]"),
"<a href=\"http://www.youtube.com/v/\\1\">http://www.youtube.com/v/\\1</a>");
m_ColorMap = boost::assign::map_list_of("red", "FF0000")("green", "00FF00")("blue", "0000FF")
("black", "000000")("gray", "7F7F7F")("white", "FFFFFF")
("yellow", "FFFF00")("cyan", "00FFFF")("magenta", "FF00FF")
("brown", "A52A2A")("orange", "FFCC00");
// make all patterns non-greedy and case-insensitive
for (TagMap::iterator iter = m_TagMap.begin(); iter != m_TagMap.end(); ++iter) {
iter->second.first.setCaseSensitivity(Qt::CaseInsensitive);
@@ -157,10 +172,11 @@ private:
}
}
private:
QRegExp m_TagNameExp;
TagMap m_TagMap;
std::map<QString, QString> m_ColorMap;
};
+270
View File
@@ -0,0 +1,270 @@
/*
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
This file is part of Mod Organizer.
Mod Organizer is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mod Organizer is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "browserdialog.h"
#include "ui_browserdialog.h"
#include "messagedialog.h"
#include "report.h"
#include "json.h"
#include "persistentcookiejar.h"
#include <gameinfo.h>
#include <utility.h>
#include <gameinfo.h>
#include <QNetworkCookieJar>
#include <QNetworkCookie>
#include <QMenu>
#include <QInputDialog>
#include <QWebHistory>
#include <QDir>
#include <QWebFrame>
#include <QDesktopWidget>
BrowserDialog::BrowserDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::BrowserDialog)
, m_AccessManager(new QNetworkAccessManager)
{
ui->setupUi(this);
m_AccessManager->setCookieJar(new PersistentCookieJar(
QDir::fromNativeSeparators(MOBase::ToQString(MOShared::GameInfo::instance().getCacheDir())) + "/cookies.dat", this));
Qt::WindowFlags flags = windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint;
Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint;
flags = flags & (~helpFlag);
setWindowFlags(flags);
m_Tabs = this->findChild<QTabWidget*>("browserTabWidget");
connect(m_Tabs, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseRequested(int)));
}
BrowserDialog::~BrowserDialog()
{
delete ui;
}
void BrowserDialog::closeEvent(QCloseEvent *event)
{
// m_AccessManager->showCookies();
QDialog::closeEvent(event);
}
void BrowserDialog::initTab(BrowserView *newView)
{
newView->page()->setNetworkAccessManager(m_AccessManager);
newView->page()->setForwardUnsupportedContent(true);
connect(newView, SIGNAL(loadProgress(int)), this, SLOT(progress(int)));
connect(newView, SIGNAL(titleChanged(QString)), this, SLOT(titleChanged(QString)));
connect(newView, SIGNAL(initTab(BrowserView*)), this, SLOT(initTab(BrowserView*)));
connect(newView, SIGNAL(startFind()), this, SLOT(startSearch()));
connect(newView, SIGNAL(urlChanged(QUrl)), this, SLOT(urlChanged(QUrl)));
connect(newView, SIGNAL(openUrlInNewTab(QUrl)), this, SLOT(openInNewTab(QUrl)));
connect(newView->page(), SIGNAL(downloadRequested(QNetworkRequest)), this, SLOT(downloadRequested(QNetworkRequest)));
connect(newView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*)));
ui->backBtn->setEnabled(false);
ui->fwdBtn->setEnabled(false);
m_Tabs->addTab(newView, tr("new"));
newView->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
newView->settings()->setAttribute(QWebSettings::AutoLoadImages, true);
}
void BrowserDialog::openInNewTab(const QUrl &url)
{
BrowserView *newView = new BrowserView(this);
initTab(newView);
newView->setUrl(url);
}
BrowserView *BrowserDialog::getCurrentView()
{
return qobject_cast<BrowserView*>(m_Tabs->currentWidget());
}
void BrowserDialog::urlChanged(const QUrl&)
{
BrowserView *currentView = getCurrentView();
if (currentView != NULL) {
ui->backBtn->setEnabled(currentView->history()->canGoBack());
ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
}
}
void BrowserDialog::openUrl(const QUrl &url)
{
if (isHidden()) {
show();
}
openInNewTab(url);
}
void BrowserDialog::maximizeWidth()
{
int viewportWidth = getCurrentView()->page()->viewportSize().width();
int frameWidth = width() - viewportWidth;
int contentWidth = getCurrentView()->page()->mainFrame()->contentsSize().width();
QDesktopWidget screen;
int currentScreen = screen.screenNumber(this);
int screenWidth = screen.screenGeometry(currentScreen).size().width();
int targetWidth = std::min<int>(std::max<int>(viewportWidth, contentWidth) + frameWidth, screenWidth);
this->resize(targetWidth, height());
}
void BrowserDialog::progress(int value)
{
ui->loadProgress->setValue(value);
if (value == 100) {
maximizeWidth();
ui->loadProgress->setVisible(false);
} else {
ui->loadProgress->setVisible(true);
}
}
void BrowserDialog::titleChanged(const QString &title)
{
BrowserView *view = qobject_cast<BrowserView*>(sender());
for (int i = 0; i < m_Tabs->count(); ++i) {
if (m_Tabs->widget(i) == view) {
m_Tabs->setTabText(i, title.mid(0, 15));
m_Tabs->setTabToolTip(i, title);
}
}
}
QString BrowserDialog::guessFileName(const QString &url)
{
QRegExp uploadsExp(QString("http://.+/uploads/([^/]+)$"));
if (uploadsExp.indexIn(url) != -1) {
// these seem to be premium downloads
return uploadsExp.cap(1);
}
QRegExp filesExp(QString("http://.+\\?file=([^&]+)"));
if (filesExp.indexIn(url) != -1) {
// a regular manual download?
return filesExp.cap(1);
}
return "unknown";
}
void BrowserDialog::unsupportedContent(QNetworkReply *reply)
{
try {
QWebPage *page = qobject_cast<QWebPage*>(sender());
if (page == NULL) {
qCritical("sender not a page");
return;
}
BrowserView *view = qobject_cast<BrowserView*>(page->view());
if (view == NULL) {
qCritical("no view?");
return;
}
qDebug("unsupported: %s - %s", view->url().toString().toUtf8().constData(), reply->url().toString().toUtf8().constData());
emit requestDownload(view->url(), reply);
} catch (const std::exception &e) {
if (isVisible()) {
MessageDialog::showMessage(tr("failed to start download"), this);
}
qCritical("exception downloading unsupported content: %s", e.what());
}
}
void BrowserDialog::downloadRequested(const QNetworkRequest &request)
{
qCritical("download request %s ignored", request.url().toString().toUtf8().constData());
}
void BrowserDialog::tabCloseRequested(int index)
{
if (m_Tabs->count() == 1) {
this->close();
} else {
m_Tabs->widget(index)->deleteLater();
m_Tabs->removeTab(index);
}
}
void BrowserDialog::on_backBtn_clicked()
{
BrowserView *currentView = getCurrentView();
if (currentView != NULL) {
currentView->back();
}
}
void BrowserDialog::on_fwdBtn_clicked()
{
BrowserView *currentView = getCurrentView();
if (currentView != NULL) {
currentView->forward();
}
}
void BrowserDialog::startSearch()
{
ui->searchEdit->setFocus();
}
void BrowserDialog::on_searchEdit_returnPressed()
{
BrowserView *currentView = getCurrentView();
if (currentView != NULL) {
currentView->findText(ui->searchEdit->text(), QWebPage::FindWrapsAroundDocument);
}
}
void BrowserDialog::on_browserTabWidget_currentChanged(QWidget *current)
{
BrowserView *currentView = qobject_cast<BrowserView*>(current);
if (currentView != NULL) {
ui->backBtn->setEnabled(currentView->history()->canGoBack());
ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
}
}
void BrowserDialog::on_refreshBtn_clicked()
{
getCurrentView()->reload();
}
+124
View File
@@ -0,0 +1,124 @@
/*
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
This file is part of Mod Organizer.
Mod Organizer is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mod Organizer is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BROWSERDIALOG_H
#define BROWSERDIALOG_H
#include "browserview.h"
#include "tutorialcontrol.h"
#include <QDialog>
#include <QProgressBar>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QTimer>
#include <QWebView>
#include <QQueue>
#include <QTabWidget>
#include <QAtomicInt>
namespace Ui {
class BrowserDialog;
}
/**
* @brief a dialog containing a webbrowser that is intended to browse the nexus network
**/
class BrowserDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief constructor
*
* @param accessManager the access manager to use for network requests
* @param parent parent widget
**/
explicit BrowserDialog(QWidget *parent = 0);
~BrowserDialog();
/**
* @brief set the url to open. If automatic login is enabled, the url is opened after login
*
* @param url the url to open
**/
void openUrl(const QUrl &url);
signals:
/**
* @brief emitted when the user starts a download
* @param pageUrl url of the current web site from which the download was started
* @param reply network reply of the started download
*/
void requestDownload(const QUrl &pageUrl, QNetworkReply *reply);
protected:
virtual void closeEvent(QCloseEvent *);
private slots:
void initTab(BrowserView *newView);
void openInNewTab(const QUrl &url);
void progress(int value);
void titleChanged(const QString &title);
void unsupportedContent(QNetworkReply *reply);
void downloadRequested(const QNetworkRequest &request);
void tabCloseRequested(int index);
void urlChanged(const QUrl &url);
void on_backBtn_clicked();
void on_fwdBtn_clicked();
void on_searchEdit_returnPressed();
void startSearch();
void on_browserTabWidget_currentChanged(QWidget *arg1);
void on_refreshBtn_clicked();
private:
QString guessFileName(const QString &url);
BrowserView *getCurrentView();
void maximizeWidth();
private:
Ui::BrowserDialog *ui;
QNetworkAccessManager *m_AccessManager;
QTabWidget *m_Tabs;
};
#endif // BROWSERDIALOG_H
+289
View File
@@ -0,0 +1,289 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BrowserDialog</class>
<widget class="QDialog" name="BrowserDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1008</width>
<height>750</height>
</rect>
</property>
<property name="windowTitle">
<string>Some Page</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="toolBar" native="true">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>22</height>
</size>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>226</red>
<green>226</green>
<blue>226</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>106</red>
<green>106</green>
<blue>106</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>199</red>
<green>199</green>
<blue>199</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>81</red>
<green>81</green>
<blue>81</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>226</red>
<green>226</green>
<blue>226</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>106</red>
<green>106</green>
<blue>106</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>199</red>
<green>199</green>
<blue>199</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>81</red>
<green>81</green>
<blue>81</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>120</red>
<green>120</green>
<blue>120</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>106</red>
<green>106</green>
<blue>106</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>120</red>
<green>120</green>
<blue>120</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>81</red>
<green>81</green>
<blue>81</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>81</red>
<green>81</green>
<blue>81</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="backBtn">
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/MO/gui/previous</normaloff>:/MO/gui/previous</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fwdBtn">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/MO/gui/next</normaloff>:/MO/gui/next</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="refreshBtn">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/MO/gui/refresh</normaloff>:/MO/gui/refresh</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Search</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="searchEdit"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTabWidget" name="browserTabWidget">
<property name="contextMenuPolicy">
<enum>Qt::DefaultContextMenu</enum>
</property>
<property name="tabsClosable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="loadProgress">
<property name="value">
<number>0</number>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections/>
</ui>
+76
View File
@@ -0,0 +1,76 @@
/*
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
This file is part of Mod Organizer.
Mod Organizer is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mod Organizer is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "browserview.h"
#include <QEvent>
#include <QKeyEvent>
#include <QWebFrame>
#include <QWebElement>
#include <QNetworkDiskCache>
#include <QMenu>
#include <Shlwapi.h>
#include "utility.h"
BrowserView::BrowserView(QWidget *parent)
: QWebView(parent)
{
installEventFilter(this);
page()->settings()->setMaximumPagesInCache(10);
}
QWebView *BrowserView::createWindow(QWebPage::WebWindowType)
{
BrowserView *newView = new BrowserView(parentWidget());
emit initTab(newView);
return newView;
}
bool BrowserView::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::ShortcutOverride) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->matches(QKeySequence::Find)) {
emit startFind();
} else if (keyEvent->matches(QKeySequence::FindNext)) {
emit findAgain();
}
} else if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::MidButton) {
mouseEvent->ignore();
return true;
}
} else if (event->type() == QEvent::MouseButtonRelease) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::MidButton) {
QWebHitTestResult hitTest = page()->frameAt(mouseEvent->pos())->hitTestContent(mouseEvent->pos());
if (hitTest.linkUrl().isValid()) {
emit openUrlInNewTab(hitTest.linkUrl());
}
mouseEvent->ignore();
return true;
}
}
return QWebView::eventFilter(obj, event);
}
+80
View File
@@ -0,0 +1,80 @@
/*
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
This file is part of Mod Organizer.
Mod Organizer is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mod Organizer is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NEXUSVIEW_H
#define NEXUSVIEW_H
#include "finddialog.h"
#include <QWebView>
#include <QWebPage>
#include <QTabWidget>
/**
* @brief web view used to display a nexus page
**/
class BrowserView : public QWebView
{
Q_OBJECT
public:
explicit BrowserView(QWidget *parent = 0);
signals:
/**
* @brief emitted when the user opens a new window to be displayed in another tab
*
* @param newView the view for the newly opened window
**/
void initTab(BrowserView *newView);
/**
* @brief emitted when the user requests a link to be opened in a new tab by middle-clicking
*
* @param url the url to open
*/
void openUrlInNewTab(const QUrl &url);
/**
* @brief Ctrl-f was clicked. The containing dialog should activate its find-facility
*/
void startFind();
/**
* @brief F3 was pressed. The containing dialog should search again
*/
void findAgain();
protected:
virtual QWebView *createWindow(QWebPage::WebWindowType type);
virtual bool eventFilter(QObject *obj, QEvent *event);
private:
QString m_FindPattern;
bool m_MiddleClick;
};
#endif // NEXUSVIEW_H
+2 -2
View File
@@ -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 {
+8 -3
View File
@@ -40,8 +40,13 @@ DownloadListWidget::~DownloadListWidget()
}
DownloadListWidgetDelegate::DownloadListWidgetDelegate(DownloadManager *manager, QTreeView *view, QObject *parent)
: QItemDelegate(parent), m_Manager(manager), m_ItemWidget(new DownloadListWidget), m_ContextRow(0), m_View(view)
DownloadListWidgetDelegate::DownloadListWidgetDelegate(DownloadManager *manager, bool metaDisplay, QTreeView *view, QObject *parent)
: QItemDelegate(parent)
, m_Manager(manager)
, m_MetaDisplay(metaDisplay)
, m_ItemWidget(new DownloadListWidget)
, m_ContextRow(0)
, m_View(view)
{
m_NameLabel = m_ItemWidget->findChild<QLabel*>("nameLabel");
m_SizeLabel = m_ItemWidget->findChild<QLabel*>("sizeLabel");
@@ -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("...");
+3 -1
View File
@@ -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;
+7 -3
View File
@@ -40,8 +40,12 @@ DownloadListWidgetCompact::~DownloadListWidgetCompact()
}
DownloadListWidgetCompactDelegate::DownloadListWidgetCompactDelegate(DownloadManager *manager, QTreeView *view, QObject *parent)
: QItemDelegate(parent), m_Manager(manager), m_ItemWidget(new DownloadListWidgetCompact), m_View(view)
DownloadListWidgetCompactDelegate::DownloadListWidgetCompactDelegate(DownloadManager *manager, bool metaDisplay, QTreeView *view, QObject *parent)
: QItemDelegate(parent)
, m_Manager(manager)
, m_MetaDisplay(metaDisplay)
, m_ItemWidget(new DownloadListWidgetCompact)
, m_View(view)
{
m_NameLabel = m_ItemWidget->findChild<QLabel*>("nameLabel");
m_SizeLabel = m_ItemWidget->findChild<QLabel*>("sizeLabel");
@@ -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("...");
+3 -1
View File
@@ -54,7 +54,7 @@ class DownloadListWidgetCompactDelegate : public QItemDelegate
public:
DownloadListWidgetCompactDelegate(DownloadManager *manager, QTreeView *view, QObject *parent = 0);
DownloadListWidgetCompactDelegate(DownloadManager *manager, bool metaDisplay, QTreeView *view, QObject *parent = 0);
~DownloadListWidgetCompactDelegate();
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
@@ -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
View File
@@ -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
View File
@@ -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;
-1
View File
@@ -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),
+15 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff

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