diff options
| author | Tannin <devnull@localhost> | 2013-04-13 19:23:18 +0200 |
|---|---|---|
| committer | Tannin <devnull@localhost> | 2013-04-13 19:23:18 +0200 |
| commit | 1c9018e9fdba7878b0ef605f81529c20ef3bbffe (patch) | |
| tree | 7b52a5f7b9091ea68f03d06692bba4c240d30d49 | |
| parent | 528338d7bfb5479115511f77b70219eda1b32a62 (diff) | |
- bugfix: wrong multibyte to widechar conversion in hookdll breaks internationalization
- bugfix: mod names not checked for validity on rename
- bugfix: mod list wasn't invalidated after rename (regression?)
- problem reports moved to separate dialog
- ncc plugin now does the check for dotNet
- python plugin wrapper started (only supports tools currently)
- new ini editor plugin in python (non-functional currently)
| -rw-r--r-- | src/installationmanager.cpp | 2 | ||||
| -rw-r--r-- | src/main.cpp | 19 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 75 | ||||
| -rw-r--r-- | src/mainwindow.h | 3 | ||||
| -rw-r--r-- | src/modlist.cpp | 15 | ||||
| -rw-r--r-- | src/organizer.pro | 9 | ||||
| -rw-r--r-- | src/problemsdialog.cpp | 58 | ||||
| -rw-r--r-- | src/problemsdialog.h | 35 | ||||
| -rw-r--r-- | src/problemsdialog.ui | 104 | ||||
| -rw-r--r-- | src/resources.qrc | 3 |
10 files changed, 293 insertions, 30 deletions
diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 1abb19da..63945150 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -18,9 +18,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "installationmanager.h" - #include "utility.h" - #include "report.h" #include "categories.h" #include "questionboxmemory.h" diff --git a/src/main.cpp b/src/main.cpp index 268bb98f..ab740467 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -64,6 +64,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QDesktopServices> #include <eh.h> #include <windows_error.h> +#include <boost/scoped_array.hpp> #pragma comment(linker, "/manifestDependency:\"name='dlls' processorArchitecture='x86' version='1.0.0.0' type='win32' \"") @@ -284,6 +285,24 @@ int main(int argc, char *argv[]) QSplashScreen splash(pixmap); splash.show(); + { // extend path to include dll directory so plugins don't need a manifest + static const int BUFSIZE = 4096; + + boost::scoped_array<TCHAR> oldPath(new TCHAR[BUFSIZE]); + DWORD offset = ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), BUFSIZE); + if (offset > BUFSIZE) { + oldPath.reset(new TCHAR[offset]); + ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), offset); + } + + std::tstring newPath(oldPath.get()); + newPath += TEXT(";"); + newPath += ToWString(QDir::toNativeSeparators(QCoreApplication::applicationDirPath())).c_str(); + newPath += TEXT("\\dlls"); + + ::SetEnvironmentVariable(TEXT("PATH"), newPath.c_str()); + } + registerMetaTypes(); QStringList arguments = application.arguments(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 6b546d4d..2fd47537 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -54,9 +54,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "csvbuilder.h" #include "gameinfoimpl.h" #include "savetextasdialog.h" +#include "problemsdialog.h" #include <gameinfo.h> #include <appconfig.h> #include <utility.h> +#include <ipluginproxy.h> #include <map> #include <ctime> #include <QTime> @@ -84,14 +86,13 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QPluginLoader> #include <QRadioButton> #include <QDesktopWidget> +#include <QtPlugin> #include <QIdentityProxyModel> #include <boost/bind.hpp> #include <boost/foreach.hpp> #include <Psapi.h> #include <shlobj.h> #include <TlHelp32.h> - - #include <QNetworkInterface> @@ -394,8 +395,7 @@ void MainWindow::updateToolBar() void MainWindow::updateProblemsButton() { - QString problemDescription; - if (checkForProblems(problemDescription)) { + if (checkForProblems()) { ui->actionProblems->setEnabled(true); ui->actionProblems->setIconText(tr("Problems")); ui->actionProblems->setToolTip(tr("There are potential problems with your setup")); @@ -436,17 +436,19 @@ bool MainWindow::errorReported(QString &logFile) } -bool MainWindow::checkForProblems(QString &problemDescription) +bool MainWindow::checkForProblems() { - problemDescription = ""; +// problemDescription = ""; foreach (IPluginDiagnose *diagnose, m_DiagnosisPlugins) { std::vector<unsigned int> activeProblems = diagnose->activeProblems(); - foreach (unsigned int key, activeProblems) { - problemDescription.append(tr("<li>%1</li>").arg(diagnose->shortDescription(key))); + if (activeProblems.size() > 0) { + return true; } } + return false; +/* QString NCCBinary = QCoreApplication::applicationDirPath().mid(0).append("/NCC/NexusClientCLI.exe"); if (!QFile::exists(NCCBinary)) { problemDescription.append(tr("<li>NCC not installed. You won't be able to install some scripted mod-installers. Get NCC from <a href=\"http://skyrim.nexusmods.com/downloads/file.php?id=1334\">the MO page on nexus</a></li>")); @@ -479,7 +481,7 @@ bool MainWindow::checkForProblems(QString &problemDescription) } else { ui->actionProblems->setToolTip(tr("Everything seems to be in order")); } - return res; + return res;*/ } @@ -886,6 +888,8 @@ void MainWindow::toolPluginInvoke() plugin->display(); } catch (const std::exception &e) { reportError(tr("Plugin \"%1\" failed: %2").arg(plugin->name()).arg(e.what())); + } catch (...) { + reportError(tr("Plugin \"%1\" failed").arg(plugin->name())); } } @@ -912,13 +916,15 @@ bool MainWindow::registerPlugin(QObject *plugin) m_Settings.registerPlugin(pluginObj); } + bool addon = false; + { // diagnosis plugins IPluginDiagnose *diagnose = qobject_cast<IPluginDiagnose*>(plugin); if (diagnose != NULL) { m_DiagnosisPlugins.push_back(diagnose); + addon = true; } } - { // tool plugins IPluginTool *tool = qobject_cast<IPluginTool*>(plugin); if (verifyPlugin(tool)) { @@ -934,7 +940,25 @@ bool MainWindow::registerPlugin(QObject *plugin) return true; } } - return false; + { // proxy plugins + IPluginProxy *proxy = qobject_cast<IPluginProxy*>(plugin); + if (verifyPlugin(proxy)) { + QStringList pluginNames = proxy->pluginList(QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::pluginPath())); + foreach (const QString &pluginName, pluginNames) { + QObject *proxiedPlugin = proxy->instantiate(pluginName); + if (proxiedPlugin != NULL) { + if (registerPlugin(proxiedPlugin)) { + qDebug("loaded plugin \"%s\"", pluginName.toUtf8().constData()); + } else { + qWarning("plugin \"%s\" failed to load", pluginName.toUtf8().constData()); + } + } + } + return true; + } + } + + return addon; } @@ -978,12 +1002,20 @@ IGameInfo &MainWindow::gameInfo() const QString MainWindow::profileName() const { - return m_CurrentProfile->getName(); + if (m_CurrentProfile != NULL) { + return m_CurrentProfile->getName(); + } else { + return ""; + } } QString MainWindow::profilePath() const { - return m_CurrentProfile->getPath(); + if (m_CurrentProfile != NULL) { + return m_CurrentProfile->getPath(); + } else { + return ""; + } } QString MainWindow::downloadsPath() const @@ -1045,6 +1077,12 @@ QVariant MainWindow::pluginSetting(const QString &pluginName, const QString &key return m_Settings.pluginSetting(pluginName, key); } +QString MainWindow::pluginDataPath() const +{ + QString pluginPath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())) + "/" + ToQString(AppConfig::pluginPath()); + return pluginPath + "/data"; +} + void MainWindow::startSteam() { @@ -4058,11 +4096,16 @@ void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int) m_CheckBSATimer.start(500); } + void MainWindow::on_actionProblems_triggered() { - QString problemDescription; - checkForProblems(problemDescription); - QMessageBox::information(this, tr("Problems"), problemDescription); +// QString problemDescription; +// checkForProblems(problemDescription); +// QMessageBox::information(this, tr("Problems"), problemDescription); + ProblemsDialog problems(m_DiagnosisPlugins, this); + if (problems.hasProblems()) { + problems.exec(); + } } void MainWindow::setCategoryListVisible(bool visible) diff --git a/src/mainwindow.h b/src/mainwindow.h index 5880fcb8..e50a8c23 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -103,6 +103,7 @@ public: virtual bool removeMod(MOBase::IModInterface *mod); virtual void modDataChanged(MOBase::IModInterface *mod); virtual QVariant pluginSetting(const QString &pluginName, const QString &key) const; + virtual QString pluginDataPath() const; void addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInfo::Ptr info); @@ -205,7 +206,7 @@ private: bool extractProgress(QProgressDialog &extractProgress, int percentage, std::string fileName); - bool checkForProblems(QString &problemDescription); + bool checkForProblems(); int getBinaryExecuteInfo(const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments); QTreeWidgetItem *addFilterItem(QTreeWidgetItem *root, const QString &name, int categoryID); diff --git a/src/modlist.cpp b/src/modlist.cpp index f186ce8e..2183ce09 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -20,12 +20,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "modlist.h" #include "report.h" -#include "utility.h" #include "messagedialog.h" #include "installationtester.h" #include "qtgroupingproxy.h" #include <gameinfo.h> - +#include <utility.h> #include <QFileInfo> #include <QDir> #include <QDirIterator> @@ -301,19 +300,25 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const bool ModList::renameMod(int index, const QString &newName) { + QString nameFixed = newName; + if (!fixDirectoryName(nameFixed) || nameFixed.isEmpty()) { + MessageDialog::showMessage(tr("Invalid name"), NULL); + return false; + } + // before we rename, write back the current profile so we don't lose changes and to ensure // there is no scheduled asynchronous rewrite anytime soon m_Profile->writeModlistNow(); ModInfo::Ptr modInfo = ModInfo::getByIndex(index); QString oldName = modInfo->name(); - modInfo->setName(newName); + modInfo->setName(nameFixed); // this just broke all profiles! The recipient of modRenamed has to do some magic // to can't write the currently active profile back - emit modRenamed(oldName, newName); + emit modRenamed(oldName, nameFixed); // invalidate the currently displayed state of this list -// notifyChange(-1); + notifyChange(-1); return true; } diff --git a/src/organizer.pro b/src/organizer.pro index 582ba633..cfdf990b 100644 --- a/src/organizer.pro +++ b/src/organizer.pro @@ -78,7 +78,8 @@ SOURCES += \ csvbuilder.cpp \
savetextasdialog.cpp \
qtgroupingproxy.cpp \
- modlistview.cpp
+ modlistview.cpp \
+ problemsdialog.cpp
HEADERS += \
transfersavesdialog.h \
@@ -144,7 +145,8 @@ HEADERS += \ csvbuilder.h \
savetextasdialog.h \
qtgroupingproxy.h \
- modlistview.h
+ modlistview.h \
+ problemsdialog.h
FORMS += \
transfersavesdialog.ui \
@@ -174,7 +176,8 @@ FORMS += \ baincomplexinstallerdialog.ui \
activatemodsdialog.ui \
profileinputdialog.ui \
- savetextasdialog.ui
+ savetextasdialog.ui \
+ problemsdialog.ui
INCLUDEPATH += ../shared ../archive ../uibase ../bsatk "$(BOOSTPATH)"
diff --git a/src/problemsdialog.cpp b/src/problemsdialog.cpp new file mode 100644 index 00000000..e0837f45 --- /dev/null +++ b/src/problemsdialog.cpp @@ -0,0 +1,58 @@ +#include "problemsdialog.h"
+#include "ui_problemsdialog.h"
+#include <utility.h>
+#include <iplugindiagnose.h>
+#include <QPushButton>
+#include <Shellapi.h>
+
+
+using namespace MOBase;
+
+
+ProblemsDialog::ProblemsDialog(std::vector<MOBase::IPluginDiagnose *> diagnosePlugins, QWidget *parent)
+ : QDialog(parent), ui(new Ui::ProblemsDialog)
+{
+ ui->setupUi(this);
+
+ foreach (IPluginDiagnose *diagnose, diagnosePlugins) {
+ std::vector<unsigned int> activeProblems = diagnose->activeProblems();
+ foreach (unsigned int key, activeProblems) {
+ QTreeWidgetItem *newItem = new QTreeWidgetItem();
+ newItem->setText(0, diagnose->shortDescription(key));
+ newItem->setData(0, Qt::UserRole, diagnose->fullDescription(key));
+
+ if (diagnose->hasGuidedFix(key)) {
+ ui->problemsWidget->setItemWidget(newItem, 1, new QPushButton(tr("Fix")));
+ } else {
+ newItem->setText(1, tr("No guided fix :("));
+ }
+ ui->problemsWidget->addTopLevelItem(newItem);
+ }
+ }
+ connect(ui->problemsWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
+ connect(ui->descriptionText, SIGNAL(anchorClicked(QUrl)), this, SLOT(urlClicked(QUrl)));
+}
+
+
+ProblemsDialog::~ProblemsDialog()
+{
+ delete ui;
+}
+
+
+bool ProblemsDialog::hasProblems() const
+{
+ return ui->problemsWidget->topLevelItemCount() != 0;
+}
+
+void ProblemsDialog::selectionChanged()
+{
+ QString text = ui->problemsWidget->currentItem()->data(0, Qt::UserRole).toString();
+ ui->descriptionText->setText(text);
+ ui->descriptionText->setLineWrapMode(text.contains('\n') ? QTextEdit::NoWrap : QTextEdit::WidgetWidth);
+}
+
+void ProblemsDialog::urlClicked(const QUrl &url)
+{
+ ::ShellExecuteW(NULL, L"open", ToWString(url.toString()).c_str(), NULL, NULL, SW_SHOWNORMAL);
+}
diff --git a/src/problemsdialog.h b/src/problemsdialog.h new file mode 100644 index 00000000..299faf8d --- /dev/null +++ b/src/problemsdialog.h @@ -0,0 +1,35 @@ +#ifndef PROBLEMSDIALOG_H
+#define PROBLEMSDIALOG_H
+
+
+#include <QDialog>
+#include <QUrl>
+#include <iplugindiagnose.h>
+
+
+namespace Ui {
+class ProblemsDialog;
+}
+
+
+class ProblemsDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit ProblemsDialog(std::vector<MOBase::IPluginDiagnose*> diagnosePlugins, QWidget *parent = 0);
+ ~ProblemsDialog();
+
+ bool hasProblems() const;
+
+private slots:
+
+ void selectionChanged();
+ void urlClicked(const QUrl &url);
+
+private:
+
+ Ui::ProblemsDialog *ui;
+};
+
+#endif // PROBLEMSDIALOG_H
diff --git a/src/problemsdialog.ui b/src/problemsdialog.ui new file mode 100644 index 00000000..b194bf31 --- /dev/null +++ b/src/problemsdialog.ui @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProblemsDialog</class>
+ <widget class="QDialog" name="ProblemsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>574</width>
+ <height>376</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Problems</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0">
+ <item>
+ <widget class="QTreeWidget" name="problemsWidget">
+ <property name="columnCount">
+ <number>2</number>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="headerDefaultSectionSize">
+ <number>420</number>
+ </attribute>
+ <column>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string notr="true">2</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextBrowser" name="descriptionText">
+ <property name="lineWrapMode">
+ <enum>QTextEdit::NoWrap</enum>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="html">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;">
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><br /></p></body></html></string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ProblemsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ProblemsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/resources.qrc b/src/resources.qrc index a743ba39..855a23fc 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -50,8 +50,5 @@ <file alias="emblem_conflict_overwritten">resources/conflict-overwritten.png</file> <file alias="emblem_conflict_redundant">resources/conflict-redundant.png</file> <file alias="emblem_notes">resources/accessories-text-editor.png</file> - <file alias="network_idle">resources/network-idle.png</file> - <file alias="network_offline">resources/network-offline.png</file> - <file alias="network_error">resources/network-error.png</file> </qresource> </RCC> |
