From f682f82db5d8ba514e927c9d7e88107348d5c32a Mon Sep 17 00:00:00 2001 From: Tannin Date: Fri, 29 Mar 2013 10:25:38 +0100 Subject: some improvements to the grouped modlist views --- src/mainwindow.cpp | 2 +- src/modlist.cpp | 23 ++- src/modlist.h | 424 ++++++++++++++++++++++++------------------------ src/qtgroupingproxy.cpp | 27 ++- src/qtgroupingproxy.h | 13 +- 5 files changed, 272 insertions(+), 217 deletions(-) (limited to 'src') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 37d041c0..43694c32 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3969,7 +3969,7 @@ void MainWindow::on_groupCombo_currentIndexChanged(int index) QAbstractProxyModel *newModel = NULL; switch (index) { case 1: { - newModel = new QtGroupingProxy(m_ModListSortProxy, QModelIndex(), ModList::COL_CATEGORY); + newModel = new QtGroupingProxy(m_ModListSortProxy, QModelIndex(), ModList::COL_CATEGORY, Qt::UserRole); } break; case 2: { newModel = new QtGroupingProxy(m_ModListSortProxy, QModelIndex(), ModList::COL_MODID); diff --git a/src/modlist.cpp b/src/modlist.cpp index 9b99b488..06f468b1 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -197,7 +197,21 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return QVariant(Qt::AlignCenter | Qt::AlignVCenter); } } else if (role == Qt::UserRole) { - return modInfo->getNexusID(); + if (column == COL_CATEGORY) { + QVariantList categoryNames; + std::set categories = modInfo->getCategories(); + CategoryFactory &categoryFactory = CategoryFactory::instance(); + for (auto iter = categories.begin(); iter != categories.end(); ++iter) { + categoryNames.append(categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*iter))); + } + if (categoryNames.count() != 0) { + return categoryNames; + } else { + return QVariant(); + } + } else { + return modInfo->getNexusID(); + } } else if (role == Qt::UserRole + 1) { return modIndex; } else if (role == Qt::FontRole) { @@ -590,6 +604,13 @@ QModelIndex ModList::parent(const QModelIndex&) const return QModelIndex(); } +QMap ModList::itemData(const QModelIndex &index) const +{ + QMap result = QAbstractItemModel::itemData(index); + result[Qt::UserRole] = data(index, Qt::UserRole); + return result; +} + QString ModList::getColumnName(int column) { diff --git a/src/modlist.h b/src/modlist.h index 7c37f4d5..86255bfb 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -17,214 +17,216 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see . */ -#ifndef MODLIST_H -#define MODLIST_H - - -#include "categories.h" -#include "nexusinterface.h" -#include "modinfo.h" -#include "profile.h" - -#include -#include -#include -#include - -#include -#include -#include - - -/** - * Model presenting an overview of the installed mod - * This is used in a view in the main window of MO. It combines general information about - * the mods from ModInfo with status information from the Profile - **/ -class ModList : public QAbstractItemModel -{ - Q_OBJECT - -public: - - enum EColumn { - COL_NAME, - COL_FLAGS, - COL_CATEGORY, - COL_MODID, - COL_VERSION, - COL_PRIORITY, - - COL_LASTCOLUMN = COL_PRIORITY - }; - -public: - - /** - * @brief constructor - * @todo ensure this view works without a profile set, otherwise there are intransparent dependencies on the initialisation order - **/ - ModList(QObject *parent = NULL); - - /** - * @brief set the profile used for status information - * - * @param profile the profile to use - **/ - void setProfile(Profile *profile); - - /** - * @brief retrieve the current sorting mode - * @note this is used to store the sorting mode between sessions - * @return current sorting mode, encoded to be compatible to previous versions - **/ - int getCurrentSortingMode() const; - - /** - * @brief force a refresh of the mod list - **/ - void refresh(); - - /** - * @brief remove the specified mod without asking for confirmation - * @param row the row to remove - */ - void removeRowForce(int row); - - void notifyChange(int row); - - static QString getColumnName(int column); - - void changeModPriority(int sourceIndex, int newPriority); - -public: // implementation of virtual functions of QAbstractItemModel - - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; - virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); - virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const; - virtual Qt::DropActions supportedDropActions() const { return Qt::MoveAction; } - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); - virtual void removeRow(int row, const QModelIndex &parent); - - - virtual QModelIndex index(int row, int column, - const QModelIndex &parent = QModelIndex()) const; - virtual QModelIndex parent(const QModelIndex &child) const; - -public slots: - -signals: - - /** - * @brief emitted whenever the sorting in the list was changed by the user - * - * the sorting of the list can only be manually changed if the list is sorted by priority - * in which case the move is intended to change the priority of a mod - **/ - void modorder_changed(); - - /** - * @brief emitted when the model wants a text to be displayed by the UI - * - * @param message the message to display - **/ - void showMessage(const QString &message); - - /** - * @brief signals change to the count of headers - */ - void resizeHeaders(); - - /** - * @brief requestColumnSelect is emitted whenever the user requested a menu to select visible columns - * @param pos the position to display the menu at - */ - void requestColumnSelect(QPoint pos); - - /** - * @brief emitted to remove a file origin - * @param name name of the orign to remove - */ - void removeOrigin(const QString &name); - - /** - * @brief emitted after a mod has been renamed - * This signal MUST be used to fix the mod names in profiles (except the active one) and to invalidate/refresh other - * structures that may have become invalid with the rename - * - * @param oldName the old name of the mod - * @param newName new name of the mod - */ - void modRenamed(const QString &oldName, const QString &newName); - - /** - * @brief emitted whenever a row in the list has changed - * - * @param row the row that changed - * @note this signal must only be emitted if the row really did change. - * Slots handling this signal therefore do not have to verify that a change has happened - * @note this signal is currently only used in tutorials - **/ - void modlist_changed(int row); - - /** - * @brief emitted to have all selected mods deleted - */ - void removeSelectedMods(); - -protected: - - // event filter, handles event from the header and the tree view itself - bool eventFilter(QObject *obj, QEvent *event); - -private: - - bool testValid(const QString &modDir); - - void changeModPriority(std::vector sourceIndices, int newPriority); - - QVariant getOverwriteData(int column, int role) const; - - QString getFlagText(ModInfo::EFlag flag, ModInfo::Ptr modInfo) const; - - static QString getColumnToolTip(int column); - - ModList::EColumn getEnabledColumn(int index) const; - - QVariant categoryData(int categoryID, int column, int role) const; - QVariant modData(int modID, int modelColumn, int role) const; - - bool renameMod(int index, const QString &newName); - -private slots: - -private: - - struct TModInfo { - TModInfo(unsigned int index, ModInfo::Ptr modInfo) - : modInfo(modInfo), nameOrder(index) {} - ModInfo::Ptr modInfo; - unsigned int nameOrder; - unsigned int priorityOrder; - unsigned int modIDOrder; - unsigned int categoryOrder; - }; - -private: - - Profile *m_Profile; - - NexusInterface *m_NexusInterface; - std::set m_RequestIDs; - - mutable bool m_Modified; - - QFontMetrics m_FontMetrics; - -}; - -#endif // MODLIST_H - +#ifndef MODLIST_H +#define MODLIST_H + + +#include "categories.h" +#include "nexusinterface.h" +#include "modinfo.h" +#include "profile.h" + +#include +#include +#include +#include + +#include +#include +#include + + +/** + * Model presenting an overview of the installed mod + * This is used in a view in the main window of MO. It combines general information about + * the mods from ModInfo with status information from the Profile + **/ +class ModList : public QAbstractItemModel +{ + Q_OBJECT + +public: + + enum EColumn { + COL_NAME, + COL_FLAGS, + COL_CATEGORY, + COL_MODID, + COL_VERSION, + COL_PRIORITY, + + COL_LASTCOLUMN = COL_PRIORITY + }; + +public: + + /** + * @brief constructor + * @todo ensure this view works without a profile set, otherwise there are intransparent dependencies on the initialisation order + **/ + ModList(QObject *parent = NULL); + + /** + * @brief set the profile used for status information + * + * @param profile the profile to use + **/ + void setProfile(Profile *profile); + + /** + * @brief retrieve the current sorting mode + * @note this is used to store the sorting mode between sessions + * @return current sorting mode, encoded to be compatible to previous versions + **/ + int getCurrentSortingMode() const; + + /** + * @brief force a refresh of the mod list + **/ + void refresh(); + + /** + * @brief remove the specified mod without asking for confirmation + * @param row the row to remove + */ + void removeRowForce(int row); + + void notifyChange(int row); + + static QString getColumnName(int column); + + void changeModPriority(int sourceIndex, int newPriority); + +public: // implementation of virtual functions of QAbstractItemModel + + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const; + virtual Qt::DropActions supportedDropActions() const { return Qt::MoveAction; } + virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + virtual void removeRow(int row, const QModelIndex &parent); + + + virtual QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + virtual QModelIndex parent(const QModelIndex &child) const; + + virtual QMap itemData(const QModelIndex &index) const; + +public slots: + +signals: + + /** + * @brief emitted whenever the sorting in the list was changed by the user + * + * the sorting of the list can only be manually changed if the list is sorted by priority + * in which case the move is intended to change the priority of a mod + **/ + void modorder_changed(); + + /** + * @brief emitted when the model wants a text to be displayed by the UI + * + * @param message the message to display + **/ + void showMessage(const QString &message); + + /** + * @brief signals change to the count of headers + */ + void resizeHeaders(); + + /** + * @brief requestColumnSelect is emitted whenever the user requested a menu to select visible columns + * @param pos the position to display the menu at + */ + void requestColumnSelect(QPoint pos); + + /** + * @brief emitted to remove a file origin + * @param name name of the orign to remove + */ + void removeOrigin(const QString &name); + + /** + * @brief emitted after a mod has been renamed + * This signal MUST be used to fix the mod names in profiles (except the active one) and to invalidate/refresh other + * structures that may have become invalid with the rename + * + * @param oldName the old name of the mod + * @param newName new name of the mod + */ + void modRenamed(const QString &oldName, const QString &newName); + + /** + * @brief emitted whenever a row in the list has changed + * + * @param row the row that changed + * @note this signal must only be emitted if the row really did change. + * Slots handling this signal therefore do not have to verify that a change has happened + * @note this signal is currently only used in tutorials + **/ + void modlist_changed(int row); + + /** + * @brief emitted to have all selected mods deleted + */ + void removeSelectedMods(); + +protected: + + // event filter, handles event from the header and the tree view itself + bool eventFilter(QObject *obj, QEvent *event); + +private: + + bool testValid(const QString &modDir); + + void changeModPriority(std::vector sourceIndices, int newPriority); + + QVariant getOverwriteData(int column, int role) const; + + QString getFlagText(ModInfo::EFlag flag, ModInfo::Ptr modInfo) const; + + static QString getColumnToolTip(int column); + + ModList::EColumn getEnabledColumn(int index) const; + + QVariant categoryData(int categoryID, int column, int role) const; + QVariant modData(int modID, int modelColumn, int role) const; + + bool renameMod(int index, const QString &newName); + +private slots: + +private: + + struct TModInfo { + TModInfo(unsigned int index, ModInfo::Ptr modInfo) + : modInfo(modInfo), nameOrder(index) {} + ModInfo::Ptr modInfo; + unsigned int nameOrder; + unsigned int priorityOrder; + unsigned int modIDOrder; + unsigned int categoryOrder; + }; + +private: + + Profile *m_Profile; + + NexusInterface *m_NexusInterface; + std::set m_RequestIDs; + + mutable bool m_Modified; + + QFontMetrics m_FontMetrics; + +}; + +#endif // MODLIST_H + diff --git a/src/qtgroupingproxy.cpp b/src/qtgroupingproxy.cpp index 5c1e0275..95a4aad0 100644 --- a/src/qtgroupingproxy.cpp +++ b/src/qtgroupingproxy.cpp @@ -14,6 +14,9 @@ * this program. If not, see . * ****************************************************************************************/ +// Modifications 2013-03-27 to 2013-03-28 by Sebastian Herbord + + #include "QtGroupingProxy.h" #include @@ -28,10 +31,12 @@ \ingroup model-view */ -QtGroupingProxy::QtGroupingProxy( QAbstractItemModel *model, QModelIndex rootNode, int groupedColumn ) +QtGroupingProxy::QtGroupingProxy(QAbstractItemModel *model, QModelIndex rootNode, int groupedColumn, Qt::ItemDataRole groupedRole, unsigned int flags ) : QAbstractProxyModel() , m_rootNode( rootNode ) , m_groupedColumn( 0 ) + , m_groupedRole( groupedRole ) + , m_flags( flags ) { setSourceModel( model ); @@ -84,14 +89,23 @@ QtGroupingProxy::belongsTo( const QModelIndex &idx ) //get all the data for this index from the model ItemData itemData = sourceModel()->itemData( idx ); + if (m_groupedRole != Qt::DisplayRole) { + itemData[Qt::DisplayRole] = itemData[m_groupedRole]; + } + + // invalid value in grouped role -> ungrouped + if (!itemData[Qt::DisplayRole].isValid()) { + return rowDataList; + } + QMapIterator i( itemData ); while( i.hasNext() ) { i.next(); int role = i.key(); QVariant variant = i.value(); - // qDebug() << "role " << role << " : (" << variant.typeName() << ") : "<< variant; - if( variant.type() == QVariant::List ) + qDebug() << "role " << role << " : (" << variant.typeName() << ") : "<< variant; + if ( variant.type() == QVariant::List ) { //a list of variants get's expanded to multiple rows QVariantList list = variant.toList(); @@ -111,6 +125,7 @@ QtGroupingProxy::belongsTo( const QModelIndex &idx ) rowData.insert( m_groupedColumn, indexData ); rowDataList.insert( i, rowData ); } + break; } else if( !variant.isNull() ) { @@ -155,8 +170,13 @@ QtGroupingProxy::buildTree() } //dumpGroups(); + if (m_flags & FLAG_NOSINGLE) { + + } + endResetModel(); + // restore expand-state for( int row = 0; row < rowCount(); row++ ) { QModelIndex idx = index( row, 0, QModelIndex() ); if (m_expandedItems.contains(idx.data(Qt::UserRole).toString())) { @@ -326,6 +346,7 @@ QtGroupingProxy::rowCount( const QModelIndex &index ) const if( !index.isValid() ) { //the number of top level groups + the number of non-grouped items + qDebug("groups: %d - ungrouped: %d", m_groupMaps.count(), m_groupHash.value(std::numeric_limits::max()).count()); int rows = m_groupMaps.count() + m_groupHash.value( std::numeric_limits::max() ).count(); //qDebug() << rows << " in root group"; return rows; diff --git a/src/qtgroupingproxy.h b/src/qtgroupingproxy.h index 6ec34481..a7f151ce 100644 --- a/src/qtgroupingproxy.h +++ b/src/qtgroupingproxy.h @@ -14,6 +14,8 @@ * this program. If not, see . * ****************************************************************************************/ +// Modifications 2013-03-27 to 2013-03-28 by Sebastian Herbord + #ifndef GROUPINGPROXY_H #define GROUPINGPROXY_H @@ -30,9 +32,16 @@ typedef QMap RowData; class QtGroupingProxy : public QAbstractProxyModel { Q_OBJECT + +public: + + static const unsigned int FLAG_NOSINGLE = 1; + static const unsigned int FLAG_NAMETOPITEM = 2; + public: explicit QtGroupingProxy( QAbstractItemModel *model, QModelIndex rootNode = QModelIndex(), - int groupedColumn = -1 ); + int groupedColumn = -1, Qt::ItemDataRole groupedRole = Qt::DisplayRole, + unsigned int flags = 0); ~QtGroupingProxy(); void setGroupedColumn( int groupedColumn ); @@ -139,6 +148,8 @@ protected: private: QSet m_expandedItems; + unsigned int m_flags; + int m_groupedRole; }; #endif //GROUPINGPROXY_H -- cgit v1.3.1 From de27ab391f5c56db9532e7cbc32145d21e5df97c Mon Sep 17 00:00:00 2001 From: Tannin Date: Thu, 4 Apr 2013 21:49:44 +0200 Subject: - creating mods from overwrite - moving files from overwrite to mods - offline mode - several fixes to the grouping system - fix to "duplicate translation" errors --- src/mainwindow.cpp | 121 ++++++++++++++++++++---- src/mainwindow.h | 7 ++ src/mainwindow.ui | 12 ++- src/modlist.cpp | 108 +++++++++++++++++----- src/modlist.h | 12 ++- src/modlistsortproxy.cpp | 20 ++-- src/modlistsortproxy.h | 2 - src/organizer.pro | 6 +- src/organizer_de.ts | 6 -- src/organizer_es.ts | 6 -- src/organizer_fr.ts | 6 -- src/overwriteinfodialog.cpp | 4 +- src/overwriteinfodialog.ui | 11 ++- src/pluginlist.cpp | 8 +- src/qtgroupingproxy.cpp | 187 +++++++++++++++++++++++++++++++------- src/qtgroupingproxy.h | 17 +++- src/resources.qrc | 3 + src/resources/emblem-favorite.png | Bin 839 -> 836 bytes src/settings.cpp | 8 ++ src/settings.h | 5 + src/settingsdialog.ui | 13 +++ 21 files changed, 441 insertions(+), 121 deletions(-) (limited to 'src') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 592c933d..2f0ca1db 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -92,10 +92,30 @@ along with Mod Organizer. If not, see . #include +#include + + using namespace MOBase; using namespace MOShared; +static bool isOnline() +{ + QList interfaces = QNetworkInterface::allInterfaces(); + + bool connected = false; + for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) { + if ( (iter->flags() & QNetworkInterface::IsUp) && + (iter->flags() & QNetworkInterface::IsRunning) && + !(iter->flags() & QNetworkInterface::IsLoopBack)) { + connected = true; + } + } + + return connected; +} + + MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), m_Tutorial(this, "MainWindow"), m_ExeName(exeName), m_OldProfileIndex(-1), @@ -134,12 +154,11 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget m_ModListSortProxy = new ModListSortProxy(m_CurrentProfile, this); m_ModListSortProxy->setSourceModel(&m_ModList); - QAbstractProxyModel *proxyModel = new QIdentityProxyModel(this); - proxyModel->setSourceModel(m_ModListSortProxy); - ui->modList->setModel(proxyModel); + ui->modList->setModel(m_ModListSortProxy); ui->modList->sortByColumn(ModList::COL_PRIORITY, Qt::AscendingOrder); ui->modList->setItemDelegateForColumn(ModList::COL_FLAGS, new IconDelegate(ui->modList)); + //ui->modList->setAcceptDrops(true); ui->modList->header()->installEventFilter(&m_ModList); ui->modList->header()->restoreState(initSettings.value("mod_list_state").toByteArray()); ui->modList->installEventFilter(&m_ModList); @@ -161,6 +180,7 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget // set up plugin list m_PluginListSortProxy = new PluginListSortProxy(this); m_PluginListSortProxy->setSourceModel(&m_PluginList); + ui->espList->setModel(m_PluginListSortProxy); ui->espList->sortByColumn(PluginList::COL_PRIORITY, Qt::AscendingOrder); ui->espList->header()->restoreState(initSettings.value("plugin_list_state").toByteArray()); @@ -202,10 +222,13 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget this, SLOT(saveSelectionChanged(QListWidgetItem*))); connect(&m_PluginList, SIGNAL(saveTimer()), this, SLOT(savePluginList())); + connect(&m_ModList, SIGNAL(modorder_changed()), this, SLOT(modorder_changed())); connect(&m_ModList, SIGNAL(removeOrigin(QString)), this, SLOT(removeOrigin(QString))); connect(&m_ModList, SIGNAL(showMessage(QString)), this, SLOT(showMessage(QString))); connect(&m_ModList, SIGNAL(modRenamed(QString,QString)), this, SLOT(modRenamed(QString,QString))); + connect(ui->modList, SIGNAL(dropModeUpdate(bool)), &m_ModList, SLOT(dropModeUpdate(bool))); + connect(m_ModListSortProxy, SIGNAL(filterActive(bool)), this, SLOT(modFilterActive(bool))); connect(ui->modFilterEdit, SIGNAL(textChanged(QString)), m_ModListSortProxy, SLOT(updateFilter(QString))); connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), m_PluginListSortProxy, SLOT(updateFilter(QString))); @@ -242,7 +265,13 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget FileDialogMemory::restore(initSettings); fixCategories(); - m_Updater.testForUpdate(); + + if (isOnline() && !m_Settings.offlineMode()) { + m_Updater.testForUpdate(); + } else { + qDebug("user doesn't seem to be connected to the internet"); + } + m_StartTime = QTime::currentTime(); m_Tutorial.expose("modList", &m_ModList); @@ -670,6 +699,10 @@ void MainWindow::showEvent(QShowEvent *event) m_Settings.directInterface().setValue("first_start", false); } + + // this has no visible impact when called before the ui is visible + int grouping = m_Settings.directInterface().value("group_state").toInt(); + ui->groupCombo->setCurrentIndex(grouping); } @@ -978,12 +1011,14 @@ IModInterface *MainWindow::getMod(const QString &name) IModInterface *MainWindow::createMod(const QString &name) { - unsigned int index = ModInfo::getIndex(name); + QString fixedName = name; + fixDirectoryName(fixedName); + unsigned int index = ModInfo::getIndex(fixedName); if (index != UINT_MAX) { - throw MyException(tr("The mod \"%1\" already exists!").arg(name)); + throw MyException(tr("The mod \"%1\" already exists!").arg(fixedName)); } - QString targetDirectory = QDir::fromNativeSeparators(m_Settings.getModDirectory()).append("/").append(name.trimmed()); + QString targetDirectory = QDir::fromNativeSeparators(m_Settings.getModDirectory()).append("/").append(fixedName.trimmed()); QSettings settingsFile(targetDirectory.mid(0).append("/meta.ini"), QSettings::IniFormat); @@ -1648,9 +1683,6 @@ void MainWindow::readSettings() languageChange(m_Settings.language()); int selectedExecutable = settings.value("selected_executable").toInt(); setExecutableIndex(selectedExecutable); - - int grouping = settings.value("group_state").toInt(); - ui->groupCombo->setCurrentIndex(grouping); } @@ -2490,8 +2522,14 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index, { std::vector flags = modInfo->getFlags(); if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) { - OverwriteInfoDialog dialog(modInfo, this); - dialog.exec(); + QDialog *dialog = this->findChild("__overwriteDialog"); + if (dialog == NULL) { + dialog = new OverwriteInfoDialog(modInfo, this); + dialog->setObjectName("__overwriteDialog"); + } + dialog->show(); + dialog->raise(); + dialog->activateWindow(); } else { ModInfoDialog dialog(modInfo, m_DirectoryStructure, this); connect(&dialog, SIGNAL(nexusLinkActivated(QString)), this, SLOT(nexusLinkActivated(QString))); @@ -2634,6 +2672,17 @@ void MainWindow::testExtractBSA(int modIndex) } +void MainWindow::ignoreMissingData_clicked() +{ + ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow); + QDir(info->absolutePath()).mkdir("textures"); + info->testValid(); + connect(this, SIGNAL(modListDataChanged(QModelIndex,QModelIndex)), &m_ModList, SIGNAL(dataChanged(QModelIndex,QModelIndex))); + + emit modListDataChanged(m_ModList.index(m_ContextRow, 0), m_ModList.index(m_ContextRow, m_ModList.columnCount() - 1)); +} + + void MainWindow::visitOnNexus_clicked() { int modID = m_ModList.data(m_ModList.index(m_ContextRow, 0), Qt::UserRole).toInt(); @@ -2674,6 +2723,28 @@ void MainWindow::syncOverwrite() } +void MainWindow::createModFromOverwrite() +{ + QString name = QInputDialog::getText(this, tr("Create Mod..."), + tr("This will move all files from overwrite into a new, regular mod." + "Please enter a name: ")); + QString fixedName = fixDirectoryName(name); + if (fixedName.isEmpty()) { + reportError(tr("Invalid name")); + return; + } else if (getMod(fixedName) != NULL) { + reportError(tr("A mod with this name already exists")); + return; + } + + IModInterface *newMod = createMod(name); + + ModInfo::Ptr overwriteInfo = ModInfo::getByIndex(m_ContextRow); + + shellMove(QStringList(overwriteInfo->absolutePath() + "\\*"), QStringList(newMod->absolutePath()), this); +} + + void MainWindow::cancelModListEditor() { ui->modList->setEnabled(false); @@ -2959,7 +3030,10 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos) ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow); std::vector flags = info->getFlags(); if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) { - menu.addAction(tr("Sync to Mods..."), this, SLOT(syncOverwrite())); + if (QDir(info->absolutePath()).count() > 2) { + menu.addAction(tr("Sync to Mods..."), this, SLOT(syncOverwrite())); + menu.addAction(tr("Create Mod..."), this, SLOT(createModFromOverwrite())); + } } else if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) != flags.end()) { menu.addAction(tr("Restore Backup"), this, SLOT(restoreBackup_clicked())); menu.addAction(tr("Remove Backup..."), this, SLOT(removeMod_clicked())); @@ -2992,6 +3066,10 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos) menu.addAction(action); } break; } + std::vector flags = info->getFlags(); + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_INVALID) != flags.end()) { + menu.addAction(tr("Ignore missing data"), this, SLOT(ignoreMissingData_clicked())); + } menu.addAction(tr("Visit on Nexus"), this, SLOT(visitOnNexus_clicked())); menu.addAction(tr("Open in explorer"), this, SLOT(openExplorer_clicked())); @@ -4062,25 +4140,30 @@ void MainWindow::on_groupCombo_currentIndexChanged(int index) QAbstractProxyModel *newModel = NULL; switch (index) { case 1: { - newModel = new QtGroupingProxy(m_ModListSortProxy, QModelIndex(), ModList::COL_CATEGORY, Qt::UserRole); + newModel = new QtGroupingProxy(&m_ModList, QModelIndex(), ModList::COL_CATEGORY, Qt::UserRole, + 0, Qt::UserRole + 2); } break; case 2: { - newModel = new QtGroupingProxy(m_ModListSortProxy, QModelIndex(), ModList::COL_MODID); + newModel = new QtGroupingProxy(&m_ModList, QModelIndex(), ModList::COL_MODID, Qt::DisplayRole, + QtGroupingProxy::FLAG_NOGROUPNAME | QtGroupingProxy::FLAG_NOSINGLE, + Qt::UserRole + 2); } break; default: { newModel = NULL; } break; } - if (newModel != NULL) { - newModel->setSourceModel(m_ModListSortProxy); +// newModel->setSourceModel(m_ModListSortProxy); + m_ModListSortProxy->setSourceModel(newModel); connect(ui->modList, SIGNAL(expanded(QModelIndex)),newModel, SLOT(expanded(QModelIndex))); connect(ui->modList, SIGNAL(collapsed(QModelIndex)), newModel, SLOT(collapsed(QModelIndex))); connect(newModel, SIGNAL(expandItem(QModelIndex)), ui->modList, SLOT(expand(QModelIndex))); - ui->modList->setModel(newModel); +// ui->modList->setModel(newModel); } else { - ui->modList->setModel(m_ModListSortProxy); + m_ModListSortProxy->setSourceModel(&m_ModList); +// ui->modList->setModel(m_ModListSortProxy); } +// ui->modList->setModel(m_ModListSortProxy); // ui->modList->setSelectionMode(QAbstractItemView::ExtendedSelection); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 91c2b17d..5880fcb8 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -137,6 +137,10 @@ signals: */ void styleChanged(const QString &styleFile); + + + void modListDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + protected: virtual void showEvent(QShowEvent *event); @@ -310,6 +314,7 @@ private slots: void endorse_clicked(); void dontendorse_clicked(); void unendorse_clicked(); + void ignoreMissingData_clicked(); void visitOnNexus_clicked(); void openExplorer_clicked(); void information_clicked(); @@ -338,6 +343,8 @@ private slots: void syncOverwrite(); + void createModFromOverwrite(); + void removeOrigin(const QString &name); void procError(QProcess::ProcessError error); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index b7d0057e..39a12ec0 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -161,7 +161,7 @@ p, li { white-space: pre-wrap; } - + 330 @@ -280,11 +280,8 @@ p, li { white-space: pre-wrap; } true - - false - - QAbstractItemView::InternalMove + QAbstractItemView::DragDrop Qt::MoveAction @@ -1201,6 +1198,11 @@ Right now this has very limited functionality QLineEdit
lineeditclear.h
+ + ModListView + QTreeView +
modlistview.h
+
diff --git a/src/modlist.cpp b/src/modlist.cpp index 2d681a0d..fc425f85 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -23,6 +23,7 @@ along with Mod Organizer. If not, see . #include "utility.h" #include "messagedialog.h" #include "installationtester.h" +#include "qtgroupingproxy.h" #include #include @@ -49,7 +50,7 @@ using namespace MOBase; ModList::ModList(QObject *parent) : QAbstractItemModel(parent), m_Profile(NULL), m_Modified(false), - m_FontMetrics(QFont()) + m_FontMetrics(QFont()), m_DropOnItems(false) { } @@ -143,15 +144,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const if (priority != INT_MIN) { return QVariant(); // hide priority for mods where it's fixed } else { - if ((m_Profile->getModPriority(modIndex) == 0) && (role == Qt::DisplayRole)) { - return tr("min"); - } else if ((m_Profile->getModPriority(modIndex) == static_cast(m_Profile->numRegularMods()) - 1) && - (role == Qt::DisplayRole)) { - return tr("max"); - } else { - //return QString::number(m_Profile->getModPriority(modIndex)); - return m_Profile->getModPriority(modIndex); - } + return m_Profile->getModPriority(modIndex); } } else if (column == COL_MODID) { int modID = modInfo->getNexusID(); @@ -208,11 +201,21 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else { return QVariant(); } + } else if (column == COL_PRIORITY) { + return m_Profile->getModPriority(modIndex); } else { return modInfo->getNexusID(); } } else if (role == Qt::UserRole + 1) { return modIndex; + } else if (role == Qt::UserRole + 2) { + switch (column) { + case COL_MODID: return QtGroupingProxy::AGGR_FIRST; + case COL_VERSION: return QtGroupingProxy::AGGR_MAX; + case COL_CATEGORY: return QtGroupingProxy::AGGR_FIRST; + case COL_PRIORITY: return QtGroupingProxy::AGGR_MIN; + default: return QtGroupingProxy::AGGR_NONE; + } } else if (role == Qt::FontRole) { QFont result; if (column == COL_NAME) { @@ -323,10 +326,12 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) return false; } + int modID = index.row(); + if (role == Qt::CheckStateRole) { bool enabled = value.toInt() == Qt::Checked; - if (m_Profile->modEnabled(index.row()) != enabled) { - m_Profile->setModEnabled(index.row(), enabled); + if (m_Profile->modEnabled(modID) != enabled) { + m_Profile->setModEnabled(modID, enabled); m_Modified = true; emit modlist_changed(index, role); @@ -335,13 +340,13 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) } else if (role == Qt::EditRole) { switch (index.column()) { case COL_NAME: { - return renameMod(index.row(), value.toString()); + return renameMod(modID, value.toString()); } break; case COL_PRIORITY: { bool ok = false; int newPriority = value.toInt(&ok); if (ok) { - m_Profile->setModPriority(index.row(), newPriority); + m_Profile->setModPriority(modID, newPriority); emit modlist_changed(index, role); return true; @@ -350,7 +355,7 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) } } break; case COL_MODID: { - ModInfo::Ptr info = ModInfo::getByIndex(index.row()); + ModInfo::Ptr info = ModInfo::getByIndex(modID); bool ok = false; int newID = value.toInt(&ok); if (ok) { @@ -362,7 +367,7 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) } } break; case COL_VERSION: { - ModInfo::Ptr info = ModInfo::getByIndex(index.row()); + ModInfo::Ptr info = ModInfo::getByIndex(modID); VersionInfo version(value.toString()); if (version.isValid()) { info->setVersion(version); @@ -435,12 +440,23 @@ Qt::ItemFlags ModList::flags(const QModelIndex &modelIndex) const result |= Qt::ItemIsEditable; } } + std::vector flags = modInfo->getFlags(); + if ((m_DropOnItems) && (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) == flags.end())) { + result |= Qt::ItemIsDropEnabled; + } } else { - result |= Qt::ItemIsDropEnabled; + if (!m_DropOnItems) result |= Qt::ItemIsDropEnabled; } return result; } +QStringList ModList::mimeTypes() const +{ + QStringList result = QAbstractItemModel::mimeTypes(); + result.append("text/uri-list"); + return result; +} + void ModList::changeModPriority(std::vector sourceIndices, int newPriority) { @@ -488,13 +504,39 @@ void ModList::changeModPriority(int sourceIndex, int newPriority) } -bool ModList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int, const QModelIndex &parent) +bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &parent) { - if (action == Qt::IgnoreAction) { - return true; + QStringList source; + QStringList target; + + if (row == -1) { + row = parent.row(); } - if (m_Profile == NULL) return false; + ModInfo::Ptr modInfo = ModInfo::getByIndex(row); + QDir modDirectory(modInfo->absolutePath()); + QDir gameDirectory(QDir::fromNativeSeparators(ToQString(MOShared::GameInfo::instance().getOverwriteDir()))); + + foreach (const QUrl &url, mimeData->urls()) { + QString relativePath = gameDirectory.relativeFilePath(url.toLocalFile()); + if (relativePath.startsWith("..")) { + qDebug("%s drop ignored", qPrintable(url.toLocalFile())); + continue; + } + source.append(url.toLocalFile()); + target.append(modDirectory.absoluteFilePath(relativePath)); + } + + if (source.count() != 0) { + shellCopy(source, target, NULL); + } + + return true; +} + + +bool ModList::dropMod(const QMimeData *mimeData, int row, const QModelIndex &parent) +{ try { QByteArray encoded = mimeData->data("application/x-qabstractitemmodeldatalist"); @@ -538,6 +580,22 @@ bool ModList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int } +bool ModList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int, const QModelIndex &parent) +{ + if (action == Qt::IgnoreAction) { + return true; + } + + if (m_Profile == NULL) return false; + if (mimeData->hasUrls()) { + return dropURLs(mimeData, row, parent); + } else { + return dropMod(mimeData, row, parent); + } + +} + + void ModList::removeRowForce(int row) { if (static_cast(row) >= ModInfo::getNumMods()) { @@ -610,6 +668,14 @@ QMap ModList::itemData(const QModelIndex &index) const } +void ModList::dropModeUpdate(bool dropOnItems) +{ + if (m_DropOnItems != dropOnItems) { + m_DropOnItems = dropOnItems; + } +} + + QString ModList::getColumnName(int column) { switch (column) { diff --git a/src/modlist.h b/src/modlist.h index ea850d54..a0b6e841 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -105,11 +105,11 @@ public: // implementation of virtual functions of QAbstractItemModel virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const; - virtual Qt::DropActions supportedDropActions() const { return Qt::MoveAction; } + virtual Qt::DropActions supportedDropActions() const { return Qt::MoveAction | Qt::CopyAction; } + virtual QStringList mimeTypes() const; virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); virtual void removeRow(int row, const QModelIndex &parent); - virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; virtual QModelIndex parent(const QModelIndex &child) const; @@ -118,6 +118,8 @@ public: // implementation of virtual functions of QAbstractItemModel public slots: + void dropModeUpdate(bool dropOnItems); + signals: /** @@ -202,6 +204,10 @@ private: bool renameMod(int index, const QString &newName); + bool dropURLs(const QMimeData *mimeData, int row, const QModelIndex &parent); + + bool dropMod(const QMimeData *mimeData, int row, const QModelIndex &parent); + private slots: private: @@ -227,6 +233,8 @@ private: QFontMetrics m_FontMetrics; + bool m_DropOnItems; + }; #endif // MODLIST_H diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 071e0384..11b3f69a 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -57,21 +57,20 @@ void ModListSortProxy::setCategoryFilter(int category) this->invalidate(); } - Qt::ItemFlags ModListSortProxy::flags(const QModelIndex &modelIndex) const { Qt::ItemFlags flags = sourceModel()->flags(mapToSource(modelIndex)); if (sortColumn() != ModList::COL_PRIORITY) { flags &= ~Qt::ItemIsDragEnabled; } + return flags; } - void ModListSortProxy::displayColumnSelection(const QPoint &pos) { - QMenu menu; + QMenu menu; for (int i = 0; i <= ModList::COL_LASTCOLUMN; ++i) { QCheckBox *checkBox = new QCheckBox(&menu); @@ -105,7 +104,7 @@ void ModListSortProxy::enableAllVisible() if (m_Profile == NULL) return; for (int i = 0; i < this->rowCount(); ++i) { - int modID = mapToSource(index(i, 0)).row(); + int modID = mapToSource(index(i, 0)).data(Qt::UserRole + 1).toInt(); m_Profile->setModEnabled(modID, true); } invalidate(); @@ -115,18 +114,25 @@ void ModListSortProxy::enableAllVisible() void ModListSortProxy::disableAllVisible() { if (m_Profile == NULL) return; + for (int i = 0; i < this->rowCount(); ++i) { - int modID = mapToSource(index(i, 0)).row(); + int modID = mapToSource(index(i, 0)).data(Qt::UserRole + 1).toInt(); m_Profile->setModEnabled(modID, false); } + invalidate(); } bool ModListSortProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { - int leftIndex = left.row(); - int rightIndex = right.row(); + bool lOk, rOk; + int leftIndex = left.data(Qt::UserRole + 1).toInt(&lOk); + int rightIndex = right.data(Qt::UserRole + 1).toInt(&rOk); + if (!lOk || !rOk) { + return false; + } + ModInfo::Ptr leftMod = ModInfo::getByIndex(leftIndex); ModInfo::Ptr rightMod = ModInfo::getByIndex(rightIndex); diff --git a/src/modlistsortproxy.h b/src/modlistsortproxy.h index 8b86b222..d1e3e238 100644 --- a/src/modlistsortproxy.h +++ b/src/modlistsortproxy.h @@ -54,8 +54,6 @@ public: bool filterMatches(ModInfo::Ptr info, bool enabled) const; -//virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const; - public slots: void displayColumnSelection(const QPoint &pos); diff --git a/src/organizer.pro b/src/organizer.pro index 560394a4..582ba633 100644 --- a/src/organizer.pro +++ b/src/organizer.pro @@ -77,7 +77,8 @@ SOURCES += \ gameinfoimpl.cpp \ csvbuilder.cpp \ savetextasdialog.cpp \ - qtgroupingproxy.cpp + qtgroupingproxy.cpp \ + modlistview.cpp HEADERS += \ transfersavesdialog.h \ @@ -142,7 +143,8 @@ HEADERS += \ gameinfoimpl.h \ csvbuilder.h \ savetextasdialog.h \ - qtgroupingproxy.h + qtgroupingproxy.h \ + modlistview.h FORMS += \ transfersavesdialog.ui \ diff --git a/src/organizer_de.ts b/src/organizer_de.ts index 52e53e8b..6f7dcf1c 100644 --- a/src/organizer_de.ts +++ b/src/organizer_de.ts @@ -1179,12 +1179,6 @@ p, li { white-space: pre-wrap; } installation failed (errorcode %1) Installation fehlgeschlagen (Fehlercode %1) - - - Installation as fomod failed: %1 - failed to open archive "%1": %2 - konnte das Archiv "%1" nicht öffnen: %2 - archive.dll not loaded: "%1" diff --git a/src/organizer_es.ts b/src/organizer_es.ts index c3cfc0fe..a3e77c64 100644 --- a/src/organizer_es.ts +++ b/src/organizer_es.ts @@ -1146,12 +1146,6 @@ p, li { white-space: pre-wrap; } installation failed (errorcode %1) - - - Installation as fomod failed: %1 - failed to open archive "%1": %2 - error al abrir el archivo "%1": %2 - archive.dll not loaded: "%1" diff --git a/src/organizer_fr.ts b/src/organizer_fr.ts index 029451eb..70cd5ab7 100644 --- a/src/organizer_fr.ts +++ b/src/organizer_fr.ts @@ -1139,12 +1139,6 @@ p, li { white-space: pre-wrap; } installation failed (errorcode %1) - - - Installation as fomod failed: %1 - failed to open archive "%1": %2 - impossible d'ouvrir l'archive "%1": %2 - archive.dll not loaded: "%1" diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp index 99699b52..11e7b552 100644 --- a/src/overwriteinfodialog.cpp +++ b/src/overwriteinfodialog.cpp @@ -77,6 +77,8 @@ OverwriteInfoDialog::OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget *parent) { ui->setupUi(this); + this->setWindowModality(Qt::NonModal); + QString path = modInfo->absolutePath(); m_FileSystemModel = new MyFileSystemModel(this); m_FileSystemModel->setReadOnly(false); @@ -84,7 +86,6 @@ OverwriteInfoDialog::OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget *parent) ui->filesView->setModel(m_FileSystemModel); ui->filesView->setRootIndex(m_FileSystemModel->index(path)); ui->filesView->setColumnWidth(0, 250); -// ui->filesView->header()->hideSection(3); m_DeleteAction = new QAction(tr("&Delete"), ui->filesView); m_RenameAction = new QAction(tr("&Rename"), ui->filesView); @@ -225,7 +226,6 @@ void OverwriteInfoDialog::on_filesView_customContextMenuRequested(const QPoint & QItemSelectionModel *selectionModel = ui->filesView->selectionModel(); m_FileSelection = selectionModel->selectedRows(0); -// m_FileSelection = m_FileTree->indexAt(pos); QMenu menu(ui->filesView); menu.addAction(m_NewFolderAction); diff --git a/src/overwriteinfodialog.ui b/src/overwriteinfodialog.ui index 2aa1bcd8..c6119ca6 100644 --- a/src/overwriteinfodialog.ui +++ b/src/overwriteinfodialog.ui @@ -19,6 +19,15 @@ Qt::CustomContextMenu + + true + + + QAbstractItemView::DragOnly + + + QAbstractItemView::ExtendedSelection + true @@ -30,7 +39,7 @@ Qt::Horizontal
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok + QDialogButtonBox::Close
diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index dfac8ccb..b5bb483b 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -599,13 +599,7 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const return m_ESPs[index].m_Name; } break; case COL_PRIORITY: { - if (m_ESPs[index].m_Priority == 0) { - return tr("min"); - } else if (m_ESPs[index].m_Priority == static_cast(m_ESPs.size()) - 1) { - return tr("max"); - } else { - return QString::number(m_ESPs[index].m_Priority); - } + return m_ESPs[index].m_Priority; } break; case COL_MODINDEX: { if (m_ESPs[index].m_LoadOrder == -1) { diff --git a/src/qtgroupingproxy.cpp b/src/qtgroupingproxy.cpp index 95a4aad0..4e066f65 100644 --- a/src/qtgroupingproxy.cpp +++ b/src/qtgroupingproxy.cpp @@ -14,7 +14,7 @@ * this program. If not, see . * ****************************************************************************************/ -// Modifications 2013-03-27 to 2013-03-28 by Sebastian Herbord +// Modifications 2013-03-27 to 2013-03-29 by Sebastian Herbord #include "QtGroupingProxy.h" @@ -31,11 +31,12 @@ \ingroup model-view */ -QtGroupingProxy::QtGroupingProxy(QAbstractItemModel *model, QModelIndex rootNode, int groupedColumn, Qt::ItemDataRole groupedRole, unsigned int flags ) +QtGroupingProxy::QtGroupingProxy(QAbstractItemModel *model, QModelIndex rootNode, int groupedColumn, int groupedRole, unsigned int flags , int aggregateRole) : QAbstractProxyModel() , m_rootNode( rootNode ) , m_groupedColumn( 0 ) , m_groupedRole( groupedRole ) + , m_aggregateRole( aggregateRole ) , m_flags( flags ) { setSourceModel( model ); @@ -104,7 +105,7 @@ QtGroupingProxy::belongsTo( const QModelIndex &idx ) i.next(); int role = i.key(); QVariant variant = i.value(); - qDebug() << "role " << role << " : (" << variant.typeName() << ") : "<< variant; + // qDebug() << "role " << role << " : (" << variant.typeName() << ") : "<< variant; if ( variant.type() == QVariant::List ) { //a list of variants get's expanded to multiple rows @@ -171,7 +172,32 @@ QtGroupingProxy::buildTree() //dumpGroups(); if (m_flags & FLAG_NOSINGLE) { + // awkward: flatten single-item groups as a post-processing steps. + int currentKey = 0; + quint32 quint32max = std::numeric_limits::max(); + std::vector rmgroups; + + QHash > temp; + + for (auto iter = m_groupHash.begin(); iter != m_groupHash.end(); ++iter) { + if ((iter.key() == quint32max) || + (iter->count() == 1)) { + temp[quint32max].append(iter.value()); + if (iter.key() != quint32max) { + rmgroups.push_back(iter.key()); + } + } else { + temp[currentKey++] = *iter; + } + } + m_groupHash = temp; + + // second loop is necessary because qt containers can't be iterated from end to + // removing by index from begin to end is ugly + for (auto iter = rmgroups.rbegin(); iter != rmgroups.rend(); ++iter) { + m_groupMaps.removeAt(*iter); + } } endResetModel(); @@ -191,6 +217,7 @@ QtGroupingProxy::addSourceRow( const QModelIndex &idx ) QList updatedGroups; QList groupData = belongsTo( idx ); + //an empty list here means it's supposed to go in root. if( groupData.isEmpty() ) { @@ -346,7 +373,6 @@ QtGroupingProxy::rowCount( const QModelIndex &index ) const if( !index.isValid() ) { //the number of top level groups + the number of non-grouped items - qDebug("groups: %d - ungrouped: %d", m_groupMaps.count(), m_groupHash.value(std::numeric_limits::max()).count()); int rows = m_groupMaps.count() + m_groupHash.value( std::numeric_limits::max() ).count(); //qDebug() << rows << " in root group"; return rows; @@ -359,12 +385,12 @@ QtGroupingProxy::rowCount( const QModelIndex &index ) const int rows = m_groupHash.value( groupIndex ).count(); //qDebug() << rows << " in group " << m_groupMaps[groupIndex]; return rows; + } else { + QModelIndex originalIndex = mapToSource( index ); + int rowCount = sourceModel()->rowCount( originalIndex ); + //qDebug() << "original item: rowCount == " << rowCount; + return rowCount; } - - QModelIndex originalIndex = mapToSource( index ); - int rowCount = sourceModel()->rowCount( originalIndex ); - //qDebug() << "original item: rowCount == " << rowCount; - return rowCount; } int @@ -379,6 +405,44 @@ QtGroupingProxy::columnCount( const QModelIndex &index ) const return sourceModel()->columnCount( mapToSource( index ) ); } + +static bool variantLess(const QVariant &LHS, const QVariant &RHS) +{ + if ((LHS.type() == RHS.type()) && + ((LHS.type() == QVariant::Int) || (LHS.type() == QVariant::UInt))) { + return LHS.toInt() < RHS.toInt(); + } + + // this should always work (comparing empty strings in the worst case) but + // the results may be wrong + return LHS.toString() < RHS.toString(); +} + + +static QVariant variantMax(const QVariantList &variants) +{ + QVariant result = variants.first(); + foreach (const QVariant &iter, variants) { + if (variantLess(result, iter)) { + result = iter; + } + } + return result; +} + + +static QVariant variantMin(const QVariantList &variants) +{ + QVariant result = variants.first(); + foreach (const QVariant &iter, variants) { + if (variantLess(iter, result)) { + result = iter; + } + } + return result; +} + + QVariant QtGroupingProxy::data( const QModelIndex &index, int role ) const { @@ -389,18 +453,8 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const int column = index.column(); if( isGroup( index ) ) { - if (column != 0) return QVariant(); - - //qDebug() << __FUNCTION__ << "is a group"; - //use cached or precalculated data - if( m_groupMaps[row][column].contains( Qt::DisplayRole ) ) - { - //qDebug() << "Using cached data"; + if ((role != Qt::DisplayRole) && (role != Qt::EditRole)) { switch (role) { - case Qt::DisplayRole: { - QString value = m_groupMaps[row][column].value( role ).toString(); - return QString("----- %1 -----").arg(value.isEmpty() ? tr("") : value); - } break; case Qt::ForegroundRole: { return QBrush(Qt::gray); } break; @@ -415,13 +469,47 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const case Qt::UserRole: { return m_groupMaps[row][column].value( Qt::DisplayRole ).toString(); } break; + case Qt::CheckStateRole: { + if (column != 0) return QVariant(); + int childCount = m_groupHash.value( row ).count(); + int checked = 0; + QModelIndex parentIndex = this->index( row, 0, index.parent() ); + for( int childRow = 0; childRow < childCount; ++childRow ) + { + QModelIndex childIndex = this->index( childRow, 0, parentIndex ); + QVariant data = mapToSource( childIndex ).data( Qt::CheckStateRole ); + if (data.toInt() == 2) ++checked; + } + if (checked == childCount) return Qt::Checked; + else if (checked == 0) return Qt::Unchecked; + else return Qt::PartiallyChecked; + } break; default: { - return QVariant(); + QModelIndex parentIndex = this->index( row, 0, index.parent() ); + if (m_groupHash.value( row ).count() > 0) { + return this->index(0, 0, parentIndex).data(role); + } else { + return QVariant(); + } // return m_groupMaps[row][column].value( role ); } break; } } + //qDebug() << __FUNCTION__ << "is a group"; + //use cached or precalculated data + if( m_groupMaps[row][column].contains( Qt::DisplayRole ) ) + { + // qDebug() << "Using cached data for " << row << "x" << column << ": " << m_groupMaps[row][column].value(Qt::DisplayRole).toString(); + if ((m_flags & FLAG_NOGROUPNAME) != 0) { + QModelIndex parentIndex = this->index( row, 0, index.parent() ); + QModelIndex childIndex = this->index( 0, column, parentIndex ); + return childIndex.data(role).toString(); + } else { + return m_groupMaps[row][column].value( role ).toString(); + } + } + //for column 0 we gather data from the grouped column instead if( column == 0 ) column = m_groupedColumn; @@ -432,6 +520,13 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const if( childCount == 0 ) return QVariant(); + int function = AGGR_NONE; + if (m_aggregateRole >= Qt::UserRole) { + QModelIndex parentIndex = this->index( row, 0, index.parent() ); + QModelIndex childIndex = this->index( 0, column, parentIndex ); + function = mapToSource(childIndex).data(m_aggregateRole).toInt(); + } + //qDebug() << __FUNCTION__ << "childCount: " << childCount; //Need a parentIndex with column == 0 because only those have children. QModelIndex parentIndex = this->index( row, 0, index.parent() ); @@ -448,19 +543,29 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const ItemData roleMap = m_groupMaps[row].value( column ); foreach( const QVariant &variant, variantsOfChildren ) { - if( roleMap[ role ] != variant ) + if( roleMap[ role ] != variant ) { roleMap.insert( role, variantsOfChildren ); + } } //qDebug() << QString("roleMap[%1]:").arg(role) << roleMap[role]; - //only one unique variant? No need to return a list - if( variantsOfChildren.count() == 1 ) - return variantsOfChildren.first(); if( variantsOfChildren.count() == 0 ) return QVariant(); - return variantsOfChildren; + //only one unique variant? No need to return a list + switch (function) { + case AGGR_EMPTY: return QVariant(); + case AGGR_FIRST: return variantsOfChildren.first(); + case AGGR_MAX: return variantMax(variantsOfChildren); + case AGGR_MIN: return variantMin(variantsOfChildren); + default: { + if( variantsOfChildren.count() == 1 ) + return variantsOfChildren.first(); + + return variantsOfChildren; + } break; + } } return mapToSource( index ).data( role ); @@ -612,7 +717,7 @@ QtGroupingProxy::mapFromSource( const QModelIndex &idx ) const //qDebug() << "proxyParent: " << proxyParent; //qDebug() << "proxyRow: " << proxyRow; - return this->index( proxyRow, 0, proxyParent ); + return this->index( proxyRow, idx.column(), proxyParent ); } Qt::ItemFlags @@ -632,10 +737,28 @@ QtGroupingProxy::flags( const QModelIndex &idx ) const if( isGroup( idx ) ) { // dumpGroups(); - // Qt::ItemFlags defaultFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable ); - Qt::ItemFlags defaultFlags(Qt::NoItemFlags); + Qt::ItemFlags defaultFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable ); + //Qt::ItemFlags defaultFlags(Qt::ItemIsEnabled); bool groupIsEditable = true; + if (idx.column() == 0) { + bool checkable = true; + foreach ( int originalRow, m_groupHash.value( idx.row() ) ) + { + QModelIndex originalIdx = sourceModel()->index( originalRow, 0, + m_rootNode.parent() ); + if ( (originalIdx.flags() & Qt::ItemIsUserCheckable) == 0 ) + { + qDebug("row %d is not checkable", originalRow); + checkable = false; + } + } + + if ( checkable ) { + defaultFlags |= Qt::ItemIsUserCheckable; + } + } + //it's possible to have empty groups if( m_groupHash.value( idx.row() ).count() == 0 ) { @@ -658,7 +781,6 @@ QtGroupingProxy::flags( const QModelIndex &idx ) const break; } } - if( groupIsEditable ) return ( defaultFlags | Qt::ItemIsEditable | Qt::ItemIsDropEnabled ); return defaultFlags; @@ -671,9 +793,9 @@ QtGroupingProxy::flags( const QModelIndex &idx ) const QModelIndex groupedColumnIndex = sourceModel()->index( originalIdx.row(), m_groupedColumn, originalIdx.parent() ); bool groupIsEditable = sourceModel()->flags( groupedColumnIndex ).testFlag( Qt::ItemIsEditable ); + if( groupIsEditable ) return originalItemFlags | Qt::ItemIsDragEnabled; - return originalItemFlags; } @@ -736,8 +858,9 @@ QtGroupingProxy::hasChildren( const QModelIndex &parent ) const if( !parent.isValid() ) return true; - if( isGroup( parent ) ) + if( isGroup( parent ) ) { return !m_groupHash.value( parent.row() ).isEmpty(); + } return sourceModel()->hasChildren( mapToSource( parent ) ); } diff --git a/src/qtgroupingproxy.h b/src/qtgroupingproxy.h index a7f151ce..e09ae7b4 100644 --- a/src/qtgroupingproxy.h +++ b/src/qtgroupingproxy.h @@ -36,12 +36,21 @@ class QtGroupingProxy : public QAbstractProxyModel public: static const unsigned int FLAG_NOSINGLE = 1; - static const unsigned int FLAG_NAMETOPITEM = 2; + static const unsigned int FLAG_NOGROUPNAME = 2; + + enum EAggregateFunction { + AGGR_NONE, // no aggregation, return child elements as list + AGGR_EMPTY, // display nothing + AGGR_FIRST, // return value of the topmost item + AGGR_MAX, // return maximum value + AGGR_MIN // return minimum value + }; public: explicit QtGroupingProxy( QAbstractItemModel *model, QModelIndex rootNode = QModelIndex(), - int groupedColumn = -1, Qt::ItemDataRole groupedRole = Qt::DisplayRole, - unsigned int flags = 0); + int groupedColumn = -1, int groupedRole = Qt::DisplayRole, + unsigned int flags = 0, + int aggregateRole = Qt::DisplayRole); ~QtGroupingProxy(); void setGroupedColumn( int groupedColumn ); @@ -150,6 +159,8 @@ private: QSet m_expandedItems; unsigned int m_flags; int m_groupedRole; + + int m_aggregateRole; }; #endif //GROUPINGPROXY_H diff --git a/src/resources.qrc b/src/resources.qrc index 855a23fc..a743ba39 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -50,5 +50,8 @@ resources/conflict-overwritten.png resources/conflict-redundant.png resources/accessories-text-editor.png + resources/network-idle.png + resources/network-offline.png + resources/network-error.png diff --git a/src/resources/emblem-favorite.png b/src/resources/emblem-favorite.png index b43e09c7..6f003c55 100644 Binary files a/src/resources/emblem-favorite.png and b/src/resources/emblem-favorite.png differ diff --git a/src/settings.cpp b/src/settings.cpp index 3ee916c0..57fba055 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -165,6 +165,11 @@ bool Settings::getNexusLogin(QString &username, QString &password) const } } +bool Settings::offlineMode() const +{ + return m_Settings.value("Settings/offline_mode", false).toBool(); +} + int Settings::logLevel() const { return m_Settings.value("Settings/log_level", 0).toInt(); @@ -367,6 +372,7 @@ void Settings::query(QWidget *parent) QCheckBox *preferIntegratedCheckBox = dialog.findChild("preferIntegratedBox"); QCheckBox *preferExternalBox = dialog.findChild("preferExternalBox"); QCheckBox *quickInstallerBox = dialog.findChild("quickInstallerBox"); + QCheckBox *offlineBox = dialog.findChild("offlineBox"); QLineEdit *nmmVersionEdit = dialog.findChild("nmmVersionEdit"); QListWidget *pluginsList = dialog.findChild("pluginsList"); @@ -447,6 +453,7 @@ void Settings::query(QWidget *parent) preferIntegratedCheckBox->setChecked(m_Settings.value("Settings/prefer_integrated_installer", false).toBool()); preferExternalBox->setChecked(m_Settings.value("Settings/prefer_external_browser", false).toBool()); quickInstallerBox->setChecked(m_Settings.value("Settings/enable_quick_installer", true).toBool()); + offlineBox->setChecked(m_Settings.value("Settings/offline_mode", false).toBool()); nmmVersionEdit->setText(m_Settings.value("Settings/nmm_version", "0.33.1").toString()); logLevelBox->setCurrentIndex(logLevel()); @@ -516,6 +523,7 @@ void Settings::query(QWidget *parent) } m_Settings.setValue("Settings/prefer_integrated_installer", preferIntegratedCheckBox->isChecked()); m_Settings.setValue("Settings/prefer_external_browser", preferExternalBox->isChecked()); + m_Settings.setValue("Settings/offline_mode", offlineBox->isChecked()); m_Settings.setValue("Settings/enable_quick_installer", quickInstallerBox->isChecked()); m_Settings.setValue("Settings/nmm_version", nmmVersionEdit->text()); diff --git a/src/settings.h b/src/settings.h index 34d61a24..38f22b71 100644 --- a/src/settings.h +++ b/src/settings.h @@ -124,6 +124,11 @@ public: **/ bool getNexusLogin(QString &username, QString &password) const; + /** + * @return true if the user disabled internet features + */ + bool offlineMode() const; + /** * @return the configured log level */ diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 6c54bc62..f248ae29 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -391,6 +391,19 @@ On some systems this will require administrative rights. + + + + Disable automatic internet features + + + Disable automatic internet features. This does not affect features that are explicitly invoked by the user (like checking mods for updates, endorsing, opening the web browser) + + + Offline Mode + + + -- cgit v1.3.1 From 5b04f38345850db86d8f43a42dd946810bceba8a Mon Sep 17 00:00:00 2001 From: Tannin Date: Thu, 4 Apr 2013 21:51:13 +0200 Subject: added modlist view class (updates drop behaviour on modlist depending on mime type) --- src/modlistview.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/modlistview.h | 20 ++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 src/modlistview.cpp create mode 100644 src/modlistview.h (limited to 'src') diff --git a/src/modlistview.cpp b/src/modlistview.cpp new file mode 100644 index 00000000..88adcceb --- /dev/null +++ b/src/modlistview.cpp @@ -0,0 +1,47 @@ +#include "modlistview.h" +#include +#include + + +class ModListViewStyle: public QProxyStyle{ +public: + ModListViewStyle(QStyle *style, int indentation); + + void drawPrimitive (PrimitiveElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget = 0) const; +private: + int m_Indentation; +}; + +ModListViewStyle::ModListViewStyle(QStyle *style, int indentation) + : QProxyStyle(style), m_Indentation(indentation) +{ +} + +void ModListViewStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget) const +{ + if (element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull()) { + QStyleOption opt(*option); + opt.rect.setLeft(m_Indentation); + if (widget) { + opt.rect.setRight(widget->width() - 5); // 5 is an arbitrary value that seems to work ok + } + QProxyStyle::drawPrimitive(element, &opt, painter, widget); + } else { + QProxyStyle::drawPrimitive(element, option, painter, widget); + } +} + +ModListView::ModListView(QWidget *parent) + : QTreeView(parent) +{ + setStyle(new ModListViewStyle(style(), indentation())); +} + +void ModListView::dragEnterEvent(QDragEnterEvent *event) +{ + emit dropModeUpdate(event->mimeData()->hasUrls()); + + QTreeView::dragEnterEvent(event); +} diff --git a/src/modlistview.h b/src/modlistview.h new file mode 100644 index 00000000..e501a660 --- /dev/null +++ b/src/modlistview.h @@ -0,0 +1,20 @@ +#ifndef MODLISTVIEW_H +#define MODLISTVIEW_H + +#include +#include + +class ModListView : public QTreeView +{ + Q_OBJECT +public: + explicit ModListView(QWidget *parent = 0); + virtual void dragEnterEvent(QDragEnterEvent *event); +signals: + void dropModeUpdate(bool dropOnRows); + +public slots: + +}; + +#endif // MODLISTVIEW_H -- cgit v1.3.1 From 528338d7bfb5479115511f77b70219eda1b32a62 Mon Sep 17 00:00:00 2001 From: Tannin Date: Fri, 5 Apr 2013 18:24:36 +0200 Subject: some code cleanup --- src/mainwindow.cpp | 25 ++++++++++++------------- src/modlist.cpp | 2 +- 2 files changed, 13 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2f0ca1db..6b546d4d 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -209,32 +209,28 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget NexusInterface::instance()->setNMMVersion(m_Settings.getNMMVersion()); updateDownloadListDelegate(); - connect(&m_ModList, SIGNAL(requestColumnSelect(QPoint)), this, SLOT(displayColumnSelection(QPoint))); - - connect(&m_DownloadManager, SIGNAL(showMessage(QString)), this, SLOT(showMessage(QString))); - - connect(NexusInterface::instance(), SIGNAL(requestNXMDownload(QString)), this, SLOT(downloadRequestedNXM(QString))); - connect(&m_NexusDialog, SIGNAL(requestDownload(QNetworkReply*, int, QString)), this, SLOT(downloadRequested(QNetworkReply*, int, QString))); ui->savegameList->installEventFilter(this); ui->savegameList->setMouseTracking(true); - connect(ui->savegameList, SIGNAL(itemEntered(QListWidgetItem*)), - this, SLOT(saveSelectionChanged(QListWidgetItem*))); - connect(&m_PluginList, SIGNAL(saveTimer()), this, SLOT(savePluginList())); + connect(&m_DownloadManager, SIGNAL(showMessage(QString)), this, SLOT(showMessage(QString))); + + connect(ui->savegameList, SIGNAL(itemEntered(QListWidgetItem*)), this, SLOT(saveSelectionChanged(QListWidgetItem*))); connect(&m_ModList, SIGNAL(modorder_changed()), this, SLOT(modorder_changed())); connect(&m_ModList, SIGNAL(removeOrigin(QString)), this, SLOT(removeOrigin(QString))); connect(&m_ModList, SIGNAL(showMessage(QString)), this, SLOT(showMessage(QString))); connect(&m_ModList, SIGNAL(modRenamed(QString,QString)), this, SLOT(modRenamed(QString,QString))); + connect(&m_ModList, SIGNAL(modlist_changed(QModelIndex, int)), this, SLOT(modlistChanged(QModelIndex, int))); + connect(&m_ModList, SIGNAL(removeSelectedMods()), this, SLOT(removeMod_clicked())); + connect(&m_ModList, SIGNAL(requestColumnSelect(QPoint)), this, SLOT(displayColumnSelection(QPoint))); connect(ui->modList, SIGNAL(dropModeUpdate(bool)), &m_ModList, SLOT(dropModeUpdate(bool))); - connect(m_ModListSortProxy, SIGNAL(filterActive(bool)), this, SLOT(modFilterActive(bool))); connect(ui->modFilterEdit, SIGNAL(textChanged(QString)), m_ModListSortProxy, SLOT(updateFilter(QString))); + connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), m_PluginListSortProxy, SLOT(updateFilter(QString))); connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), this, SLOT(espFilterChanged(QString))); - connect(&m_ModList, SIGNAL(modlist_changed(QModelIndex, int)), this, SLOT(modlistChanged(QModelIndex, int))); - connect(&m_ModList, SIGNAL(removeSelectedMods()), this, SLOT(removeMod_clicked())); + connect(&m_PluginList, SIGNAL(saveTimer()), this, SLOT(savePluginList())); connect(&m_DirectoryRefresher, SIGNAL(refreshed()), this, SLOT(directory_refreshed())); connect(&m_DirectoryRefresher, SIGNAL(progress(int)), this, SLOT(refresher_progress(int))); @@ -242,17 +238,20 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget connect(&m_Settings, SIGNAL(languageChanged(QString)), this, SLOT(languageChange(QString))); connect(&m_Settings, SIGNAL(styleChanged(QString)), this, SIGNAL(styleChanged(QString))); - connect(this, SIGNAL(styleChanged(QString)), this, SLOT(updateStyle(QString))); connect(&m_Updater, SIGNAL(restart()), this, SLOT(close())); connect(&m_Updater, SIGNAL(updateAvailable()), this, SLOT(updateAvailable())); connect(&m_Updater, SIGNAL(motdAvailable(QString)), this, SLOT(motdReceived(QString))); + connect(&m_NexusDialog, SIGNAL(requestDownload(QNetworkReply*, int, QString)), this, SLOT(downloadRequested(QNetworkReply*, int, QString))); connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginSuccessful(bool)), this, SLOT(loginSuccessful(bool))); connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginFailed(QString)), this, SLOT(loginFailed(QString))); + connect(NexusInterface::instance(), SIGNAL(requestNXMDownload(QString)), this, SLOT(downloadRequestedNXM(QString))); connect(&TutorialManager::instance(), SIGNAL(windowTutorialFinished(QString)), this, SLOT(windowTutorialFinished(QString))); + connect(this, SIGNAL(styleChanged(QString)), this, SLOT(updateStyle(QString))); + m_CheckBSATimer.setSingleShot(true); connect(&m_CheckBSATimer, SIGNAL(timeout()), this, SLOT(checkBSAList())); diff --git a/src/modlist.cpp b/src/modlist.cpp index fc425f85..f186ce8e 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -528,7 +528,7 @@ bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &pa } if (source.count() != 0) { - shellCopy(source, target, NULL); + shellMove(source, target, NULL); } return true; -- cgit v1.3.1 From 1c9018e9fdba7878b0ef605f81529c20ef3bbffe Mon Sep 17 00:00:00 2001 From: Tannin Date: Sat, 13 Apr 2013 19:23:18 +0200 Subject: - 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) --- src/installationmanager.cpp | 2 - src/main.cpp | 19 ++++++++ src/mainwindow.cpp | 75 +++++++++++++++++++++++++------- src/mainwindow.h | 3 +- src/modlist.cpp | 15 ++++--- src/organizer.pro | 9 ++-- src/problemsdialog.cpp | 58 ++++++++++++++++++++++++ src/problemsdialog.h | 35 +++++++++++++++ src/problemsdialog.ui | 104 ++++++++++++++++++++++++++++++++++++++++++++ src/resources.qrc | 3 -- 10 files changed, 293 insertions(+), 30 deletions(-) create mode 100644 src/problemsdialog.cpp create mode 100644 src/problemsdialog.h create mode 100644 src/problemsdialog.ui (limited to 'src') 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 . */ #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 . #include #include #include +#include #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 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 . #include "csvbuilder.h" #include "gameinfoimpl.h" #include "savetextasdialog.h" +#include "problemsdialog.h" #include #include #include +#include #include #include #include @@ -84,14 +86,13 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include #include #include #include #include - - #include @@ -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 activeProblems = diagnose->activeProblems(); - foreach (unsigned int key, activeProblems) { - problemDescription.append(tr("
  • %1
  • ").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("
  • NCC not installed. You won't be able to install some scripted mod-installers. Get NCC from the MO page on nexus
  • ")); @@ -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(plugin); if (diagnose != NULL) { m_DiagnosisPlugins.push_back(diagnose); + addon = true; } } - { // tool plugins IPluginTool *tool = qobject_cast(plugin); if (verifyPlugin(tool)) { @@ -934,7 +940,25 @@ bool MainWindow::registerPlugin(QObject *plugin) return true; } } - return false; + { // proxy plugins + IPluginProxy *proxy = qobject_cast(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 . #include "modlist.h" #include "report.h" -#include "utility.h" #include "messagedialog.h" #include "installationtester.h" #include "qtgroupingproxy.h" #include - +#include #include #include #include @@ -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 +#include +#include +#include + + +using namespace MOBase; + + +ProblemsDialog::ProblemsDialog(std::vector diagnosePlugins, QWidget *parent) + : QDialog(parent), ui(new Ui::ProblemsDialog) +{ + ui->setupUi(this); + + foreach (IPluginDiagnose *diagnose, diagnosePlugins) { + std::vector 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 +#include +#include + + +namespace Ui { +class ProblemsDialog; +} + + +class ProblemsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ProblemsDialog(std::vector 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 @@ + + + ProblemsDialog + + + + 0 + 0 + 574 + 376 + + + + Problems + + + + + + 2 + + + false + + + 420 + + + + 1 + + + + + 2 + + + + + + + + QTextEdit::NoWrap + + + true + + + <!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> + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + ProblemsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ProblemsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + 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 @@ resources/conflict-overwritten.png resources/conflict-redundant.png resources/accessories-text-editor.png - resources/network-idle.png - resources/network-offline.png - resources/network-error.png -- cgit v1.3.1 From d161e1a0d61181185323fcb547d9e0651d546fb2 Mon Sep 17 00:00:00 2001 From: Tannin Date: Sun, 14 Apr 2013 20:49:18 +0200 Subject: - if no version is known for a mod, the file date is used - added files for the python proxy --- src/installationmanager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 63945150..16761f24 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -43,6 +43,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include @@ -720,6 +721,11 @@ bool InstallationManager::install(const QString &fileName, const QString &modsDi categoryID = CategoryFactory::instance().getCategoryID(categoryIndex); } + if (version.isEmpty()) { + QDateTime lastMod = fileInfo.lastModified(); + version = "d" + lastMod.toString("yyyy.M.d"); + } + { // guess the mod name and mod if from the file name if there was no meta information QString guessedModName; int guessedModID = modID; -- cgit v1.3.1 From 9bc123e8e2dbd17508a68e4afc2eb881873601bd Mon Sep 17 00:00:00 2001 From: Tannin Date: Fri, 10 May 2013 10:57:35 +0200 Subject: - initial support for exposing the nexusbridge to python - started improving usability of nexus bridge - support for installers implemented in python --- src/downloadlist.h | 142 ++++++++++++++++++------------------ src/installationmanager.cpp | 16 ++-- src/mainwindow.cpp | 11 ++- src/mainwindow.h | 1 + src/modinfo.cpp | 62 +++------------- src/modinfo.h | 20 +++-- src/modinfodialog.cpp | 15 ++-- src/modlist.cpp | 13 +++- src/nexusdialog.cpp | 4 +- src/nexusinterface.cpp | 54 +++++++++----- src/nexusinterface.h | 43 +++++------ src/organizer.pro | 1 + src/resources.qrc | 1 + src/resources/x-office-calendar.png | Bin 0 -> 604 bytes src/version.rc | 4 +- 15 files changed, 192 insertions(+), 195 deletions(-) create mode 100644 src/resources/x-office-calendar.png (limited to 'src') diff --git a/src/downloadlist.h b/src/downloadlist.h index abd177b2..1ae97cd0 100644 --- a/src/downloadlist.h +++ b/src/downloadlist.h @@ -17,76 +17,72 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see . */ -#ifndef DOWNLOADLIST_H -#define DOWNLOADLIST_H - -#include - - -class DownloadManager; - - -/** - * @brief model of the list of active and completed downloads - **/ -class DownloadList : public QAbstractTableModel -{ - - Q_OBJECT - -public: - - /** - * @brief constructor - * - * @param manager the download manager processing downloads - * @param parent parent object Defaults to 0. - **/ - explicit DownloadList(DownloadManager *manager, QObject *parent = 0); - - /** - * @brief retrieve the number of rows to display. Invoked by Qt - * - * @param parent not relevant for this implementation - * @return number of rows to display - **/ - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; - - virtual int columnCount(const QModelIndex &parent) const; - - QModelIndex index(int row, int column, const QModelIndex &parent) const; - QModelIndex parent(const QModelIndex &child) const; - - virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; - - /** - * @brief retrieve the data to display in a specific row. Invoked by Qt - * - * @param index location to look up - * @param role ... Defaults to Qt::DisplayRole. - * @return this implementation only returns the row, the QItemDelegate implementation is expected to fetch its information from the DownloadManager - **/ - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - -signals: - -public slots: - - /** - * @brief used to inform the model that data has changed - * - * @param row the row that changed. This can be negative to update the whole view - **/ - void update(int row); - - void aboutToUpdate(); - -private: - -private: - - DownloadManager *m_Manager; - -}; - -#endif // DOWNLOADLIST_H +#ifndef DOWNLOADLIST_H +#define DOWNLOADLIST_H + +#include + + +class DownloadManager; + + +/** + * @brief model of the list of active and completed downloads + **/ +class DownloadList : public QAbstractTableModel +{ + + Q_OBJECT + +public: + + /** + * @brief constructor + * + * @param manager the download manager processing downloads + * @param parent parent object Defaults to 0. + **/ + explicit DownloadList(DownloadManager *manager, QObject *parent = 0); + + /** + * @brief retrieve the number of rows to display. Invoked by Qt + * + * @param parent not relevant for this implementation + * @return number of rows to display + **/ + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + + virtual int columnCount(const QModelIndex &parent) const; + + QModelIndex index(int row, int column, const QModelIndex &parent) const; + QModelIndex parent(const QModelIndex &child) const; + + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + + /** + * @brief retrieve the data to display in a specific row. Invoked by Qt + * + * @param index location to look up + * @param role ... Defaults to Qt::DisplayRole. + * @return this implementation only returns the row, the QItemDelegate implementation is expected to fetch its information from the DownloadManager + **/ + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + +public slots: + + /** + * @brief used to inform the model that data has changed + * + * @param row the row that changed. This can be negative to update the whole view + **/ + void update(int row); + + void aboutToUpdate(); + +private: + + DownloadManager *m_Manager; + +}; + +#endif // DOWNLOADLIST_H diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 16761f24..52ef01c1 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -693,7 +693,7 @@ bool InstallationManager::install(const QString &fileName, const QString &modsDi GuessedValue &modName, bool &hasIniTweaks) { QFileInfo fileInfo(fileName); - bool success = false; +// bool success = false; if (m_SupportedExtensions.find(fileInfo.suffix()) == m_SupportedExtensions.end()) { reportError(tr("File format \"%1\" not supported").arg(fileInfo.completeSuffix())); return false; @@ -706,7 +706,7 @@ bool InstallationManager::install(const QString &fileName, const QString &modsDi QString version = ""; QString newestVersion = ""; int categoryID = 0; - bool nameGuessed = false; +// bool nameGuessed = false; QString metaName = fileName.mid(0).append(".meta"); if (QFile(metaName).exists()) { @@ -804,10 +804,14 @@ bool InstallationManager::install(const QString &fileName, const QString &modsDi return false; } break; case IPluginInstaller::RESULT_SUCCESS: { - DirectoryTree::node_iterator iniTweakNode = filesTree->nodeFind(DirectoryTreeInformation("INI Tweaks")); - hasIniTweaks = (iniTweakNode != filesTree->nodesEnd()) && - ((*iniTweakNode)->numLeafs() != 0); - return true; + if (filesTree != NULL) { + DirectoryTree::node_iterator iniTweakNode = filesTree->nodeFind(DirectoryTreeInformation("INI Tweaks")); + hasIniTweaks = (iniTweakNode != filesTree->nodesEnd()) && + ((*iniTweakNode)->numLeafs() != 0); + return true; + } else { + return false; + } } break; } } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2fd47537..50c81ccc 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -900,7 +900,7 @@ void MainWindow::registerPluginTool(IPluginTool *tool) action->setToolTip(tool->tooltip()); tool->setParentWidget(this); action->setData(qVariantFromValue((void*)tool)); - connect(action, SIGNAL(triggered()), this, SLOT(toolPluginInvoke())); + connect(action, SIGNAL(triggered()), this, SLOT(toolPluginInvoke()), Qt::QueuedConnection); QToolButton *toolBtn = qobject_cast(ui->toolBar->widgetForAction(ui->actionTool)); toolBtn->menu()->addAction(action); } @@ -911,6 +911,7 @@ bool MainWindow::registerPlugin(QObject *plugin) { // generic treatment for all plugins IPlugin *pluginObj = qobject_cast(plugin); if (pluginObj == NULL) { + qDebug("not an IPlugin"); return false; } m_Settings.registerPlugin(pluginObj); @@ -958,6 +959,8 @@ bool MainWindow::registerPlugin(QObject *plugin) } } + qDebug("no matching plugin interface"); + return addon; } @@ -1000,6 +1003,12 @@ IGameInfo &MainWindow::gameInfo() const } +IModRepositoryBridge *MainWindow::createNexusBridge() const +{ + return new NexusBridge(); +} + + QString MainWindow::profileName() const { if (m_CurrentProfile != NULL) { diff --git a/src/mainwindow.h b/src/mainwindow.h index e50a8c23..e398a674 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -94,6 +94,7 @@ public: void loadPlugins(); virtual MOBase::IGameInfo &gameInfo() const; + virtual MOBase::IModRepositoryBridge *createNexusBridge() const; virtual QString profileName() const; virtual QString profilePath() const; virtual QString downloadsPath() const; diff --git a/src/modinfo.cpp b/src/modinfo.cpp index d84a6aa0..2ac7182b 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -56,35 +56,6 @@ static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS) return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0; } -ModInfo::NexusFileInfo::NexusFileInfo(const QString &data) -{ - QVariantList result = QtJson::Json::parse(data).toList(); - - while (result.length() < 7) { - result.append(QVariant()); - } - id = result.at(0).toInt(); - name = result.at(1).toString(); - url = result.at(2).toString(); - version = result.at(3).toString(); - description = result.at(4).toString(); - category = result.at(5).toInt(); - size = result.at(6).toInt(); -} - - -QString ModInfo::NexusFileInfo::toString() const -{ - return QString("[ %1,\"%2\",\"%3\",\"%4\",\"%5\",%6,%7 ]") - .arg(id) - .arg(name) - .arg(url) - .arg(version) - .arg(description.mid(0).replace("\"", "'")) - .arg(category) - .arg(size); -} - ModInfo::Ptr ModInfo::createFrom(const QDir &dir, DirectoryEntry **directoryStructure) { @@ -356,7 +327,7 @@ ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStruc for (int i = 0; i < numNexusFiles; ++i) { metaFile.setArrayIndex(i); QString infoString = metaFile.value("info", "").toString(); - NexusFileInfo info(infoString); + ModRepositoryFileInfo *info = new ModRepositoryFileInfo(infoString, this); m_NexusFileInfos.push_back(info); } metaFile.endArray(); @@ -379,10 +350,10 @@ ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStruc } } - connect(&m_NexusBridge, SIGNAL(nxmDescriptionAvailable(int,QVariant,QVariant)), this, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant))); - connect(&m_NexusBridge, SIGNAL(nxmFilesAvailable(int,QVariant,QVariant)), this, SLOT(nxmFilesAvailable(int,QVariant,QVariant))); - connect(&m_NexusBridge, SIGNAL(nxmEndorsementToggled(int,QVariant,QVariant)), this, SLOT(nxmEndorsementToggled(int,QVariant,QVariant))); - connect(&m_NexusBridge, SIGNAL(nxmRequestFailed(int,QVariant,QString)), this, SLOT(nxmRequestFailed(int,QVariant,QString))); + connect(&m_NexusBridge, SIGNAL(descriptionAvailable(int,QVariant,QVariant)), this, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant))); + connect(&m_NexusBridge, SIGNAL(filesAvailable(int,QVariant,const QList&)), this, SLOT(nxmFilesAvailable(int,QVariant,QList))); + connect(&m_NexusBridge, SIGNAL(endorsementToggled(int,QVariant,QVariant)), this, SLOT(nxmEndorsementToggled(int,QVariant,QVariant))); + connect(&m_NexusBridge, SIGNAL(requestFailed(int,QVariant,QString)), this, SLOT(nxmRequestFailed(int,QVariant,QString))); } @@ -422,7 +393,7 @@ void ModInfoRegular::saveMeta() metaFile.beginWriteArray("nexusFiles"); for (int i = 0; i < m_NexusFileInfos.size(); ++i) { metaFile.setArrayIndex(i); - metaFile.setValue("info", m_NexusFileInfos.at(i).toString()); + metaFile.setValue("info", m_NexusFileInfos.at(i)->toString()); } metaFile.endArray(); } else { @@ -454,24 +425,9 @@ void ModInfoRegular::nxmDescriptionAvailable(int, QVariant, QVariant resultData) } -void ModInfoRegular::nxmFilesAvailable(int, QVariant, QVariant resultData) +void ModInfoRegular::nxmFilesAvailable(int, QVariant, const QList &resultData) { - m_NexusFileInfos.clear(); - - QVariantList result = resultData.toList(); - - foreach(QVariant file, result) { - QVariantMap fileInfo = file.toMap(); - - m_NexusFileInfos.push_back(NexusFileInfo(fileInfo["id"].toInt(), - fileInfo["name"].toString(), - fileInfo["uri"].toString(), - fileInfo["version"].toString(), - fileInfo["description"].toString(), - fileInfo["category_id"].toInt(), - fileInfo["size"].toInt())); - } - + m_NexusFileInfos = resultData; m_LastNexusQuery = QDateTime::currentDateTime(); m_MetaInfoChanged = true; saveMeta(); @@ -697,7 +653,7 @@ QString ModInfoRegular::notes() const return m_Notes; } -void ModInfoRegular::getNexusFiles(QList::const_iterator &begin, QList::const_iterator &end) +void ModInfoRegular::getNexusFiles(QList::const_iterator &begin, QList::const_iterator &end) { begin = m_NexusFileInfos.begin(); end = m_NexusFileInfos.end(); diff --git a/src/modinfo.h b/src/modinfo.h index adf194dd..92752e4b 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -35,6 +35,7 @@ along with Mod Organizer. If not, see . #include #include +using MOBase::ModRepositoryFileInfo; /** * @brief Represents meta information about a single mod. @@ -79,7 +80,7 @@ public: ENDORSED_UNKNOWN, ENDORSED_NEVER }; - +/* struct NexusFileInfo { NexusFileInfo(const QString &data); NexusFileInfo(int id, const QString &name, const QString &url, const QString &version, @@ -95,7 +96,7 @@ public: int size; QString toString() const; - }; + };*/ public: @@ -373,7 +374,8 @@ public: * @param begin iterator to the first file * @param end iterator to one past the last file */ - virtual void getNexusFiles(QList::const_iterator &begin, QList::const_iterator &end) = 0; + virtual void getNexusFiles(QList::const_iterator &begin, + QList::const_iterator &end) = 0; /** * @return nexus description of the mod (html) @@ -684,7 +686,7 @@ public: * @param begin iterator to the first file * @param end iterator to one past the last file */ - virtual void getNexusFiles(QList::const_iterator &begin, QList::const_iterator &end); + virtual void getNexusFiles(QList::const_iterator &begin, QList::const_iterator &end); /** * @return nexus description of the mod (html) @@ -719,7 +721,7 @@ private: private slots: void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData); - void nxmFilesAvailable(int, QVariant, QVariant resultData); + void nxmFilesAvailable(int, QVariant, const QList &resultData); void nxmEndorsementToggled(int, QVariant userData, QVariant resultData); void nxmRequestFailed(int modID, QVariant userData, const QString &errorMessage); @@ -746,7 +748,7 @@ private: QString m_InstallationFile; QString m_Notes; QString m_NexusDescription; - QList m_NexusFileInfos; + QList m_NexusFileInfos; QDateTime m_LastNexusQuery; @@ -782,7 +784,8 @@ public: virtual std::vector getFlags() const; virtual QString getDescription() const; virtual QDateTime getLastNexusQuery() const { return QDateTime(); } - virtual void getNexusFiles(QList::const_iterator&, QList::const_iterator&) {} + virtual void getNexusFiles(QList::const_iterator&, + QList::const_iterator&) {} virtual QString getNexusDescription() const { return QString(); } private: @@ -825,7 +828,8 @@ public: virtual int getHighlight() const; virtual QString getDescription() const; virtual QDateTime getLastNexusQuery() const { return QDateTime(); } - virtual void getNexusFiles(QList::const_iterator&, QList::const_iterator&) {} + virtual void getNexusFiles(QList::const_iterator&, + QList::const_iterator&) {} virtual QString getNexusDescription() const { return QString(); } private: diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 5d6f4a2b..d1c37263 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -781,20 +781,21 @@ void ModInfoDialog::modDetailsUpdated(bool success) // prevent sorting while we change the table filesWidget->setSortingEnabled(false); int row = 0; - QList::const_iterator current, end; + QList::const_iterator current, end; m_ModInfo->getNexusFiles(current, end); for (; current != end; ++current) { + ModRepositoryFileInfo *fileInfo = *current; filesWidget->insertRow(row); - int type = current->category; + int type = fileInfo->categoryID; filesWidget->setItem(row, 4, new QTableWidgetItem(QString("%1").arg(type))); filesWidget->setItem(row, 0, new QTableWidgetItem(getFileCategory(type))); - QTableWidgetItem *nameItem = new QTableWidgetItem(current->name); - nameItem->setToolTip(current->description); - nameItem->setData(Qt::UserRole, current->id); + QTableWidgetItem *nameItem = new QTableWidgetItem(fileInfo->name); + nameItem->setToolTip(fileInfo->description); + nameItem->setData(Qt::UserRole, fileInfo->fileID); filesWidget->setItem(row, 1, nameItem); - filesWidget->setItem(row, 2, new QTableWidgetItem(current->version)); + filesWidget->setItem(row, 2, new QTableWidgetItem(fileInfo->version.canonicalString())); QTableWidgetItem *sizeItem = new QTableWidgetItem(); - sizeItem->setData(Qt::DisplayRole, current->size); + sizeItem->setData(Qt::DisplayRole, fileInfo->fileSize); filesWidget->setItem(row, 3, sizeItem); ++row; } diff --git a/src/modlist.cpp b/src/modlist.cpp index 2183ce09..3fc8ae23 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -136,6 +136,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const QString version = modInfo->getVersion().canonicalString(); if (version.isEmpty() && modInfo->canBeUpdated()) { version = "?"; + } else if (version[0] == 'd') { + version.remove(0, 1); } return version; } else if (column == COL_PRIORITY) { @@ -228,10 +230,13 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } return result; } else if (role == Qt::DecorationRole) { - if ((column == COL_VERSION) && - modInfo->updateAvailable() && - modInfo->getNewestVersion().isValid()) { - return QIcon(":/MO/gui/update_available"); + if (column == COL_VERSION) { + if (modInfo->updateAvailable() && + modInfo->getNewestVersion().isValid()) { + return QIcon(":/MO/gui/update_available"); + } else if (modInfo->getVersion().isVersionDate()) { + return QIcon(":/MO/gui/version_date"); + } } return QVariant(); } else if (role == Qt::ForegroundRole) { diff --git a/src/nexusdialog.cpp b/src/nexusdialog.cpp index 6d8e850b..2569798e 100644 --- a/src/nexusdialog.cpp +++ b/src/nexusdialog.cpp @@ -168,7 +168,9 @@ void NexusDialog::loginFinished(bool necessary) void NexusDialog::loadNexus() { - m_View->load(QUrl(m_Url)); + if (m_View != NULL) { + m_View->load(QUrl(m_Url)); + } } diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index 49cf595e..56752ca5 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -32,34 +32,35 @@ using namespace MOShared; NexusBridge::NexusBridge() + : m_Interface(NexusInterface::instance()) + , m_Url(MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl())) { - m_Interface = NexusInterface::instance(); } -void NexusBridge::requestDescription(int modID, QVariant userData, const QString &url) +void NexusBridge::requestDescription(int modID, QVariant userData) { - m_RequestIDs.insert(m_Interface->requestDescription(modID, this, userData, url)); + m_RequestIDs.insert(m_Interface->requestDescription(modID, this, userData, m_Url)); } -void NexusBridge::requestFiles(int modID, QVariant userData, const QString &url) +void NexusBridge::requestFiles(int modID, QVariant userData) { - m_RequestIDs.insert(m_Interface->requestFiles(modID, this, userData, url)); + m_RequestIDs.insert(m_Interface->requestFiles(modID, this, userData, m_Url)); } -void NexusBridge::requestFileInfo(int modID, int fileID, QVariant userData, const QString &url) +void NexusBridge::requestFileInfo(int modID, int fileID, QVariant userData) { - m_RequestIDs.insert(m_Interface->requestFileInfo(modID, fileID, this, userData, url)); + m_RequestIDs.insert(m_Interface->requestFileInfo(modID, fileID, this, userData, m_Url)); } -void NexusBridge::requestDownloadURL(int modID, int fileID, QVariant userData, const QString &url) +void NexusBridge::requestDownloadURL(int modID, int fileID, QVariant userData) { - m_RequestIDs.insert(m_Interface->requestDownloadURL(modID, fileID, this, userData, url)); + m_RequestIDs.insert(m_Interface->requestDownloadURL(modID, fileID, this, userData, m_Url)); } -void NexusBridge::requestToggleEndorsement(int modID, bool endorse, QVariant userData, const QString &url) +void NexusBridge::requestToggleEndorsement(int modID, bool endorse, QVariant userData) { - m_RequestIDs.insert(m_Interface->requestToggleEndorsement(modID, endorse, this, userData, url)); + m_RequestIDs.insert(m_Interface->requestToggleEndorsement(modID, endorse, this, userData, m_Url)); } void NexusBridge::nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData, int requestID) @@ -67,7 +68,7 @@ void NexusBridge::nxmDescriptionAvailable(int modID, QVariant userData, QVariant std::set::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { m_RequestIDs.erase(iter); - emit nxmDescriptionAvailable(modID, userData, resultData); + emit descriptionAvailable(modID, userData, resultData); } } @@ -76,7 +77,26 @@ void NexusBridge::nxmFilesAvailable(int modID, QVariant userData, QVariant resul std::set::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { m_RequestIDs.erase(iter); - emit nxmFilesAvailable(modID, userData, resultData); + + QList fileInfoList; + + QVariantList resultList = resultData.toList(); + + foreach(QVariant file, resultList) { + ModRepositoryFileInfo *temp = new ModRepositoryFileInfo(NULL); + QVariantMap fileInfo = file.toMap(); + temp->uri = fileInfo["uri"].toString(); + temp->name = fileInfo["name"].toString(); + temp->description = fileInfo["description"].toString(); + temp->version = VersionInfo(fileInfo["version"].toString()); + temp->categoryID = fileInfo["category_id"].toInt(); + temp->fileID = fileInfo["id"].toInt(); + temp->fileSize = fileInfo["size"].toInt(); + fileInfoList.append(temp); + } + + emit bla(userData.toString()); + emit filesAvailable(modID, userData, fileInfoList); } } @@ -85,7 +105,7 @@ void NexusBridge::nxmFileInfoAvailable(int modID, int fileID, QVariant userData, std::set::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { m_RequestIDs.erase(iter); - emit nxmFileInfoAvailable(modID, fileID, userData, resultData); + emit fileInfoAvailable(modID, fileID, userData, resultData); } } @@ -94,7 +114,7 @@ void NexusBridge::nxmDownloadURLsAvailable(int modID, int fileID, QVariant userD std::set::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { m_RequestIDs.erase(iter); - emit nxmDownloadURLsAvailable(modID, fileID, userData, resultData); + //emit downloadURLsAvailable(modID, fileID, userData, resultData); } } @@ -103,7 +123,7 @@ void NexusBridge::nxmEndorsementToggled(int modID, QVariant userData, QVariant r std::set::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { m_RequestIDs.erase(iter); - emit nxmEndorsementToggled(modID, userData, resultData); + //emit endorsementToggled(modID, userData, resultData); } } @@ -112,7 +132,7 @@ void NexusBridge::nxmRequestFailed(int modID, QVariant userData, int requestID, std::set::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { m_RequestIDs.erase(iter); - emit nxmRequestFailed(modID, userData, errorMessage); + //emit requestFailed(modID, userData, errorMessage); } } diff --git a/src/nexusinterface.h b/src/nexusinterface.h index cca84e06..cb455e93 100644 --- a/src/nexusinterface.h +++ b/src/nexusinterface.h @@ -26,6 +26,7 @@ along with Mod Organizer. If not, see . #include "utility.h" #include #include +#include #include #include #include @@ -46,7 +47,7 @@ class NexusInterface; * NexusBridge does this automatically. Users connect to the signals of NexusBridge they intend * to handle and only receive the signals the caused **/ -class NexusBridge : public QObject +class NexusBridge : public MOBase::IModRepositoryBridge { Q_OBJECT @@ -62,18 +63,15 @@ public: * @param userData user data to be returned with the result * @param url the url to request from **/ - void requestDescription(int modID, QVariant userData, - const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl())); + virtual void requestDescription(int modID, QVariant userData); /** * @brief request a list of the files belonging to a mod * * @param modID id of the mod caller is interested in * @param userData user data to be returned with the result - * @param url the url to request from **/ - void requestFiles(int modID, QVariant userData, - const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl())); + virtual void requestFiles(int modID, QVariant userData); /** * @brief request info about a single file of a mod @@ -81,10 +79,8 @@ public: * @param modID id of the mod caller is interested in * @param fileID id of the file the caller is interested in * @param userData user data to be returned with the result - * @param url the url to request from **/ - void requestFileInfo(int modID, int fileID, QVariant userData, - const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl())); + virtual void requestFileInfo(int modID, int fileID, QVariant userData); /** * @brief request the download url of a file @@ -92,28 +88,28 @@ public: * @param modID id of the mod caller is interested in * @param fileID id of the file the caller is interested in * @param userData user data to be returned with the result - * @param url the url to request from **/ - void requestDownloadURL(int modID, int fileID, QVariant userData, - const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl())); + virtual void requestDownloadURL(int modID, int fileID, QVariant userData); /** * @brief requestToggleEndorsement - * @param modID - * @param userData - * @param url + * @param modID id of the mod caller is interested in + * @param userData user data to be returned with the result */ - void requestToggleEndorsement(int modID, bool endorse, QVariant userData, - const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl())); + virtual void requestToggleEndorsement(int modID, bool endorse, QVariant userData); +/* +signals: + + void descriptionAvailable(int modID, QVariant userData, QVariant resultData); + void filesAvailable(int modID, QVariant userData, const QList &resultData); + void fileInfoAvailable(int modID, int fileID, QVariant userData, QVariant resultData); + void downloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData); + void endorsementToggled(int modID, QVariant userData, QVariant resultData); + void requestFailed(int modID, QVariant userData, const QString &errorMessage);*/ signals: - void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData); - void nxmFilesAvailable(int modID, QVariant userData, QVariant resultData); - void nxmFileInfoAvailable(int modID, int fileID, QVariant userData, QVariant resultData); - void nxmDownloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData); - void nxmEndorsementToggled(int modID, QVariant userData, QVariant resultData); - void nxmRequestFailed(int modID, QVariant userData, const QString &errorMessage); + void bla(QString userData); public slots: @@ -127,6 +123,7 @@ public slots: private: NexusInterface *m_Interface; + QString m_Url; std::set m_RequestIDs; }; diff --git a/src/organizer.pro b/src/organizer.pro index cfdf990b..c4a829cf 100644 --- a/src/organizer.pro +++ b/src/organizer.pro @@ -195,6 +195,7 @@ CONFIG(debug, debug|release) { LIBS += -L$$OUT_PWD/../shared/release -L$$OUT_PWD/../bsatk/release LIBS += -L$$OUT_PWD/../uibase/release QMAKE_CXXFLAGS += /Zi + QMAKE_CXXFLAGS -= -O2 QMAKE_LFLAGS += /DEBUG } diff --git a/src/resources.qrc b/src/resources.qrc index 855a23fc..df17ea79 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -50,5 +50,6 @@ resources/conflict-overwritten.png resources/conflict-redundant.png resources/accessories-text-editor.png + resources/x-office-calendar.png diff --git a/src/resources/x-office-calendar.png b/src/resources/x-office-calendar.png new file mode 100644 index 00000000..f6978d7d Binary files /dev/null and b/src/resources/x-office-calendar.png differ diff --git a/src/version.rc b/src/version.rc index 3b2c4804..9921149a 100644 --- a/src/version.rc +++ b/src/version.rc @@ -1,7 +1,7 @@ #include "Winver.h" -#define VER_FILEVERSION 0,13,0,0 -#define VER_FILEVERSION_STR 0,13,0,0 +#define VER_FILEVERSION 0,99,0,0 +#define VER_FILEVERSION_STR 0,99,0,0 VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION -- cgit v1.3.1