diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ec306e5a..625239aa0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -167,6 +167,7 @@ if(USE_SYSTEM_TINYXML) find_library(TINYXML_LIBRARIES tinyxml) find_path(TINYXML_INCLUDE_DIR tinyxml.h) message(STATUS "Found TinyXML: ${TINYXML_LIBRARIES} ${TINYXML_INCLUDE_DIR}") + add_definitions (-DTIXML_USE_STL) if(TINYXML_LIBRARIES AND TINYXML_INCLUDE_DIR) include_directories(${TINYXML_INCLUDE_DIR}) message(STATUS "Using system TinyXML library.") diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index a60e9f0e2..6ccf9c3f3 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -305,14 +305,14 @@ int load(Arguments& info) info.data.author = esm.getAuthor(); info.data.description = esm.getDesc(); - info.data.masters = esm.getMasters(); + info.data.masters = esm.getGameFiles(); if (!quiet) { std::cout << "Author: " << esm.getAuthor() << std::endl << "Description: " << esm.getDesc() << std::endl << "File format version: " << esm.getFVer() << std::endl; - std::vector m = esm.getMasters(); + std::vector m = esm.getGameFiles(); if (!m.empty()) { std::cout << "Masters:" << std::endl; diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index add3dea40..44392794b 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -4,141 +4,146 @@ #include #include #include +#include #include -#include -#include -#include +#include -#include -#include -#include +#include +#include +#include #include "settings/gamesettings.hpp" #include "settings/launchersettings.hpp" #include "utils/textinputdialog.hpp" +#include "components/contentselector/view/contentselector.hpp" +#include "components/contentselector/model/contentmodel.hpp" + +#include DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent) : mCfgMgr(cfg) , mGameSettings(gameSettings) , mLauncherSettings(launcherSettings) - , QWidget(parent) { setupUi(this); + // mContentSelector.setParent(parent); - // Models - mDataFilesModel = new DataFilesModel(this); + // QMetaObject::connectSlotsByName(this); - mMastersProxyModel = new QSortFilterProxyModel(); - mMastersProxyModel->setFilterRegExp(QString("^.*\\.esm")); - mMastersProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - mMastersProxyModel->setSourceModel(mDataFilesModel); - - mPluginsProxyModel = new PluginsProxyModel(); - mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp")); - mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - mPluginsProxyModel->setSourceModel(mDataFilesModel); - - mFilterProxyModel = new QSortFilterProxyModel(); - mFilterProxyModel->setDynamicSortFilter(true); - mFilterProxyModel->setSourceModel(mPluginsProxyModel); - - QCheckBox checkBox; - unsigned int height = checkBox.sizeHint().height() + 4; - - mastersTable->setModel(mMastersProxyModel); - mastersTable->setObjectName("MastersTable"); - mastersTable->setContextMenuPolicy(Qt::CustomContextMenu); - mastersTable->setSortingEnabled(false); - mastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection); - mastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - mastersTable->setAlternatingRowColors(true); - mastersTable->horizontalHeader()->setStretchLastSection(true); - mastersTable->horizontalHeader()->hide(); - - // Set the row height to the size of the checkboxes - mastersTable->verticalHeader()->setDefaultSectionSize(height); - mastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - mastersTable->verticalHeader()->hide(); - - pluginsTable->setModel(mFilterProxyModel); - pluginsTable->setObjectName("PluginsTable"); - pluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); - pluginsTable->setSortingEnabled(false); - pluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); - pluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection); - pluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - pluginsTable->setAlternatingRowColors(true); - pluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); - pluginsTable->horizontalHeader()->setStretchLastSection(true); - pluginsTable->horizontalHeader()->hide(); - - pluginsTable->verticalHeader()->setDefaultSectionSize(height); - pluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - - // Adjust the tableview widths inside the splitter - QList sizeList; - sizeList << mLauncherSettings.value(QString("General/MastersTable/width"), QString("200")).toInt(); - sizeList << mLauncherSettings.value(QString("General/PluginTable/width"), QString("340")).toInt(); - - splitter->setSizes(sizeList); + projectGroupBox->hide(); // Create a dialog for the new profile name input mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); - connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int))); - connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); - connect(pluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - connect(mastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - connect(pluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); - connect(mastersTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); - connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); + buildContentModel(); + buildGameFileView(); + buildAddonView(); + buildProfilesView(); - connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); - - connect(splitter, SIGNAL(splitterMoved(int,int)), this, SLOT(updateSplitter())); createActions(); setupDataFiles(); + + + updateViews(); +} + +void DataFilesPage::buildContentModel() +{ + mContentModel = new ContentSelectorModel::ContentModel(); + connect(mContentModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); +} + +void DataFilesPage::buildGameFileView() +{ + mGameFileProxyModel = new QSortFilterProxyModel(this); + mGameFileProxyModel->setFilterRegExp(QString::number((int)ContentSelectorModel::ContentType_GameFile)); + mGameFileProxyModel->setFilterRole (Qt::UserRole); + mGameFileProxyModel->setSourceModel (mContentModel); + + gameFileView->setPlaceholderText(QString("Select a game file...")); + gameFileView->setModel(mGameFileProxyModel); + + connect(gameFileView, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentGameFileIndexChanged(int))); + + gameFileView->setCurrentIndex(-1); + gameFileView->setCurrentIndex(0); +} + +void DataFilesPage::buildAddonView() +{ + mAddonProxyModel = new QSortFilterProxyModel(this); + mAddonProxyModel->setFilterRegExp (QString::number((int)ContentSelectorModel::ContentType_Addon)); + mAddonProxyModel->setFilterRole (Qt::UserRole); + mAddonProxyModel->setDynamicSortFilter (true); + mAddonProxyModel->setSourceModel (mContentModel); + + addonView->setModel(mAddonProxyModel); + + connect(addonView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(slotAddonTableItemClicked(const QModelIndex &))); +} + +void DataFilesPage::buildProfilesView() +{ + profilesComboBox->setPlaceholderText(QString("Select a profile...")); + connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentProfileIndexChanged(int))); +} + +void DataFilesPage::updateViews() +{ + // Ensure the columns are hidden because sort() re-enables them + addonView->setColumnHidden(1, true); + addonView->setColumnHidden(2, true); + addonView->setColumnHidden(3, true); + addonView->setColumnHidden(4, true); + addonView->setColumnHidden(5, true); + addonView->setColumnHidden(6, true); + addonView->setColumnHidden(7, true); + addonView->setColumnHidden(8, true); + addonView->resizeColumnsToContents(); +} + +void ContentSelectorView::ContentSelector::addFiles(const QString &path) +{ + mContentModel->addFiles(path); + //mContentModel->sort(3); // Sort by date accessed + gameFileView->setCurrentIndex(-1); + mContentModel->uncheckAll(); } void DataFilesPage::createActions() { - // Add the actions to the toolbuttons newProfileButton->setDefaultAction(newProfileAction); deleteProfileButton->setDefaultAction(deleteProfileAction); - - // Context menu actions - mContextMenu = new QMenu(this); - mContextMenu->addAction(checkAction); - mContextMenu->addAction(uncheckAction); } void DataFilesPage::setupDataFiles() { // Set the encoding to the one found in openmw.cfg or the default - mDataFilesModel->setEncoding(mGameSettings.value(QString("encoding"), QString("win1252"))); + //mContentSelector.setEncoding(mGameSettings.value(QString("encoding"), QString("win1252"))); QStringList paths = mGameSettings.getDataDirs(); foreach (const QString &path, paths) { - mDataFilesModel->addFiles(path); + //mContentSelector. + mContentModel->addFiles(path); } QString dataLocal = mGameSettings.getDataLocal(); if (!dataLocal.isEmpty()) - mDataFilesModel->addFiles(dataLocal); + //mContentSelector. + mContentModel->addFiles(dataLocal); // Sort by date accessed for now - mDataFilesModel->sort(3); + //mContentSelector->sort(3); QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/")); QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); @@ -168,6 +173,7 @@ void DataFilesPage::setupDataFiles() loadSettings(); + gameFileView->setCurrentIndex(-1); } void DataFilesPage::loadSettings() @@ -177,27 +183,16 @@ void DataFilesPage::loadSettings() if (profile.isEmpty()) return; - mDataFilesModel->uncheckAll(); + // mContentSelector. + mContentModel->uncheckAll(); - QStringList masters = mLauncherSettings.values(QString("Profiles/") + profile + QString("/master"), Qt::MatchExactly); - QStringList plugins = mLauncherSettings.values(QString("Profiles/") + profile + QString("/plugin"), Qt::MatchExactly); - - foreach (const QString &master, masters) { - QModelIndex index = mDataFilesModel->indexFromItem(mDataFilesModel->findItem(master)); - if (index.isValid()) - mDataFilesModel->setCheckState(index, Qt::Checked); - } - - foreach (const QString &plugin, plugins) { - QModelIndex index = mDataFilesModel->indexFromItem(mDataFilesModel->findItem(plugin)); - if (index.isValid()) - mDataFilesModel->setCheckState(index, Qt::Checked); - } + QStringList gameFiles = mLauncherSettings.values(QString("Profiles/") + profile + QString("/master"), Qt::MatchExactly); + QStringList addons = mLauncherSettings.values(QString("Profiles/") + profile + QString("/plugin"), Qt::MatchExactly); } void DataFilesPage::saveSettings() { - if (mDataFilesModel->rowCount() < 1) + if (mContentModel->rowCount() < 1) return; QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); @@ -213,17 +208,17 @@ void DataFilesPage::saveSettings() mGameSettings.remove(QString("master")); mGameSettings.remove(QString("plugin")); - QStringList items = mDataFilesModel->checkedItems(); + ContentSelectorModel::ContentFileList items = mContentModel->checkedItems(); - foreach(const QString &item, items) { + foreach(const ContentSelectorModel::EsmFile *item, items) { - if (item.endsWith(QString(".esm"), Qt::CaseInsensitive)) { - mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), item); - mGameSettings.setMultiValue(QString("master"), item); + if (item->gameFiles().size() == 0) { + mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), item->fileName()); + mGameSettings.setMultiValue(QString("master"), item->fileName()); - } else if (item.endsWith(QString(".esp"), Qt::CaseInsensitive)) { - mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/plugin"), item); - mGameSettings.setMultiValue(QString("plugin"), item); + } else { + mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/plugin"), item->fileName()); + mGameSettings.setMultiValue(QString("plugin"), item->fileName()); } } @@ -242,48 +237,11 @@ void DataFilesPage::updateOkButton(const QString &text) : mNewProfileDialog->setOkButtonEnabled(false); } -void DataFilesPage::updateSplitter() -{ - // Sigh, update the saved splitter size in settings only when moved - // Since getting mSplitter->sizes() if page is hidden returns invalid values - QList sizes = splitter->sizes(); - - mLauncherSettings.setValue(QString("General/MastersTable/width"), QString::number(sizes.at(0))); - mLauncherSettings.setValue(QString("General/PluginsTable/width"), QString::number(sizes.at(1))); -} - -void DataFilesPage::updateViews() -{ - // Ensure the columns are hidden because sort() re-enables them - mastersTable->setColumnHidden(1, true); - mastersTable->setColumnHidden(2, true); - mastersTable->setColumnHidden(3, true); - mastersTable->setColumnHidden(4, true); - mastersTable->setColumnHidden(5, true); - mastersTable->setColumnHidden(6, true); - mastersTable->setColumnHidden(7, true); - mastersTable->setColumnHidden(8, true); - - pluginsTable->setColumnHidden(1, true); - pluginsTable->setColumnHidden(2, true); - pluginsTable->setColumnHidden(3, true); - pluginsTable->setColumnHidden(4, true); - pluginsTable->setColumnHidden(5, true); - pluginsTable->setColumnHidden(6, true); - pluginsTable->setColumnHidden(7, true); - pluginsTable->setColumnHidden(8, true); -} - void DataFilesPage::setProfilesComboBoxIndex(int index) { profilesComboBox->setCurrentIndex(index); } -void DataFilesPage::slotCurrentIndexChanged(int index) -{ - emit profileChanged(index); -} - QAbstractItemModel* DataFilesPage::profilesComboBoxModel() { return profilesComboBox->model(); @@ -330,112 +288,30 @@ void DataFilesPage::on_deleteProfileAction_triggered() } } -void DataFilesPage::on_checkAction_triggered() -{ - if (pluginsTable->hasFocus()) - setPluginsCheckstates(Qt::Checked); - - if (mastersTable->hasFocus()) - setMastersCheckstates(Qt::Checked); - -} - -void DataFilesPage::on_uncheckAction_triggered() -{ - if (pluginsTable->hasFocus()) - setPluginsCheckstates(Qt::Unchecked); - - if (mastersTable->hasFocus()) - setMastersCheckstates(Qt::Unchecked); -} - -void DataFilesPage::setMastersCheckstates(Qt::CheckState state) -{ - if (!mastersTable->selectionModel()->hasSelection()) { - return; - } - - QModelIndexList indexes = mastersTable->selectionModel()->selectedIndexes(); - - foreach (const QModelIndex &index, indexes) - { - if (!index.isValid()) - return; - - QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index); - - if (!sourceIndex.isValid()) - return; - - mDataFilesModel->setCheckState(sourceIndex, state); - } -} - void DataFilesPage::setPluginsCheckstates(Qt::CheckState state) { - if (!pluginsTable->selectionModel()->hasSelection()) { + if (!addonView->selectionModel()->hasSelection()) { return; } - QModelIndexList indexes = pluginsTable->selectionModel()->selectedIndexes(); + QModelIndexList indexes = addonView->selectionModel()->selectedIndexes(); foreach (const QModelIndex &index, indexes) { if (!index.isValid()) return; - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( - mFilterProxyModel->mapToSource(index)); + QModelIndex sourceIndex = mAddonProxyModel->mapToSource(index); if (!sourceIndex.isValid()) return; - mDataFilesModel->setCheckState(sourceIndex, state); + //bool isChecked = ( state == Qt::Checked ); + + mContentModel->setData(sourceIndex, state, Qt::CheckStateRole); } } -void DataFilesPage::setCheckState(QModelIndex index) -{ - if (!index.isValid()) - return; - - QObject *object = QObject::sender(); - - // Not a signal-slot call - if (!object) - return; - - - if (object->objectName() == QLatin1String("PluginsTable")) { - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( - mFilterProxyModel->mapToSource(index)); - - if (sourceIndex.isValid()) { - (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) - ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked) - : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); - } - } - - if (object->objectName() == QLatin1String("MastersTable")) { - QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index); - - if (sourceIndex.isValid()) { - (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) - ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked) - : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); - } - } - - return; -} - -void DataFilesPage::filterChanged(const QString filter) -{ - QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString); - mFilterProxyModel->setFilterRegExp(regExp); -} - void DataFilesPage::profileChanged(const QString &previous, const QString ¤t) { // Prevent the deletion of the default profile @@ -480,72 +356,51 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre loadSettings(); } +//////////////////////////// -void DataFilesPage::showContextMenu(const QPoint &point) +QStringList DataFilesPage::checkedItemsPaths() { - QObject *object = QObject::sender(); + QStringList itemPaths; - // Not a signal-slot call - if (!object) - return; + foreach( const ContentSelectorModel::EsmFile *file, mContentModel->checkedItems()) + itemPaths << file->path(); - if (object->objectName() == QLatin1String("PluginsTable")) { - if (!pluginsTable->selectionModel()->hasSelection()) - return; - - QPoint globalPos = pluginsTable->mapToGlobal(point); - QModelIndexList indexes = pluginsTable->selectionModel()->selectedIndexes(); - - // Show the check/uncheck actions depending on the state of the selected items - uncheckAction->setEnabled(false); - checkAction->setEnabled(false); - - foreach (const QModelIndex &index, indexes) - { - if (!index.isValid()) - return; - - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( - mFilterProxyModel->mapToSource(index)); - - if (!sourceIndex.isValid()) - return; - - (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) - ? uncheckAction->setEnabled(true) - : checkAction->setEnabled(true); - } - - // Show menu - mContextMenu->exec(globalPos); - } - - if (object->objectName() == QLatin1String("MastersTable")) { - if (!mastersTable->selectionModel()->hasSelection()) - return; - - QPoint globalPos = mastersTable->mapToGlobal(point); - QModelIndexList indexes = mastersTable->selectionModel()->selectedIndexes(); - - // Show the check/uncheck actions depending on the state of the selected items - uncheckAction->setEnabled(false); - checkAction->setEnabled(false); - - foreach (const QModelIndex &index, indexes) - { - if (!index.isValid()) - return; - - QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index); - - if (!sourceIndex.isValid()) - return; - - (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) - ? uncheckAction->setEnabled(true) - : checkAction->setEnabled(true); - } - - mContextMenu->exec(globalPos); - } + return itemPaths; +} + +void DataFilesPage::slotCurrentProfileIndexChanged(int index) +{ + emit profileChanged(index); +} + +void DataFilesPage::slotCurrentGameFileIndexChanged(int index) +{ + static int oldIndex = -1; + + QAbstractItemModel *const model = gameFileView->model(); + QSortFilterProxyModel *proxy = dynamic_cast(model); + + if (proxy) + proxy->setDynamicSortFilter(false); + + if (oldIndex > -1) + model->setData(model->index(oldIndex, 0), false, Qt::UserRole + 1); + + oldIndex = index; + + model->setData(model->index(index, 0), true, Qt::UserRole + 1); + + if (proxy) + proxy->setDynamicSortFilter(true); +} + +void DataFilesPage::slotAddonTableItemClicked(const QModelIndex &index) +{ + QAbstractItemModel *const model = addonView->model(); + //QSortFilterProxyModel *proxy = dynamic_cast(model); + + if (model->data(index, Qt::CheckStateRole).toInt() == Qt::Unchecked) + model->setData(index, Qt::Checked, Qt::CheckStateRole); + else + model->setData(index, Qt::Unchecked, Qt::CheckStateRole); } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index a0b029330..9c7b0538e 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -5,17 +5,17 @@ #include #include "ui_datafilespage.h" +#include "components/contentselector/view/contentselector.hpp" class QSortFilterProxyModel; class QAbstractItemModel; class QAction; class QMenu; -class DataFilesModel; class TextInputDialog; class GameSettings; class LauncherSettings; -class PluginsProxyModel; + namespace Files { struct ConfigurationManager; } @@ -36,44 +36,33 @@ signals: void profileChanged(int index); public slots: - void setCheckState(QModelIndex index); void setProfilesComboBoxIndex(int index); - void filterChanged(const QString filter); - void showContextMenu(const QPoint &point); + //void showContextMenu(const QPoint &point); void profileChanged(const QString &previous, const QString ¤t); void profileRenamed(const QString &previous, const QString ¤t); void updateOkButton(const QString &text); - void updateSplitter(); void updateViews(); - // Action slots void on_newProfileAction_triggered(); void on_deleteProfileAction_triggered(); - void on_checkAction_triggered(); - void on_uncheckAction_triggered(); private slots: - void slotCurrentIndexChanged(int index); private: - DataFilesModel *mDataFilesModel; - - PluginsProxyModel *mPluginsProxyModel; - QSortFilterProxyModel *mMastersProxyModel; - - QSortFilterProxyModel *mFilterProxyModel; QMenu *mContextMenu; - + //ContentSelectorView::ContentSelector mContentSelector; + ContentSelectorModel::ContentModel *mContentModel; Files::ConfigurationManager &mCfgMgr; GameSettings &mGameSettings; LauncherSettings &mLauncherSettings; TextInputDialog *mNewProfileDialog; + QSortFilterProxyModel *mGameFileProxyModel; + QSortFilterProxyModel *mAddonProxyModel; - void setMastersCheckstates(Qt::CheckState state); void setPluginsCheckstates(Qt::CheckState state); void createActions(); @@ -83,6 +72,22 @@ private: void loadSettings(); + ////////////////////////////////////// + void buildContentModel(); + void buildGameFileView(); + void buildAddonView(); + void buildProfilesView(); + + //void addFiles(const QString &path); + + QStringList checkedItemsPaths(); + +private slots: + void slotCurrentProfileIndexChanged(int index); + void slotCurrentGameFileIndexChanged(int index); + void slotAddonTableItemClicked(const QModelIndex &index); + + }; #endif diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 9308c1d57..4d9ce14d6 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include "settings/graphicssettings.hpp" diff --git a/apps/launcher/utils/textinputdialog.cpp b/apps/launcher/utils/textinputdialog.cpp index a4b36b95e..51928c09a 100644 --- a/apps/launcher/utils/textinputdialog.cpp +++ b/apps/launcher/utils/textinputdialog.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWidget *parent) : QDialog(parent) @@ -19,7 +19,7 @@ TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWid // Line edit QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore - mLineEdit = new LineEdit(this); + mLineEdit = new ContentSelectorView::LineEdit(this); mLineEdit->setValidator(validator); mLineEdit->setCompleter(0); diff --git a/apps/launcher/utils/textinputdialog.hpp b/apps/launcher/utils/textinputdialog.hpp index cbb453ac8..de3a9fb72 100644 --- a/apps/launcher/utils/textinputdialog.hpp +++ b/apps/launcher/utils/textinputdialog.hpp @@ -2,20 +2,23 @@ #define TEXTINPUTDIALOG_HPP #include -//#include "lineedit.hpp" class QDialogButtonBox; -class LineEdit; + +namespace ContentSelectorView { + class LineEdit; +} + class TextInputDialog : public QDialog { Q_OBJECT public: explicit TextInputDialog(const QString& title, const QString &text, QWidget *parent = 0); - inline LineEdit *lineEdit() { return mLineEdit; } + inline ContentSelectorView::LineEdit *lineEdit() { return mLineEdit; } void setOkButtonEnabled(bool enabled); - LineEdit *mLineEdit; + ContentSelectorView::LineEdit *mLineEdit; int exec(); diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index b6de9295d..88167aff3 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -18,12 +18,12 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world - idtable idtableproxymodel regionmap + idtable idtableproxymodel regionmap data ) opencs_units_noqt (model/world - universalid data record commands columnbase scriptcontext cell refidcollection + universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns ) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 9a6832ec0..ba1dfb57e 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -79,8 +79,8 @@ void CS::Editor::setupDataFiles() } // Set the charset for reading the esm/esp files - QString encoding = QString::fromStdString(variables["encoding"].as()); - mFileDialog.setEncoding(encoding); + // QString encoding = QString::fromStdString(variables["encoding"].as()); + //mFileDialog.setEncoding(encoding); dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end()); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index c83b2a685..248ebf2c5 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -32,7 +32,7 @@ namespace CS CSVDoc::StartupDialogue mStartup; CSVDoc::NewGameDialogue mNewGame; CSVSettings::UserSettingsDialog mSettings; - FileDialog mFileDialog; + CSVDoc::FileDialog mFileDialog; Files::ConfigurationManager mCfgMgr; boost::filesystem::path mLocal; diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index ef7123c20..e5e7514ce 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) if(!editor.makeIPCServer()) { editor.connectToIPCServer(); - return 0; + // return 0; } return editor.run(); diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 6cf31d0a4..84a00cef8 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -107,6 +107,11 @@ namespace CSMWorld virtual int getAppendIndex (UniversalId::Type type = UniversalId::Type_None) const; ///< \param type Will be ignored, unless the collection supports multiple record types + virtual std::vector getIds (bool listDeleted = true) const; + ///< Return a sorted collection of all IDs + /// + /// \param listDeleted include deleted record in the list + void addColumn (Column *column); void setRecord (int index, const Record& record); @@ -293,6 +298,21 @@ namespace CSMWorld return static_cast (mRecords.size()); } + template + std::vector Collection::getIds (bool listDeleted) const + { + std::vector ids; + + for (typename std::map::const_iterator iter = mIndex.begin(); + iter!=mIndex.end(); ++iter) + { + if (listDeleted || !mRecords[iter->second].isDeleted()) + ids.push_back (IdAccessorT().getId (mRecords[iter->second].get())); + } + + return ids; + } + template const Record& Collection::getRecord (const std::string& id) const { diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 1700a68ec..ff6dab247 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -78,8 +78,12 @@ namespace CSMWorld virtual int getAppendIndex (UniversalId::Type type = UniversalId::Type_None) const = 0; ///< \param type Will be ignored, unless the collection supports multiple record types - }; + virtual std::vector getIds (bool listDeleted = true) const = 0; + ///< Return a sorted collection of all IDs + /// + /// \param listDeleted include deleted record in the list + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fbdbb4413..7eb96a5c3 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -2,6 +2,7 @@ #include "data.hpp" #include +#include #include @@ -15,13 +16,31 @@ #include "columns.hpp" void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type1, - UniversalId::Type type2) + UniversalId::Type type2, bool update) { mModels.push_back (model); mModelIndex.insert (std::make_pair (type1, model)); if (type2!=UniversalId::Type_None) mModelIndex.insert (std::make_pair (type2, model)); + + if (update) + { + connect (model, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), + this, SLOT (dataChanged (const QModelIndex&, const QModelIndex&))); + connect (model, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + this, SLOT (rowsChanged (const QModelIndex&, int, int))); + connect (model, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), + this, SLOT (rowsChanged (const QModelIndex&, int, int))); + } +} + +void CSMWorld::Data::appendIds (std::vector& ids, const CollectionBase& collection, + bool listDeleted) +{ + std::vector ids2 = collection.getIds (listDeleted); + + ids.insert (ids.end(), ids2.begin(), ids2.end()); } CSMWorld::Data::Data() : mRefs (mCells) @@ -155,7 +174,7 @@ CSMWorld::Data::Data() : mRefs (mCells) addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); - addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); + addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill, false); addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); @@ -167,8 +186,8 @@ CSMWorld::Data::Data() : mRefs (mCells) addModel (new IdTable (&mCells), UniversalId::Type_Cells, UniversalId::Type_Cell); addModel (new IdTable (&mReferenceables), UniversalId::Type_Referenceables, UniversalId::Type_Referenceable); - addModel (new IdTable (&mRefs), UniversalId::Type_References, UniversalId::Type_Reference); - addModel (new IdTable (&mFilters), UniversalId::Type_Filters, UniversalId::Type_Filter); + addModel (new IdTable (&mRefs), UniversalId::Type_References, UniversalId::Type_Reference, false); + addModel (new IdTable (&mFilters), UniversalId::Type_Filters, UniversalId::Type_Filter, false); } CSMWorld::Data::~Data() @@ -341,7 +360,7 @@ QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { RegionMap *table = 0; addModel (table = new RegionMap (*this), UniversalId::Type_RegionMap, - UniversalId::Type_None); + UniversalId::Type_None, false); return table; } throw std::logic_error ("No table model available for " + id.toString()); @@ -440,3 +459,36 @@ bool CSMWorld::Data::hasId (const std::string& id) const getCells().searchId (id)!=-1 || getReferenceables().searchId (id)!=-1; } + +std::vector CSMWorld::Data::getIds (bool listDeleted) const +{ + std::vector ids; + + appendIds (ids, mGlobals, listDeleted); + appendIds (ids, mGmsts, listDeleted); + appendIds (ids, mClasses, listDeleted); + appendIds (ids, mFactions, listDeleted); + appendIds (ids, mRaces, listDeleted); + appendIds (ids, mSounds, listDeleted); + appendIds (ids, mScripts, listDeleted); + appendIds (ids, mRegions, listDeleted); + appendIds (ids, mBirthsigns, listDeleted); + appendIds (ids, mSpells, listDeleted); + appendIds (ids, mCells, listDeleted); + appendIds (ids, mReferenceables, listDeleted); + + std::sort (ids.begin(), ids.end()); + + return ids; +} + +void CSMWorld::Data::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + if (topLeft.column()<=0) + emit idListChanged(); +} + +void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end) +{ + emit idListChanged(); +} \ No newline at end of file diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 2f8a2117e..e900bb10f 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -6,6 +6,9 @@ #include +#include +#include + #include #include #include @@ -30,8 +33,10 @@ class QAbstractItemModel; namespace CSMWorld { - class Data + class Data : public QObject { + Q_OBJECT + IdCollection mGlobals; IdCollection mGmsts; IdCollection mSkills; @@ -55,13 +60,17 @@ namespace CSMWorld Data& operator= (const Data&); void addModel (QAbstractItemModel *model, UniversalId::Type type1, - UniversalId::Type type2 = UniversalId::Type_None); + UniversalId::Type type2 = UniversalId::Type_None, bool update = true); + + static void appendIds (std::vector& ids, const CollectionBase& collection, + bool listDeleted); + ///< Append all IDs from collection to \a ids. public: Data(); - ~Data(); + virtual ~Data(); const IdCollection& getGlobals() const; @@ -136,6 +145,21 @@ namespace CSMWorld ///< Merging content of a file into base or modified. bool hasId (const std::string& id) const; + + std::vector getIds (bool listDeleted = true) const; + ///< Return a sorted collection of all IDs that are not internal to the editor. + /// + /// \param listDeleted include deleted record in the list + + signals: + + void idListChanged(); + + private slots: + + void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + void rowsChanged (const QModelIndex& parent, int start, int end); }; } diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 343cbe302..cda2711cc 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -534,3 +534,8 @@ int CSMWorld::RefIdCollection::getAppendIndex (UniversalId::Type type) const { return mData.getAppendIndex (type); } + +std::vector CSMWorld::RefIdCollection::getIds (bool listDeleted) const +{ + return mData.getIds (listDeleted); +} diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index c10d1d2d0..22f83150d 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -89,6 +89,11 @@ namespace CSMWorld virtual int getAppendIndex (UniversalId::Type type) const; ///< \param type Will be ignored, unless the collection supports multiple record types + + virtual std::vector getIds (bool listDeleted) const; + ///< Return a sorted collection of all IDs + /// + /// \param listDeleted include deleted record in the list }; } diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index c95db045f..9457937f1 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -196,3 +196,25 @@ int CSMWorld::RefIdData::getSize() const { return mIndex.size(); } + +std::vector CSMWorld::RefIdData::getIds (bool listDeleted) const +{ + std::vector ids; + + for (std::map::const_iterator iter (mIndex.begin()); iter!=mIndex.end(); + ++iter) + { + if (listDeleted || !getRecord (iter->second).isDeleted()) + { + std::map::const_iterator container = + mRecordContainers.find (iter->second.second); + + if (container==mRecordContainers.end()) + throw std::logic_error ("Invalid referenceable ID type"); + + ids.push_back (container->second->getId (iter->second.first)); + } + } + + return ids; +} diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 475566fb5..e221fbc7c 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -182,6 +182,11 @@ namespace CSMWorld void load (const LocalIndex& index, ESM::ESMReader& reader, bool base); int getSize() const; + + std::vector getIds (bool listDeleted = true) const; + ///< Return a sorted collection of all IDs + /// + /// \param listDeleted include deleted record in the list }; } diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 69b72abf2..86689d823 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -1,6 +1,14 @@ #include "scriptcontext.hpp" +#include + +#include + +#include "data.hpp" + +CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUpdated (false) {} + bool CSMWorld::ScriptContext::canDeclareLocals() const { return false; @@ -18,5 +26,19 @@ char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std: bool CSMWorld::ScriptContext::isId (const std::string& name) const { - return false; + if (!mIdsUpdated) + { + mIds = mData.getIds(); + + std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCase); + + mIdsUpdated = true; + } + + return std::binary_search (mIds.begin(), mIds.end(), Misc::StringUtils::lowerCase (name)); +} + +void CSMWorld::ScriptContext::invalidateIds() +{ + mIdsUpdated = false; } \ No newline at end of file diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp index 1231aea64..b839b5a43 100644 --- a/apps/opencs/model/world/scriptcontext.hpp +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -1,14 +1,25 @@ #ifndef CSM_WORLD_SCRIPTCONTEXT_H #define CSM_WORLD_SCRIPTCONTEXT_H +#include +#include + #include namespace CSMWorld { + class Data; + class ScriptContext : public Compiler::Context { + const Data& mData; + mutable std::vector mIds; + mutable bool mIdsUpdated; + public: + ScriptContext (const Data& data); + virtual bool canDeclareLocals() const; ///< Is the compiler allowed to declare local variables? @@ -20,6 +31,8 @@ namespace CSMWorld virtual bool isId (const std::string& name) const; ///< Does \a name match an ID, that can be referenced? + + void invalidateIds(); }; } diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 910819700..2784bca8c 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -43,6 +43,10 @@ boost::filesystem::path CSVDoc::AdjusterWidget::getPath() const return mResultPath; } +bool CSVDoc::AdjusterWidget::isValid() const +{ + return mValid; +} void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) { QString message; @@ -88,4 +92,4 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) pixmap (QSize (16, 16))); emit stateChanged (mValid); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/adjusterwidget.hpp b/apps/opencs/view/doc/adjusterwidget.hpp index f578dc4ae..d970cffee 100644 --- a/apps/opencs/view/doc/adjusterwidget.hpp +++ b/apps/opencs/view/doc/adjusterwidget.hpp @@ -25,6 +25,9 @@ namespace CSVDoc void setLocalData (const boost::filesystem::path& localData); + QString getText() const; + bool isValid() const; + boost::filesystem::path getPath() const; ///< This function must not be called if there is no valid path. @@ -38,4 +41,4 @@ namespace CSVDoc }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index f956317a7..9dce090a1 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -9,145 +9,48 @@ #include #include #include +#include -#include -#include -#include +#include +#include -#include +#include "filewidget.hpp" +#include "adjusterwidget.hpp" -FileDialog::FileDialog(QWidget *parent) : - QDialog(parent) +#include + +CSVDoc::FileDialog::FileDialog(QWidget *parent) : + ContentSelector(parent), + mFileWidget (new FileWidget (this)), + mAdjusterWidget (new AdjusterWidget (this)), + mEnable_1(false), + mEnable_2(false) { - setupUi(this); - - // Models - mDataFilesModel = new DataFilesModel(this); - - mMastersProxyModel = new QSortFilterProxyModel(); - mMastersProxyModel->setFilterRegExp(QString("^.*\\.esm")); - mMastersProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - mMastersProxyModel->setSourceModel(mDataFilesModel); - - mPluginsProxyModel = new PluginsProxyModel(); - mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp")); - mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - mPluginsProxyModel->setSourceModel(mDataFilesModel); - - mFilterProxyModel = new QSortFilterProxyModel(); - mFilterProxyModel->setDynamicSortFilter(true); - mFilterProxyModel->setSourceModel(mPluginsProxyModel); - - QCheckBox checkBox; - unsigned int height = checkBox.sizeHint().height() + 4; - - mastersTable->setModel(mMastersProxyModel); - mastersTable->setObjectName("MastersTable"); - mastersTable->setContextMenuPolicy(Qt::CustomContextMenu); - mastersTable->setSortingEnabled(false); - mastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection); - mastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - mastersTable->setAlternatingRowColors(true); - mastersTable->horizontalHeader()->setStretchLastSection(true); - - // Set the row height to the size of the checkboxes - mastersTable->verticalHeader()->setDefaultSectionSize(height); - mastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - mastersTable->verticalHeader()->hide(); - - pluginsTable->setModel(mFilterProxyModel); - pluginsTable->setObjectName("PluginsTable"); - pluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); - pluginsTable->setSortingEnabled(false); - pluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); - pluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection); - pluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - pluginsTable->setAlternatingRowColors(true); - pluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); - pluginsTable->horizontalHeader()->setStretchLastSection(true); - - pluginsTable->verticalHeader()->setDefaultSectionSize(height); - pluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - // Hide the profile elements - profileLabel->hide(); - profilesComboBox->hide(); - newProfileButton->hide(); - deleteProfileButton->hide(); + profileGroupBox->hide(); + addonView->showColumn(2); - // Add some extra widgets - QHBoxLayout *nameLayout = new QHBoxLayout(); - QSpacerItem *spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + resize(400, 400); - mNameLabel = new QLabel(tr("File Name:"), this); + mFileWidget->setType(true); + mFileWidget->extensionLabelIsVisible(false); - QRegExpValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9\\s]*$")); - mNameLineEdit = new LineEdit(this); - mNameLineEdit->setValidator(validator); + connect(projectCreateButton, SIGNAL(clicked()), this, SIGNAL(createNewFile())); - nameLayout->addSpacerItem(spacer); - nameLayout->addWidget(mNameLabel); - nameLayout->addWidget(mNameLineEdit); + connect(projectButtonBox, SIGNAL(accepted()), this, SIGNAL(openFiles())); + connect(projectButtonBox, SIGNAL(rejected()), this, SLOT(reject())); - mButtonBox = new QDialogButtonBox(this); + connect (mFileWidget, SIGNAL (nameChanged (const QString&, bool)), + mAdjusterWidget, SLOT (setName (const QString&, bool))); - mCreateButton = new QPushButton(tr("Create"), this); - mCreateButton->setEnabled(false); - - verticalLayout->addLayout(nameLayout); - verticalLayout->addWidget(mButtonBox); - - // Set sizes - QList sizeList; - sizeList << 175; - sizeList << 200; - - splitter->setSizes(sizeList); - - resize(600, 400); - - connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); - connect(mDataFilesModel, SIGNAL(checkedItemsChanged(QStringList)), this, SLOT(updateOpenButton(QStringList))); - connect(mNameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(updateCreateButton(QString))); - - connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); - - connect(pluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - connect(mastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - - connect(mCreateButton, SIGNAL(clicked()), this, SLOT(createButtonClicked())); - - connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect (mAdjusterWidget, SIGNAL (stateChanged (bool)), this, SLOT (slotAdjusterChanged(bool))); + connect (this, SIGNAL (signalGameFileChanged(int)), this, SLOT (slotGameFileSelected(int))); + connect (this, SIGNAL (signalUpdateCreateButton(bool, int)), this, SLOT (slotEnableCreateButton(bool, int))); } -void FileDialog::updateViews() +void CSVDoc::FileDialog::updateOpenButton(const QStringList &items) { - // Ensure the columns are hidden because sort() re-enables them - mastersTable->setColumnHidden(1, true); - mastersTable->setColumnHidden(3, true); - mastersTable->setColumnHidden(4, true); - mastersTable->setColumnHidden(5, true); - mastersTable->setColumnHidden(6, true); - mastersTable->setColumnHidden(7, true); - mastersTable->setColumnHidden(8, true); - mastersTable->resizeColumnsToContents(); - - pluginsTable->setColumnHidden(1, true); - pluginsTable->setColumnHidden(3, true); - pluginsTable->setColumnHidden(4, true); - pluginsTable->setColumnHidden(5, true); - pluginsTable->setColumnHidden(6, true); - pluginsTable->setColumnHidden(7, true); - pluginsTable->setColumnHidden(8, true); - pluginsTable->resizeColumnsToContents(); - -} - -void FileDialog::updateOpenButton(const QStringList &items) -{ - QPushButton *openButton = mButtonBox->button(QDialogButtonBox::Open); + QPushButton *openButton = projectButtonBox->button(QDialogButtonBox::Open); if (!openButton) return; @@ -155,118 +58,60 @@ void FileDialog::updateOpenButton(const QStringList &items) openButton->setEnabled(!items.isEmpty()); } -void FileDialog::updateCreateButton(const QString &name) +void CSVDoc::FileDialog::slotEnableCreateButton(bool enable, int widgetNumber) { - if (!mCreateButton->isVisible()) - return; - mCreateButton->setEnabled(!name.isEmpty()); + if (widgetNumber == 1) + mEnable_1 = enable; + + if (widgetNumber == 2) + mEnable_2 = enable; + + qDebug() << "update enabled" << mEnable_1 << mEnable_2 << enable; + projectCreateButton->setEnabled(mEnable_1 && mEnable_2); } -void FileDialog::filterChanged(const QString &filter) +QString CSVDoc::FileDialog::fileName() { - QRegExp filterRe(filter, Qt::CaseInsensitive, QRegExp::FixedString); - mFilterProxyModel->setFilterRegExp(filterRe); + return mFileWidget->getName(); } -void FileDialog::addFiles(const QString &path) -{ - mDataFilesModel->addFiles(path); - mDataFilesModel->sort(3); // Sort by date accessed -} - -void FileDialog::setEncoding(const QString &encoding) -{ - mDataFilesModel->setEncoding(encoding); -} - -void FileDialog::setCheckState(QModelIndex index) -{ - if (!index.isValid()) - return; - - QObject *object = QObject::sender(); - - // Not a signal-slot call - if (!object) - return; - - - if (object->objectName() == QLatin1String("PluginsTable")) { - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( - mFilterProxyModel->mapToSource(index)); - - if (sourceIndex.isValid()) { - (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) - ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked) - : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); - } - } - - if (object->objectName() == QLatin1String("MastersTable")) { - QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index); - - if (sourceIndex.isValid()) { - (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) - ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked) - : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); - } - } - - return; -} - -QStringList FileDialog::checkedItemsPaths() -{ - return mDataFilesModel->checkedItemsPaths(); -} - -QString FileDialog::fileName() -{ - return mNameLineEdit->text(); -} - -void FileDialog::openFile() +void CSVDoc::FileDialog::openFile() { setWindowTitle(tr("Open")); - mNameLabel->hide(); - mNameLineEdit->hide(); - mCreateButton->hide(); - - mButtonBox->removeButton(mCreateButton); - mButtonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Open); - QPushButton *openButton = mButtonBox->button(QDialogButtonBox::Open); - openButton->setEnabled(false); + mFileWidget->hide(); + adjusterWidgetFrame->hide(); + projectCreateButton->hide(); + projectGroupBox->setTitle(tr("")); + projectButtonBox->button(QDialogButtonBox::Open)->setEnabled(false); show(); raise(); activateWindow(); } -void FileDialog::newFile() +void CSVDoc::FileDialog::newFile() { setWindowTitle(tr("New")); - mNameLabel->show(); - mNameLineEdit->clear(); - mNameLineEdit->show(); - mCreateButton->show(); + fileWidgetFrame->layout()->addWidget(mFileWidget); + adjusterWidgetFrame->layout()->addWidget(mAdjusterWidget); - mButtonBox->setStandardButtons(QDialogButtonBox::Cancel); - mButtonBox->addButton(mCreateButton, QDialogButtonBox::ActionRole); + projectButtonBox->setStandardButtons(QDialogButtonBox::Cancel); + projectButtonBox->addButton(projectCreateButton, QDialogButtonBox::ActionRole); show(); raise(); activateWindow(); } -void FileDialog::accept() +void CSVDoc::FileDialog::slotAdjusterChanged(bool value) { - emit openFiles(); + emit signalUpdateCreateButton(mAdjusterWidget->isValid(), 2); } -void FileDialog::createButtonClicked() +void CSVDoc::FileDialog::slotGameFileSelected(int value) { - emit createNewFile(); + emit signalUpdateCreateButton(value > -1, 1); } diff --git a/apps/opencs/view/doc/filedialog.hpp b/apps/opencs/view/doc/filedialog.hpp index b21618d5d..7782dd94e 100644 --- a/apps/opencs/view/doc/filedialog.hpp +++ b/apps/opencs/view/doc/filedialog.hpp @@ -4,6 +4,7 @@ #include #include +#include "components/contentselector/view/contentselector.hpp" #include "ui_datafilespage.h" class QDialogButtonBox; @@ -13,54 +14,54 @@ class QPushButton; class QStringList; class QString; class QMenu; +class QLabel; class DataFilesModel; class PluginsProxyModel; -class FileDialog : public QDialog, private Ui::DataFilesPage +namespace ContentSelectorView { - Q_OBJECT -public: - explicit FileDialog(QWidget *parent = 0); - void addFiles(const QString &path); - void setEncoding(const QString &encoding); + class LineEdit; +} - void openFile(); - void newFile(); - void accepted(); +namespace CSVDoc +{ + class FileWidget; + class AdjusterWidget; - QStringList checkedItemsPaths(); - QString fileName(); + class FileDialog : public ContentSelectorView::ContentSelector + { + Q_OBJECT -signals: - void openFiles(); - void createNewFile(); - -public slots: - void accept(); + FileWidget *mFileWidget; + AdjusterWidget *mAdjusterWidget; -private slots: - void updateViews(); - void updateOpenButton(const QStringList &items); - void updateCreateButton(const QString &name); - void setCheckState(QModelIndex index); + bool mEnable_1; + bool mEnable_2; - void filterChanged(const QString &filter); + public: + explicit FileDialog(QWidget *parent = 0); - void createButtonClicked(); + void openFile(); + void newFile(); -private: - QLabel *mNameLabel; - LineEdit *mNameLineEdit; + QString fileName(); - QPushButton *mCreateButton; - QDialogButtonBox *mButtonBox; + signals: + void openFiles(); + void createNewFile(); - DataFilesModel *mDataFilesModel; + void signalUpdateCreateButton (bool, int); + void signalUpdateCreateButtonFlags(int); - PluginsProxyModel *mPluginsProxyModel; - QSortFilterProxyModel *mMastersProxyModel; - QSortFilterProxyModel *mFilterProxyModel; -}; + public slots: + private slots: + //void updateViews(); + void updateOpenButton(const QStringList &items); + void slotEnableCreateButton(bool enable, int widgetNumber); + void slotAdjusterChanged(bool value); + void slotGameFileSelected(int value); + }; +} #endif // FILEDIALOG_HPP diff --git a/apps/opencs/view/doc/filewidget.cpp b/apps/opencs/view/doc/filewidget.cpp index c8f33e92d..9cd2fad42 100644 --- a/apps/opencs/view/doc/filewidget.cpp +++ b/apps/opencs/view/doc/filewidget.cpp @@ -50,4 +50,9 @@ QString CSVDoc::FileWidget::getName() const void CSVDoc::FileWidget::textChanged (const QString& text) { emit nameChanged (getName(), mAddon); -} \ No newline at end of file +} + +void CSVDoc::FileWidget::extensionLabelIsVisible(bool visible) +{ + mType->setVisible(visible); +} diff --git a/apps/opencs/view/doc/filewidget.hpp b/apps/opencs/view/doc/filewidget.hpp index c51c29632..ff09d71a3 100644 --- a/apps/opencs/view/doc/filewidget.hpp +++ b/apps/opencs/view/doc/filewidget.hpp @@ -27,6 +27,8 @@ namespace CSVDoc QString getName() const; + void extensionLabelIsVisible(bool visible); + private slots: void textChanged (const QString& text); diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index 288a3d12a..e06dab372 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -4,6 +4,7 @@ #include #include +#include bool CSVWorld::ScriptHighlighter::parseInt (int value, const Compiler::TokenLoc& loc, Compiler::Scanner& scanner) @@ -22,7 +23,7 @@ bool CSVWorld::ScriptHighlighter::parseFloat (float value, const Compiler::Token bool CSVWorld::ScriptHighlighter::parseName (const std::string& name, const Compiler::TokenLoc& loc, Compiler::Scanner& scanner) { - highlight (loc, Type_Name); + highlight (loc, mContext.isId (name) ? Type_Id : Type_Name); return true; } @@ -62,10 +63,10 @@ void CSVWorld::ScriptHighlighter::highlight (const Compiler::TokenLoc& loc, Type setFormat (index, length, mScheme[type]); } -CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent) -: QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext) +CSVWorld::ScriptHighlighter::ScriptHighlighter (const CSMWorld::Data& data, QTextDocument *parent) +: QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext), mContext (data) { - /// \ŧodo replace this with user settings + /// \todo replace this with user settings { QTextCharFormat format; format.setForeground (Qt::darkMagenta); @@ -101,6 +102,16 @@ CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent) format.setForeground (Qt::green); mScheme.insert (std::make_pair (Type_Comment, format)); } + + { + QTextCharFormat format; + format.setForeground (Qt::blue); + mScheme.insert (std::make_pair (Type_Id, format)); + } + + // configure compiler + Compiler::registerExtensions (mExtensions); + mContext.setExtensions (&mExtensions); } void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text) @@ -114,5 +125,9 @@ void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text) scanner.scan (*this); } catch (...) {} // ignore syntax errors +} +void CSVWorld::ScriptHighlighter::invalidateIds() +{ + mContext.invalidateIds(); } \ No newline at end of file diff --git a/apps/opencs/view/world/scripthighlighter.hpp b/apps/opencs/view/world/scripthighlighter.hpp index 3ef697809..495c2e6a3 100644 --- a/apps/opencs/view/world/scripthighlighter.hpp +++ b/apps/opencs/view/world/scripthighlighter.hpp @@ -7,6 +7,7 @@ #include #include +#include #include "../../model/world/scriptcontext.hpp" @@ -23,12 +24,14 @@ namespace CSVWorld Type_Name, Type_Keyword, Type_Special, - Type_Comment + Type_Comment, + Type_Id }; private: Compiler::NullErrorHandler mErrorHandler; + Compiler::Extensions mExtensions; CSMWorld::ScriptContext mContext; std::map mScheme; @@ -71,9 +74,11 @@ namespace CSVWorld public: - ScriptHighlighter (QTextDocument *parent); + ScriptHighlighter (const CSMWorld::Data& data, QTextDocument *parent); virtual void highlightBlock (const QString& text); + + void invalidateIds(); }; } diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index ab1c2d57c..446c34e5f 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -58,7 +58,13 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); - new ScriptHighlighter (mEditor->document()); + connect (&document.getData(), SIGNAL (idListChanged()), this, SLOT (idListChanged())); + + mHighlighter = new ScriptHighlighter (document.getData(), mEditor->document()); + + connect (&mUpdateTimer, SIGNAL (timeout()), this, SLOT (updateHighlighting())); + + mUpdateTimer.setSingleShot (true); } void CSVWorld::ScriptSubView::setEditLock (bool locked) @@ -66,8 +72,19 @@ void CSVWorld::ScriptSubView::setEditLock (bool locked) mEditor->setReadOnly (locked); } +void CSVWorld::ScriptSubView::idListChanged() +{ + mHighlighter->invalidateIds(); + + if (!mUpdateTimer.isActive()) + mUpdateTimer.start (0); +} + void CSVWorld::ScriptSubView::textChanged() { + if (mChangeLocked) + return; + ChangeLock lock (*this); mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel, @@ -79,6 +96,8 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo if (mChangeLocked) return; + ChangeLock lock (*this); + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); if (index.row()>=topLeft.row() && index.row()<=bottomRight.row() && @@ -96,4 +115,14 @@ void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, i if (!parent.isValid() && index.row()>=start && index.row()<=end) deleteLater(); +} + +void CSVWorld::ScriptSubView::updateHighlighting() +{ + if (mChangeLocked) + return; + + ChangeLock lock (*this); + + mHighlighter->rehighlight(); } \ No newline at end of file diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 07d87d947..7ceab70ba 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -3,6 +3,8 @@ #include "../doc/subview.hpp" +#include + class QTextEdit; class QModelIndex; @@ -18,6 +20,8 @@ namespace CSMWorld namespace CSVWorld { + class ScriptHighlighter; + class ScriptSubView : public CSVDoc::SubView { Q_OBJECT @@ -27,6 +31,8 @@ namespace CSVWorld CSMWorld::IdTable *mModel; int mColumn; int mChangeLocked; + ScriptHighlighter *mHighlighter; + QTimer mUpdateTimer; class ChangeLock { @@ -49,13 +55,19 @@ namespace CSVWorld virtual void setEditLock (bool locked); - private slots: + public slots: + + void idListChanged(); void textChanged(); void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); void rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end); + + private slots: + + void updateHighlighting(); }; } diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a44fd4b34..b367e2a1e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -119,6 +119,10 @@ target_link_libraries(openmw components ) +if (USE_SYSTEM_TINYXML) + target_link_libraries(openmw ${TINYXML_LIBRARIES}) +endif() + if (NOT UNIX) target_link_libraries(openmw ${SDL2MAIN_LIBRARY}) endif() diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6101358de..f8453afed 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -396,6 +396,8 @@ namespace MWBase /// It only applies to the current form the NPC is in. virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor) = 0; + virtual bool getGodModeState() = 0; + virtual bool toggleGodMode() = 0; }; } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index f9d31bdcd..edcd49738 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -250,6 +250,7 @@ namespace MWGui // remove object from the container it was coming from mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount); mDragAndDrop->finish(); + mDragAndDrop->mSourceModel->update(); } else { diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1039a0dce..430a5d843 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -585,7 +585,7 @@ namespace MWInput mPlayer->pitch(-y/scale); } - if (arg.zrel) + if (arg.zrel && mControlSwitch["playerviewswitch"]) //Check to make sure you are allowed to zoomout and there is a change { MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.zrel); MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 566d4bc50..ca26e88ce 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -275,9 +275,8 @@ namespace MWMechanics continue; } - // workaround: always keep player alive for now - // \todo remove workaround, once player death can be handled - if(iter->first.getRefData().getHandle()=="player") + // If it's the player and God Mode is turned on, keep it alive + if(iter->first.getRefData().getHandle()=="player" && MWBase::Environment::get().getWorld()->getGodModeState()) { MWMechanics::DynamicStat stat(stats.getHealth()); diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index 1a7b34817..3ed458c3f 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -151,8 +151,7 @@ namespace MWMechanics for (Collection::const_iterator iter (prev.begin()); iter!=prev.end(); ++iter) { Collection::const_iterator other = now.mCollection.find (iter->first); - - if (other==prev.end()) + if (other==now.end()) { result.add (iter->first, EffectParam() - iter->second); } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index c53cafa17..a8d8a5f2b 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -726,8 +726,7 @@ namespace MWScript bool enabled = MWBase::Environment::get().getWorld()->toggleGodMode(); - // context.report (enabled ? "God Mode -> On" : "God Mode -> Off"); - context.report("Unimplemented"); + context.report (enabled ? "God Mode -> On" : "God Mode -> Off"); } }; diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 7703f2d23..963316070 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -36,7 +36,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) // all files/readers used by the engine. This will greaty accelerate // refnumber mangling, as required for handling moved references. int index = ~0; - const std::vector &masters = esm.getMasters(); + const std::vector &masters = esm.getGameFiles(); std::vector *allPlugins = esm.getGlobalReaderList(); for (size_t j = 0; j < masters.size(); j++) { ESM::Header::MasterData &mast = const_cast(masters[j]); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a372e5288..f3d4c81b7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -170,7 +170,7 @@ namespace MWWorld mSky (true), mCells (mStore, mEsm), mActivationDistanceOverride (mActivationDistanceOverride), mFallback(fallbackMap), mPlayIntro(0), mTeleportEnabled(true), - mFacedDistance(FLT_MAX) + mFacedDistance(FLT_MAX), mGodMode(false) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); @@ -1948,9 +1948,16 @@ namespace MWWorld stats.getSkill(ESM::Skill::Acrobatics).setModified(gmst.find("fWerewolfAcrobatics")->getFloat(), 0); } + bool World::getGodModeState() + { + return mGodMode; + } + bool World::toggleGodMode() { - return false; + mGodMode = !mGodMode; + + return mGodMode; } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 30ffcda40..53b01f1ab 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -68,6 +68,8 @@ namespace MWWorld OEngine::Physic::PhysicEngine* mPhysEngine; + bool mGodMode; + // not implemented World (const World&); World& operator= (const World&); @@ -440,6 +442,8 @@ namespace MWWorld virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor); + virtual bool getGodModeState(); + virtual bool toggleGodMode(); }; } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 04423dc6f..7053bb973 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -1,5 +1,5 @@ project (Components) - +set (CMAKE_BUILD_TYPE DEBUG) # source files add_component_dir (settings @@ -74,21 +74,26 @@ add_component_dir (loadinglistener loadinglistener ) +set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/datafilespage.ui + ) find_package(Qt4 COMPONENTS QtCore QtGui) if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) - add_component_qt_dir (fileorderlist - model/modelitem model/datafilesmodel model/pluginsproxymodel model/esm/esmfile - utils/profilescombobox utils/comboboxlineedit utils/lineedit utils/naturalsort + add_component_qt_dir (contentselector + model/modelitem model/esmfile + model/naturalsort model/contentmodel + view/profilescombobox view/comboboxlineedit + view/lineedit view/contentselector ) include(${QT_USE_FILE}) + QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI}) QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) endif(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) -include_directories(${BULLET_INCLUDE_DIRS}) +include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) -add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS}) +add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES}) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp new file mode 100644 index 000000000..b85da25c6 --- /dev/null +++ b/components/contentselector/model/contentmodel.cpp @@ -0,0 +1,478 @@ +#include "contentmodel.hpp" +#include "esmfile.hpp" + +#include +#include +#include +#include + +ContentSelectorModel::ContentModel::ContentModel(QObject *parent) : + QAbstractTableModel(parent), + mMimeType ("application/omwcontent"), + mMimeTypes (QStringList() << mMimeType), + mColumnCount (1), + mDragDropFlags (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled), + mDefaultFlags (Qt::ItemIsDropEnabled | Qt::ItemIsSelectable), + mDropActions (Qt::CopyAction | Qt::MoveAction) +{ + // setEncoding ("win1252"); + uncheckAll(); +} +/* +void ContentSelectorModel::ContentModel::setEncoding(const QString &encoding) +{ + if (encoding == QLatin1String("win1252")) + mCodec = QTextCodec::codecForName("windows-1252"); + + else if (encoding == QLatin1String("win1251")) + mCodec = QTextCodec::codecForName("windows-1251"); + + else if (encoding == QLatin1String("win1250")) + mCodec = QTextCodec::codecForName("windows-1250"); + + else + return; // This should never happen; +} +*/ +int ContentSelectorModel::ContentModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + return mColumnCount; +} + +int ContentSelectorModel::ContentModel::rowCount(const QModelIndex &parent) const +{ + if(parent.isValid()) + return 0; + + return mFiles.size(); +} + +const ContentSelectorModel::EsmFile *ContentSelectorModel::ContentModel::item(int row) const +{ + if (row >= 0 && row < mFiles.size()) + return mFiles.at(row); + + return 0; +} + +ContentSelectorModel::EsmFile *ContentSelectorModel::ContentModel::item(int row) +{ + if (row >= 0 && row < mFiles.count()) + return mFiles.at(row); + + return 0; +} +const ContentSelectorModel::EsmFile *ContentSelectorModel::ContentModel::findItem(const QString &name) const +{ + foreach (const EsmFile *file, mFiles) + { + if (name == file->fileName()) + return file; + } + return 0; +} + +QModelIndex ContentSelectorModel::ContentModel::indexFromItem(const EsmFile *item) const +{ + //workaround: non-const pointer cast for calls from outside contentmodel/contentselector + EsmFile *non_const_file_ptr = const_cast(item); + + if (item) + return index(mFiles.indexOf(non_const_file_ptr),0); + + return QModelIndex(); +} + +Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::NoItemFlags; + + const EsmFile *file = item(index.row()); + + if (!file) + return Qt::NoItemFlags; + + if (canBeChecked(file)) + return Qt::ItemIsEnabled | mDragDropFlags | mDefaultFlags; + + return mDefaultFlags; +} + +QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() >= mFiles.size()) + return QVariant(); + + const EsmFile *file = item(index.row()); + + if (!file) + return QVariant(); + + const int column = index.column(); + + switch (role) + { + case Qt::EditRole: + case Qt::DisplayRole: + { + if (column >=0 && column <=EsmFile::FileProperty_GameFile) + return file->fileProperty(static_cast(column)); + + return QVariant(); + break; + } + + case Qt::TextAlignmentRole: + { + switch (column) + { + case 0: + case 1: + return Qt::AlignLeft + Qt::AlignVCenter; + case 2: + case 3: + return Qt::AlignRight + Qt::AlignVCenter; + default: + return Qt::AlignLeft + Qt::AlignVCenter; + } + return QVariant(); + break; + } + + case Qt::ToolTipRole: + { + if (column != 0) + return QVariant(); + + return file->toolTip(); + break; + } + + case Qt::CheckStateRole: + { + if (!file->isGameFile()) + return isChecked(file->fileName()); + break; + } + + case Qt::UserRole: + { + if (file->isGameFile()) + return ContentType_GameFile; + else + if (flags(index) & Qt::ItemIsEnabled) + return ContentType_Addon; + + break; + } + + case Qt::UserRole + 1: + return isChecked(file->fileName()); + break; + } + return QVariant(); +} + +bool ContentSelectorModel::ContentModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if(!index.isValid()) + return false; + + EsmFile *file = item(index.row()); + QString fileName = file->fileName(); + bool success = false; + + switch(role) + { + case Qt::EditRole: + { + QStringList list = value.toStringList(); + + for (int i = 0; i < EsmFile::FileProperty_GameFile; i++) + file->setFileProperty(static_cast(i), list.at(i)); + + for (int i = EsmFile::FileProperty_GameFile; i < list.size(); i++) + file->setFileProperty (EsmFile::FileProperty_GameFile, list.at(i)); + + emit dataChanged(index, index); + + success = true; + } + break; + + case Qt::UserRole+1: + { + setCheckState(fileName, value.toBool()); + + emit dataChanged(index, index); + + foreach (EsmFile *file, mFiles) + { + if (file->gameFiles().contains(fileName)) + { + QModelIndex idx = indexFromItem(file); + emit dataChanged(idx, idx); + } + } + success = true; + } + break; + + case Qt::CheckStateRole: + { + int checkValue = value.toInt(); + bool success = false; + bool setState = false; + if ((checkValue==Qt::Checked) && !isChecked(fileName)) + { + setState = true; + success = true; + } + else if ((checkValue == Qt::Checked) && isChecked (fileName)) + setState = true; + else if (checkValue == Qt::Unchecked) + setState = true; + + if (setState) + { + setCheckState(fileName, success); + emit dataChanged(index, index); + + } + else + return success; + + + foreach (EsmFile *file, mFiles) + { + if (file->gameFiles().contains(fileName)) + { + QModelIndex idx = indexFromItem(file); + emit dataChanged(idx, idx); + } + } + + success = true; + } + break; + } + + return success; +} + +bool ContentSelectorModel::ContentModel::insertRows(int position, int rows, const QModelIndex &parent) +{ + if (parent.isValid()) + return false; + + beginInsertRows(parent, position, position+rows-1); + { + for (int row = 0; row < rows; ++row) + mFiles.insert(position, new EsmFile); + + } endInsertRows(); + + return true; +} + +bool ContentSelectorModel::ContentModel::removeRows(int position, int rows, const QModelIndex &parent) +{ + if (parent.isValid()) + return false; + + beginRemoveRows(parent, position, position+rows-1); + { + for (int row = 0; row < rows; ++row) + delete mFiles.takeAt(position); + + } endRemoveRows(); + + return true; +} + +Qt::DropActions ContentSelectorModel::ContentModel::supportedDropActions() const +{ + return mDropActions; +} + +QStringList ContentSelectorModel::ContentModel::mimeTypes() const +{ + return mMimeTypes; +} + +QMimeData *ContentSelectorModel::ContentModel::mimeData(const QModelIndexList &indexes) const +{ + QByteArray encodedData; + + foreach (const QModelIndex &index, indexes) + { + if (!index.isValid()) + continue; + + encodedData.append(item(index.row())->encodedData()); + } + + QMimeData *mimeData = new QMimeData(); + mimeData->setData(mMimeType, encodedData); + + return mimeData; +} + +bool ContentSelectorModel::ContentModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) +{ + if (action == Qt::IgnoreAction) + return true; + + if (column > 0) + return false; + + if (!data->hasFormat(mMimeType)) + return false; + + int beginRow = rowCount(); + + if (row != -1) + beginRow = row; + + else if (parent.isValid()) + beginRow = parent.row(); + + QByteArray encodedData = data->data(mMimeType); + QDataStream stream(&encodedData, QIODevice::ReadOnly); + + while (!stream.atEnd()) + { + + QString value; + QStringList values; + QStringList gamefiles; + + for (int i = 0; i < EsmFile::FileProperty_GameFile; ++i) + { + stream >> value; + values << value; + } + + stream >> gamefiles; + + insertRows(beginRow, 1); + + QModelIndex idx = index(beginRow++, 0, QModelIndex()); + setData(idx, QStringList() << values << gamefiles, Qt::EditRole); + } + + return true; +} + +bool ContentSelectorModel::ContentModel::canBeChecked(const EsmFile *file) const +{ + //element can be checked if all its dependencies are + foreach (const QString &gamefile, file->gameFiles()) + if (!isChecked(gamefile)) + return false; + + return true; +} + +void ContentSelectorModel::ContentModel::addFile(EsmFile *file) +{ + beginInsertRows(QModelIndex(), mFiles.count(), mFiles.count()); + mFiles.append(file); + endInsertRows(); +} + +void ContentSelectorModel::ContentModel::addFiles(const QString &path) +{ + QDir dir(path); + QStringList filters; + filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon"; + dir.setNameFilters(filters); + + QTextCodec *codec = QTextCodec::codecForName("UTF8"); + + // Create a decoder for non-latin characters in esx metadata + QTextDecoder *decoder = codec->makeDecoder(); + + foreach (const QString &path, dir.entryList()) + { + QFileInfo info(dir.absoluteFilePath(path)); + EsmFile *file = new EsmFile(path); + + try { + ESM::ESMReader fileReader; + ToUTF8::Utf8Encoder encoder(); //ToUTF8::calculateEncoding(QString(mCodec->name()).toStdString())); + //fileReader.setEncoder(&encoder); + fileReader.open(dir.absoluteFilePath(path).toStdString()); + + foreach (const ESM::Header::MasterData &item, fileReader.getGameFiles()) + file->addGameFile(QString::fromStdString(item.name)); + + file->setAuthor (decoder->toUnicode(fileReader.getAuthor().c_str())); + file->setDate (info.lastModified()); + file->setFormat (fileReader.getFormat()); + file->setPath (info.absoluteFilePath()); + file->setDescription(decoder->toUnicode(fileReader.getDesc().c_str())); + + + // Put the file in the table + if (findItem(path) == 0) + addFile(file); + + } catch(std::runtime_error &e) { + // An error occurred while reading the .esp + qWarning() << "Error reading addon file: " << e.what(); + continue; + } + + } + + delete decoder; +} + +bool ContentSelectorModel::ContentModel::isChecked(const QString& name) const +{ + if (mCheckStates.contains(name)) + return (mCheckStates[name] == Qt::Checked); + + return false; +} + +void ContentSelectorModel::ContentModel::setCheckState(const QString &name, bool isChecked) +{ + if (name.isEmpty()) + return; + + Qt::CheckState state = Qt::Unchecked; + + if (isChecked) + state = Qt::Checked; + + mCheckStates[name] = state; +} + +ContentSelectorModel::ContentFileList ContentSelectorModel::ContentModel::checkedItems() const +{ + ContentFileList list; + + foreach (EsmFile *file, mFiles) + { + if (isChecked(file->fileName())) + list << file; + } + + return list; +} + +void ContentSelectorModel::ContentModel::uncheckAll() +{ + emit layoutAboutToBeChanged(); + mCheckStates.clear(); + emit layoutChanged(); +} diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp new file mode 100644 index 000000000..a8ff103da --- /dev/null +++ b/components/contentselector/model/contentmodel.hpp @@ -0,0 +1,73 @@ +#ifndef CONTENTMODEL_HPP +#define CONTENTMODEL_HPP + +#include +#include + +namespace ContentSelectorModel +{ + class EsmFile; + + typedef QList ContentFileList; + + enum ContentType + { + ContentType_GameFile, + ContentType_Addon + }; + + class ContentModel : public QAbstractTableModel + { + Q_OBJECT + public: + explicit ContentModel(QObject *parent = 0); + + //void setEncoding(const QString &encoding); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + + QVariant data(const QModelIndex &index, int role) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()); + bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()); + + Qt::DropActions supportedDropActions() const; + QStringList mimeTypes() const; + QMimeData *mimeData(const QModelIndexList &indexes) const; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + + void addFiles(const QString &path); + + QModelIndex indexFromItem(const EsmFile *item) const; + const EsmFile *findItem(const QString &name) const; + + bool isChecked(const QString &name) const; + void setCheckState(const QString &name, bool isChecked); + ContentFileList checkedItems() const; + void uncheckAll(); + + private: + + void addFile(EsmFile *file); + const EsmFile *item(int row) const; + EsmFile *item(int row); + bool canBeChecked(const EsmFile *file) const; + + ContentFileList mFiles; + QHash mCheckStates; + QTextCodec *mCodec; + + public: + QString mMimeType; + QStringList mMimeTypes; + int mColumnCount; + Qt::ItemFlags mDragDropFlags; + Qt::ItemFlags mDefaultFlags; + Qt::DropActions mDropActions; + + }; +} +#endif // CONTENTMODEL_HPP diff --git a/components/contentselector/model/esmfile.cpp b/components/contentselector/model/esmfile.cpp new file mode 100644 index 000000000..9dfe49eba --- /dev/null +++ b/components/contentselector/model/esmfile.cpp @@ -0,0 +1,136 @@ +#include "esmfile.hpp" + +#include +#include + +int ContentSelectorModel::EsmFile::sPropertyCount = 7; +QString ContentSelectorModel::EsmFile::sToolTip = QString("Author: %1
\ + Version: %2
\ +
Description:
%3
\ +
Dependencies: %4
"); + + +ContentSelectorModel::EsmFile::EsmFile(QString fileName, ModelItem *parent) + : ModelItem(parent), mFileName(fileName), mFormat(0) +{} + +void ContentSelectorModel::EsmFile::setFileName(const QString &fileName) +{ + mFileName = fileName; +} + +void ContentSelectorModel::EsmFile::setAuthor(const QString &author) +{ + mAuthor = author; +} + +void ContentSelectorModel::EsmFile::setDate(const QDateTime &modified) +{ + mModified = modified; +} + +void ContentSelectorModel::EsmFile::setFormat(int format) +{ + mFormat = format; +} + +void ContentSelectorModel::EsmFile::setPath(const QString &path) +{ + mPath = path; +} + +void ContentSelectorModel::EsmFile::setGameFiles(const QStringList &gamefiles) +{ + mGameFiles = gamefiles; +} + +void ContentSelectorModel::EsmFile::setDescription(const QString &description) +{ + mDescription = description; +} + +QByteArray ContentSelectorModel::EsmFile::encodedData() const +{ + QByteArray encodedData; + QDataStream stream(&encodedData, QIODevice::WriteOnly); + + stream << mFileName << mAuthor << QString::number(mFormat) + << mModified.toString() << mPath << mDescription + << mGameFiles; + + return encodedData; +} + +QVariant ContentSelectorModel::EsmFile::fileProperty(const FileProperty prop) const +{ + switch (prop) + { + case FileProperty_FileName: + return mFileName; + break; + + case FileProperty_Author: + return mAuthor; + break; + + case FileProperty_Format: + return mFormat; + break; + + case FileProperty_DateModified: + return mModified.toString(Qt::ISODate); + break; + + case FileProperty_Path: + return mPath; + break; + + case FileProperty_Description: + return mDescription; + break; + + case FileProperty_GameFile: + return mGameFiles; + break; + + default: + break; + } + return QVariant(); +} +void ContentSelectorModel::EsmFile::setFileProperty (const FileProperty prop, const QString &value) +{ + switch (prop) + { + case FileProperty_FileName: + mFileName = value; + break; + + case FileProperty_Author: + mAuthor = value; + break; + + case FileProperty_Format: + mFormat = value.toInt(); + break; + + case FileProperty_DateModified: + mModified = QDateTime::fromString(value); + break; + + case FileProperty_Path: + mPath = value; + break; + + case FileProperty_Description: + mDescription = value; + break; + + case FileProperty_GameFile: + mGameFiles << value; + break; + + default: + break; + } +} diff --git a/components/contentselector/model/esmfile.hpp b/components/contentselector/model/esmfile.hpp new file mode 100644 index 000000000..743b1c5a6 --- /dev/null +++ b/components/contentselector/model/esmfile.hpp @@ -0,0 +1,85 @@ +#ifndef ESMFILE_HPP +#define ESMFILE_HPP + +#include +#include + +#include "modelitem.hpp" + +class QMimeData; + +namespace ContentSelectorModel +{ + class EsmFile : public ModelItem + { + Q_OBJECT + Q_PROPERTY(QString filename READ fileName) + + public: + + enum FileProperty + { + FileProperty_FileName = 0, + FileProperty_Author = 1, + FileProperty_Format = 2, + FileProperty_DateModified = 3, + FileProperty_Path = 4, + FileProperty_Description = 5, + FileProperty_GameFile = 6 + }; + + EsmFile(QString fileName = QString(), ModelItem *parent = 0); + // EsmFile(const EsmFile &); + + ~EsmFile() + {} + + void setFileProperty (const FileProperty prop, const QString &value); + + void setFileName(const QString &fileName); + void setAuthor(const QString &author); + void setSize(const int size); + void setDate(const QDateTime &modified); + void setFormat(const int format); + void setPath(const QString &path); + void setGameFiles(const QStringList &gameFiles); + void setDescription(const QString &description); + + inline void addGameFile (const QString &name) {mGameFiles.append(name); } + QVariant fileProperty (const FileProperty prop) const; + + inline QString fileName() const { return mFileName; } + inline QString author() const { return mAuthor; } + inline QDateTime modified() const { return mModified; } + inline float format() const { return mFormat; } + inline QString path() const { return mPath; } + inline const QStringList &gameFiles() const { return mGameFiles; } + inline QString description() const { return mDescription; } + inline QString toolTip() const { return sToolTip.arg(mAuthor) + .arg(mFormat) + .arg(mDescription) + .arg(mGameFiles.join(", ")); + } + + inline bool isGameFile() const { return (mGameFiles.size() == 0); } + QByteArray encodedData() const; + + public: + static int sPropertyCount; + static QString sToolTip; + + private: + + QString mFileName; + QString mAuthor; + QDateTime mModified; + int mFormat; + QString mPath; + QStringList mGameFiles; + QString mDescription; + QString mToolTip; + + }; +} + +#endif diff --git a/components/contentselector/model/modelitem.cpp b/components/contentselector/model/modelitem.cpp new file mode 100644 index 000000000..e1d737c2d --- /dev/null +++ b/components/contentselector/model/modelitem.cpp @@ -0,0 +1,69 @@ +#include "modelitem.hpp" + +ContentSelectorModel::ModelItem::ModelItem(ModelItem *parent) + : mParentItem(parent) +{ +} +/* +ContentSelectorModel::ModelItem::ModelItem(const ModelItem *parent) + // : mParentItem(parent) +{ +} +*/ + +ContentSelectorModel::ModelItem::~ModelItem() +{ + qDeleteAll(mChildItems); +} + + +ContentSelectorModel::ModelItem *ContentSelectorModel::ModelItem::parent() const +{ + return mParentItem; +} + +bool ContentSelectorModel::ModelItem::hasFormat(const QString &mimetype) const +{ + if (mimetype == "application/omwcontent") + return true; + + return QMimeData::hasFormat(mimetype); +} +int ContentSelectorModel::ModelItem::row() const +{ + if (mParentItem) + return 1; + //return mParentItem->childRow(const_cast(this)); + //return mParentItem->mChildItems.indexOf(const_cast(this)); + + return -1; +} + + +int ContentSelectorModel::ModelItem::childCount() const +{ + return mChildItems.count(); +} + +int ContentSelectorModel::ModelItem::childRow(ModelItem *child) const +{ + Q_ASSERT(child); + + return mChildItems.indexOf(child); +} + +ContentSelectorModel::ModelItem *ContentSelectorModel::ModelItem::child(int row) +{ + return mChildItems.value(row); +} + + +void ContentSelectorModel::ModelItem::appendChild(ModelItem *item) +{ + mChildItems.append(item); +} + +void ContentSelectorModel::ModelItem::removeChild(int row) +{ + mChildItems.removeAt(row); +} diff --git a/components/contentselector/model/modelitem.hpp b/components/contentselector/model/modelitem.hpp new file mode 100644 index 000000000..57214b09c --- /dev/null +++ b/components/contentselector/model/modelitem.hpp @@ -0,0 +1,39 @@ +#ifndef MODELITEM_HPP +#define MODELITEM_HPP + +#include +#include + +namespace ContentSelectorModel +{ + class ModelItem : public QMimeData + { + Q_OBJECT + + public: + ModelItem(ModelItem *parent = 0); + //ModelItem(const ModelItem *parent = 0); + + ~ModelItem(); + + ModelItem *parent() const; + int row() const; + + int childCount() const; + int childRow(ModelItem *child) const; + ModelItem *child(int row); + + void appendChild(ModelItem *child); + void removeChild(int row); + + bool hasFormat(const QString &mimetype) const; + + //virtual bool acceptChild(ModelItem *child); + + protected: + ModelItem *mParentItem; + QList mChildItems; + }; +} + +#endif diff --git a/components/fileorderlist/utils/naturalsort.cpp b/components/contentselector/model/naturalsort.cpp similarity index 100% rename from components/fileorderlist/utils/naturalsort.cpp rename to components/contentselector/model/naturalsort.cpp diff --git a/components/contentselector/model/naturalsort.hpp b/components/contentselector/model/naturalsort.hpp new file mode 100644 index 000000000..8386e4e9f --- /dev/null +++ b/components/contentselector/model/naturalsort.hpp @@ -0,0 +1,11 @@ +#ifndef NATURALSORT_H +#define NATURALSORT_H + +#include + + bool naturalSortLessThanCS( const QString &left, const QString &right ); + bool naturalSortLessThanCI( const QString &left, const QString &right ); + bool naturalSortGreaterThanCS( const QString &left, const QString &right ); + bool naturalSortGreaterThanCI( const QString &left, const QString &right ); + +#endif diff --git a/components/fileorderlist/utils/comboboxlineedit.cpp b/components/contentselector/view/comboboxlineedit.cpp similarity index 83% rename from components/fileorderlist/utils/comboboxlineedit.cpp rename to components/contentselector/view/comboboxlineedit.cpp index 4d62e1399..df647a4a0 100644 --- a/components/fileorderlist/utils/comboboxlineedit.cpp +++ b/components/contentselector/view/comboboxlineedit.cpp @@ -3,7 +3,7 @@ #include "comboboxlineedit.hpp" -ComboBoxLineEdit::ComboBoxLineEdit(QWidget *parent) +ContentSelectorView::ComboBoxLineEdit::ComboBoxLineEdit(QWidget *parent) : QLineEdit(parent) { mClearButton = new QToolButton(this); @@ -21,7 +21,7 @@ ComboBoxLineEdit::ComboBoxLineEdit(QWidget *parent) setStyleSheet(QString("ComboBoxLineEdit { background-color: transparent; padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1)); } -void ComboBoxLineEdit::resizeEvent(QResizeEvent *) +void ContentSelectorView::ComboBoxLineEdit::resizeEvent(QResizeEvent *) { QSize sz = mClearButton->sizeHint(); int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); @@ -29,7 +29,7 @@ void ComboBoxLineEdit::resizeEvent(QResizeEvent *) (rect().bottom() + 1 - sz.height())/2); } -void ComboBoxLineEdit::updateClearButton(const QString& text) +void ContentSelectorView::ComboBoxLineEdit::updateClearButton(const QString& text) { mClearButton->setVisible(!text.isEmpty()); } diff --git a/components/fileorderlist/utils/comboboxlineedit.hpp b/components/contentselector/view/comboboxlineedit.hpp similarity index 56% rename from components/fileorderlist/utils/comboboxlineedit.hpp rename to components/contentselector/view/comboboxlineedit.hpp index ba10731ae..1aef2f57b 100644 --- a/components/fileorderlist/utils/comboboxlineedit.hpp +++ b/components/contentselector/view/comboboxlineedit.hpp @@ -14,22 +14,24 @@ class QToolButton; -class ComboBoxLineEdit : public QLineEdit +namespace ContentSelectorView { - Q_OBJECT + class ComboBoxLineEdit : public QLineEdit + { + Q_OBJECT -public: - ComboBoxLineEdit(QWidget *parent = 0); + public: + ComboBoxLineEdit(QWidget *parent = 0); -protected: - void resizeEvent(QResizeEvent *); + protected: + void resizeEvent(QResizeEvent *); -private slots: - void updateClearButton(const QString &text); - -private: - QToolButton *mClearButton; -}; + private slots: + void updateClearButton(const QString &text); + private: + QToolButton *mClearButton; + }; +} #endif // LIENEDIT_H diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp new file mode 100644 index 000000000..e6ed0ec56 --- /dev/null +++ b/components/contentselector/view/contentselector.cpp @@ -0,0 +1,137 @@ +#include "contentselector.hpp" + +#include "../model/contentmodel.hpp" +#include "../model/esmfile.hpp" + +#include + +#include +#include +#include + +ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : + QDialog(parent) +{ + setupUi(this); + + buildContentModel(); + buildGameFileView(); + buildAddonView(); + buildProfilesView(); + + updateViews(); + +} + +void ContentSelectorView::ContentSelector::buildContentModel() +{ + mContentModel = new ContentSelectorModel::ContentModel(); + connect(mContentModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); +} + +void ContentSelectorView::ContentSelector::buildGameFileView() +{ + mGameFileProxyModel = new QSortFilterProxyModel(this); + mGameFileProxyModel->setFilterRegExp(QString::number((int)ContentSelectorModel::ContentType_GameFile)); + mGameFileProxyModel->setFilterRole (Qt::UserRole); + mGameFileProxyModel->setSourceModel (mContentModel); + + gameFileView->setPlaceholderText(QString("Select a game file...")); + gameFileView->setModel(mGameFileProxyModel); + + connect(gameFileView, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentGameFileIndexChanged(int))); + connect(gameFileView, SIGNAL(currentIndexChanged(int)), this, SIGNAL(signalGameFileChanged(int))); + + gameFileView->setCurrentIndex(-1); + gameFileView->setCurrentIndex(0); +} + +void ContentSelectorView::ContentSelector::buildAddonView() +{ + mAddonProxyModel = new QSortFilterProxyModel(this); + mAddonProxyModel->setFilterRegExp (QString::number((int)ContentSelectorModel::ContentType_Addon)); + mAddonProxyModel->setFilterRole (Qt::UserRole); + mAddonProxyModel->setDynamicSortFilter (true); + mAddonProxyModel->setSourceModel (mContentModel); + + addonView->setModel(mAddonProxyModel); + + connect(addonView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(slotAddonTableItemClicked(const QModelIndex &))); +} + +void ContentSelectorView::ContentSelector::buildProfilesView() +{ + profilesComboBox->setPlaceholderText(QString("Select a profile...")); + connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentProfileIndexChanged(int))); +} + +void ContentSelectorView::ContentSelector::updateViews() +{ + // Ensure the columns are hidden because sort() re-enables them + addonView->setColumnHidden(1, true); + addonView->setColumnHidden(2, true); + addonView->setColumnHidden(3, true); + addonView->setColumnHidden(4, true); + addonView->setColumnHidden(5, true); + addonView->setColumnHidden(6, true); + addonView->setColumnHidden(7, true); + addonView->setColumnHidden(8, true); + addonView->resizeColumnsToContents(); +} + +void ContentSelectorView::ContentSelector::addFiles(const QString &path) +{ + mContentModel->addFiles(path); + //mContentModel->sort(3); // Sort by date accessed + gameFileView->setCurrentIndex(-1); + mContentModel->uncheckAll(); +} + +QStringList ContentSelectorView::ContentSelector::checkedItemsPaths() +{ + QStringList itemPaths; + + foreach( const ContentSelectorModel::EsmFile *file, mContentModel->checkedItems()) + itemPaths << file->path(); + + return itemPaths; +} + +void ContentSelectorView::ContentSelector::slotCurrentProfileIndexChanged(int index) +{ + emit profileChanged(index); +} + +void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int index) +{ + static int oldIndex = -1; + + QAbstractItemModel *const model = gameFileView->model(); + QSortFilterProxyModel *proxy = dynamic_cast(model); + + if (proxy) + proxy->setDynamicSortFilter(false); + + if (oldIndex > -1) + model->setData(model->index(oldIndex, 0), false, Qt::UserRole + 1); + + oldIndex = index; + + model->setData(model->index(index, 0), true, Qt::UserRole + 1); + + if (proxy) + proxy->setDynamicSortFilter(true); + + emit signalGameFileChanged(true); +} + +void ContentSelectorView::ContentSelector::slotAddonTableItemClicked(const QModelIndex &index) +{ + QAbstractItemModel *const model = addonView->model(); + //QSortFilterProxyModel *proxy = dynamic_cast(model); + + if (model->data(index, Qt::CheckStateRole).toInt() == Qt::Unchecked) + model->setData(index, Qt::Checked, Qt::CheckStateRole); + else + model->setData(index, Qt::Unchecked, Qt::CheckStateRole); +} diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp new file mode 100644 index 000000000..5af53dc46 --- /dev/null +++ b/components/contentselector/view/contentselector.hpp @@ -0,0 +1,53 @@ +#ifndef CONTENTSELECTOR_HPP +#define CONTENTSELECTOR_HPP + +#include + +#include "ui_datafilespage.h" + +namespace ContentSelectorModel { class ContentModel; } + +class QSortFilterProxyModel; + +namespace ContentSelectorView +{ + class ContentSelector : public QDialog, protected Ui::DataFilesPage + { + Q_OBJECT + + protected: + + ContentSelectorModel::ContentModel *mContentModel; + QSortFilterProxyModel *mGameFileProxyModel; + QSortFilterProxyModel *mAddonProxyModel; + + public: + + explicit ContentSelector(QWidget *parent = 0); + + static ContentSelector &cast(QWidget *subject); //static constructor function for singleton performance. + + void addFiles(const QString &path); + void setCheckState(QModelIndex index, QSortFilterProxyModel *model); + QStringList checkedItemsPaths(); + + private: + + void buildContentModel(); + void buildGameFileView(); + void buildAddonView(); + void buildProfilesView(); + + signals: + void profileChanged(int index); + void signalGameFileChanged(int value); + + private slots: + void updateViews(); + void slotCurrentProfileIndexChanged(int index); + void slotCurrentGameFileIndexChanged(int index); + void slotAddonTableItemClicked(const QModelIndex &index); + }; +} + +#endif // CONTENTSELECTOR_HPP diff --git a/components/fileorderlist/utils/lineedit.cpp b/components/contentselector/view/lineedit.cpp similarity index 85% rename from components/fileorderlist/utils/lineedit.cpp rename to components/contentselector/view/lineedit.cpp index b0f339589..b6fdfa805 100644 --- a/components/fileorderlist/utils/lineedit.cpp +++ b/components/contentselector/view/lineedit.cpp @@ -1,9 +1,10 @@ #include #include +#include #include "lineedit.hpp" -LineEdit::LineEdit(QWidget *parent) +ContentSelectorView::LineEdit::LineEdit(QWidget *parent) : QLineEdit(parent) { mClearButton = new QToolButton(this); @@ -24,7 +25,7 @@ LineEdit::LineEdit(QWidget *parent) qMax(msz.height(), mClearButton->sizeHint().height() + frameWidth * 2 + 2)); } -void LineEdit::resizeEvent(QResizeEvent *) +void ContentSelectorView::LineEdit::resizeEvent(QResizeEvent *) { QSize sz = mClearButton->sizeHint(); int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); @@ -32,7 +33,7 @@ void LineEdit::resizeEvent(QResizeEvent *) (rect().bottom() + 1 - sz.height())/2); } -void LineEdit::updateClearButton(const QString& text) +void ContentSelectorView::LineEdit::updateClearButton(const QString& text) { mClearButton->setVisible(!text.isEmpty()); } diff --git a/components/fileorderlist/utils/lineedit.hpp b/components/contentselector/view/lineedit.hpp similarity index 55% rename from components/fileorderlist/utils/lineedit.hpp rename to components/contentselector/view/lineedit.hpp index 14bd7b1b4..ab1c37203 100644 --- a/components/fileorderlist/utils/lineedit.hpp +++ b/components/contentselector/view/lineedit.hpp @@ -14,22 +14,26 @@ class QToolButton; -class LineEdit : public QLineEdit +namespace ContentSelectorView { - Q_OBJECT + class LineEdit : public QLineEdit + { + Q_OBJECT -public: - LineEdit(QWidget *parent = 0); + QString mPlaceholderText; -protected: - void resizeEvent(QResizeEvent *); + public: + LineEdit(QWidget *parent = 0); -private slots: - void updateClearButton(const QString &text); + protected: + void resizeEvent(QResizeEvent *); -private: - QToolButton *mClearButton; -}; + private slots: + void updateClearButton(const QString &text); + private: + QToolButton *mClearButton; + }; +} #endif // LIENEDIT_H diff --git a/components/fileorderlist/utils/profilescombobox.cpp b/components/contentselector/view/profilescombobox.cpp similarity index 65% rename from components/fileorderlist/utils/profilescombobox.cpp rename to components/contentselector/view/profilescombobox.cpp index c3ff953ae..cb0ba7b77 100644 --- a/components/fileorderlist/utils/profilescombobox.cpp +++ b/components/contentselector/view/profilescombobox.cpp @@ -7,7 +7,7 @@ #include "profilescombobox.hpp" #include "comboboxlineedit.hpp" -ProfilesComboBox::ProfilesComboBox(QWidget *parent) : +ContentSelectorView::ProfilesComboBox::ProfilesComboBox(QWidget *parent) : QComboBox(parent) { mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore @@ -21,7 +21,7 @@ ProfilesComboBox::ProfilesComboBox(QWidget *parent) : setInsertPolicy(QComboBox::NoInsert); } -void ProfilesComboBox::setEditEnabled(bool editable) +void ContentSelectorView::ProfilesComboBox::setEditEnabled(bool editable) { if (isEditable() == editable) return; @@ -47,7 +47,7 @@ void ProfilesComboBox::setEditEnabled(bool editable) SLOT(slotTextChanged(QString))); } -void ProfilesComboBox::slotTextChanged(const QString &text) +void ContentSelectorView::ProfilesComboBox::slotTextChanged(const QString &text) { QPalette *palette = new QPalette(); palette->setColor(QPalette::Text,Qt::red); @@ -61,7 +61,7 @@ void ProfilesComboBox::slotTextChanged(const QString &text) } } -void ProfilesComboBox::slotEditingFinished() +void ContentSelectorView::ProfilesComboBox::slotEditingFinished() { QString current = currentText(); QString previous = itemText(currentIndex()); @@ -82,7 +82,7 @@ void ProfilesComboBox::slotEditingFinished() emit(profileRenamed(previous, current)); } -void ProfilesComboBox::slotIndexChanged(int index) +void ContentSelectorView::ProfilesComboBox::slotIndexChanged(int index) { if (index == -1) return; @@ -90,3 +90,24 @@ void ProfilesComboBox::slotIndexChanged(int index) emit(profileChanged(mOldProfile, currentText())); mOldProfile = itemText(index); } + +void ContentSelectorView::ProfilesComboBox::paintEvent(QPaintEvent *) +{ + QStylePainter painter(this); + painter.setPen(palette().color(QPalette::Text)); + + // draw the combobox frame, focusrect and selected etc. + QStyleOptionComboBox opt; + initStyleOption(&opt); + painter.drawComplexControl(QStyle::CC_ComboBox, opt); + + // draw the icon and text + if (!opt.editable && currentIndex() == -1) // <<< we adjust the text displayed when nothing is selected + opt.currentText = mPlaceholderText; + painter.drawControl(QStyle::CE_ComboBoxLabel, opt); +} + +void ContentSelectorView::ProfilesComboBox::setPlaceholderText(const QString &text) +{ + mPlaceholderText = text; +} diff --git a/components/contentselector/view/profilescombobox.hpp b/components/contentselector/view/profilescombobox.hpp new file mode 100644 index 000000000..d81c1e6a5 --- /dev/null +++ b/components/contentselector/view/profilescombobox.hpp @@ -0,0 +1,38 @@ +#ifndef PROFILESCOMBOBOX_HPP +#define PROFILESCOMBOBOX_HPP + +#include +#include +class QString; +class QRegExpValidator; + +namespace ContentSelectorView +{ + class ProfilesComboBox : public QComboBox + { + Q_OBJECT + public: + explicit ProfilesComboBox(QWidget *parent = 0); + void setEditEnabled(bool editable); + void setPlaceholderText (const QString &text); + + signals: + void profileChanged(const QString &previous, const QString ¤t); + void profileRenamed(const QString &oldName, const QString &newName); + + private slots: + void slotEditingFinished(); + void slotIndexChanged(int index); + void slotTextChanged(const QString &text); + + private: + QString mOldProfile; + QString mPlaceholderText; + QRegExpValidator *mValidator; + + protected: + void paintEvent(QPaintEvent *); + }; +} + +#endif // PROFILESCOMBOBOX_HPP diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index edc724cd2..3bf194c4e 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -34,7 +34,7 @@ public: float getFVer() const { if(mHeader.mData.version == VER_12) return 1.2; else return 1.3; } const std::string getAuthor() const { return mHeader.mData.author.toString(); } const std::string getDesc() const { return mHeader.mData.desc.toString(); } - const std::vector &getMasters() const { return mHeader.mMaster; } + const std::vector &getGameFiles() const { return mHeader.mMaster; } int getFormat() const; const NAME &retSubName() const { return mCtx.subName; } uint32_t getSubSize() const { return mCtx.leftSub; } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 57d3278d8..9b3aa09e8 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -172,7 +172,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // If the most significant 8 bits are used, then this reference already exists. // In this case, do not spawn a new reference, but overwrite the old one. ref.mRefnum &= 0x00ffffff; // delete old plugin ID - const std::vector &masters = esm.getMasters(); + const std::vector &masters = esm.getGameFiles(); global = masters[local-1].index + 1; ref.mRefnum |= global << 24; // insert global plugin ID } @@ -276,7 +276,7 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) int local = (mref.mRefnum & 0xff000000) >> 24; size_t global = esm.getIndex() + 1; mref.mRefnum &= 0x00ffffff; // delete old plugin ID - const std::vector &masters = esm.getMasters(); + const std::vector &masters = esm.getGameFiles(); global = masters[local-1].index + 1; mref.mRefnum |= global << 24; // insert global plugin ID diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp deleted file mode 100644 index 02a6766b0..000000000 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ /dev/null @@ -1,445 +0,0 @@ -#include -#include -#include -#include - -#include - -#include - -#include "esm/esmfile.hpp" - -#include "datafilesmodel.hpp" - -#include - -DataFilesModel::DataFilesModel(QObject *parent) : - QAbstractTableModel(parent) -{ - mEncoding = QString("win1252"); -} - -DataFilesModel::~DataFilesModel() -{ -} - -void DataFilesModel::setEncoding(const QString &encoding) -{ - mEncoding = encoding; -} - -void DataFilesModel::setCheckState(const QModelIndex &index, Qt::CheckState state) -{ - setData(index, state, Qt::CheckStateRole); -} - -Qt::CheckState DataFilesModel::checkState(const QModelIndex &index) -{ - EsmFile *file = item(index.row()); - return mCheckStates[file->fileName()]; -} - -int DataFilesModel::columnCount(const QModelIndex &parent) const -{ - return parent.isValid() ? 0 : 9; -} - -int DataFilesModel::rowCount(const QModelIndex &parent) const -{ - return parent.isValid() ? 0 : mFiles.count(); -} - - -bool DataFilesModel::moveRow(int oldrow, int row, const QModelIndex &parent) -{ - if (oldrow < 0 || row < 0 || oldrow == row) - return false; - - emit layoutAboutToBeChanged(); - //emit beginMoveRows(parent, oldrow, oldrow, parent, row); - mFiles.swap(oldrow, row); - //emit endInsertRows(); - emit layoutChanged(); - - return true; -} - -QVariant DataFilesModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - EsmFile *file = item(index.row()); - - if (!file) - return QVariant(); - - const int column = index.column(); - - switch (role) { - case Qt::DisplayRole: { - - switch (column) { - case 0: - return file->fileName(); - case 1: - return file->author(); - case 2: - return QString("%1 kB").arg(int((file->size() + 1023) / 1024)); - case 3: - //return file->modified().toString(Qt::TextDate); - return file->modified().toString(Qt::ISODate); - case 4: - return file->accessed().toString(Qt::TextDate); - case 5: - return file->version(); - case 6: - return file->path(); - case 7: - return file->masters().join(", "); - case 8: - return file->description(); - } - } - - case Qt::TextAlignmentRole: { - switch (column) { - case 0: - case 1: - return Qt::AlignLeft + Qt::AlignVCenter; - case 2: - case 3: - case 4: - case 5: - return Qt::AlignRight + Qt::AlignVCenter; - default: - return Qt::AlignLeft + Qt::AlignVCenter; - } - } - - case Qt::CheckStateRole: { - if (column != 0) - return QVariant(); - return mCheckStates[file->fileName()]; - } - case Qt::ToolTipRole: - { - if (column != 0) - return QVariant(); - - if (file->version() == 0.0f) - return QVariant(); // Data not set - - QString tooltip = - QString("Author: %1
\ - Version: %2
\ -
Description:
%3
\ -
Dependencies: %4
") - .arg(file->author()) - .arg(QString::number(file->version())) - .arg(file->description()) - .arg(file->masters().join(", ")); - - - return tooltip; - - } - default: - return QVariant(); - } - -} - -Qt::ItemFlags DataFilesModel::flags(const QModelIndex &index) const -{ - if (!index.isValid()) - return Qt::NoItemFlags; - - EsmFile *file = item(index.row()); - - if (!file) - return Qt::NoItemFlags; - - if (canBeChecked(file)) { - if (index.column() == 0) { - return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; - } else { - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; - } - } else { - if (index.column() == 0) { - return Qt::ItemIsUserCheckable | Qt::ItemIsSelectable; - } else { - return Qt::NoItemFlags | Qt::ItemIsSelectable; - } - } - -} - -QVariant DataFilesModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (role != Qt::DisplayRole) - return QVariant(); - - if (orientation == Qt::Horizontal) { - switch (section) { - case 0: return tr("Name"); - case 1: return tr("Author"); - case 2: return tr("Size"); - case 3: return tr("Modified"); - case 4: return tr("Accessed"); - case 5: return tr("Version"); - case 6: return tr("Path"); - case 7: return tr("Masters"); - case 8: return tr("Description"); - } - } else { - // Show row numbers - return ++section; - } - - return QVariant(); -} - -bool DataFilesModel::setData(const QModelIndex &index, const QVariant &value, int role) -{ - if (!index.isValid()) - return false; - - if (role == Qt::CheckStateRole) { - QString name = item(index.row())->fileName(); - mCheckStates[name] = static_cast(value.toInt()); - - // Force a redraw of the view since unchecking one item can affect another - QModelIndex firstIndex = indexFromItem(mFiles.first()); - QModelIndex lastIndex = indexFromItem(mFiles.last()); - - emit dataChanged(firstIndex, lastIndex); - emit checkedItemsChanged(checkedItems()); - return true; - } - - return false; -} - -bool lessThanEsmFile(const EsmFile *e1, const EsmFile *e2) -{ - //Masters first then alphabetically - if (e1->fileName().endsWith(".esm") && !e2->fileName().endsWith(".esm")) - return true; - if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm")) - return false; - - return e1->fileName().toLower() < e2->fileName().toLower(); -} - -bool lessThanDate(const EsmFile *e1, const EsmFile *e2) -{ - if (e1->modified().toString(Qt::ISODate) < e2->modified().toString(Qt::ISODate)) { - return true; - } else { - return false; - } -} - -void DataFilesModel::sort(int column, Qt::SortOrder order) -{ - emit layoutAboutToBeChanged(); - - if (column == 3) { - qSort(mFiles.begin(), mFiles.end(), lessThanDate); - } else { - qSort(mFiles.begin(), mFiles.end(), lessThanEsmFile); - } - - emit layoutChanged(); -} - -void DataFilesModel::addFile(EsmFile *file) -{ - emit beginInsertRows(QModelIndex(), mFiles.count(), mFiles.count()); - mFiles.append(file); - emit endInsertRows(); -} - -void DataFilesModel::addFiles(const QString &path) -{ - QDir dir(path); - QStringList filters; - filters << "*.esp" << "*.esm"; - dir.setNameFilters(filters); - - // Create a decoder for non-latin characters in esx metadata - QTextCodec *codec; - - if (mEncoding == QLatin1String("win1252")) { - codec = QTextCodec::codecForName("windows-1252"); - } else if (mEncoding == QLatin1String("win1251")) { - codec = QTextCodec::codecForName("windows-1251"); - } else if (mEncoding == QLatin1String("win1250")) { - codec = QTextCodec::codecForName("windows-1250"); - } else { - return; // This should never happen; - } - - QTextDecoder *decoder = codec->makeDecoder(); - - foreach (const QString &path, dir.entryList()) { - QFileInfo info(dir.absoluteFilePath(path)); - EsmFile *file = new EsmFile(path); - - try { - ESM::ESMReader fileReader; - ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding.toStdString())); - fileReader.setEncoder(&encoder); - fileReader.open(dir.absoluteFilePath(path).toStdString()); - - std::vector mlist = fileReader.getMasters(); - - QStringList masters; - - for (unsigned int i = 0; i < mlist.size(); ++i) { - QString master = QString::fromStdString(mlist[i].name); - masters.append(master); - } - - file->setAuthor(decoder->toUnicode(fileReader.getAuthor().c_str())); - file->setSize(info.size()); - file->setDates(info.lastModified(), info.lastRead()); - file->setVersion(fileReader.getFVer()); - file->setPath(info.absoluteFilePath()); - file->setMasters(masters); - file->setDescription(decoder->toUnicode(fileReader.getDesc().c_str())); - - - // Put the file in the table - if (findItem(path) == 0) - addFile(file); - } catch(std::runtime_error &e) { - // An error occurred while reading the .esp - qWarning() << "Error reading esp: " << e.what(); - continue; - } - - } - - delete decoder; -} - -QModelIndex DataFilesModel::indexFromItem(EsmFile *item) const -{ - if (item) - return createIndex(mFiles.indexOf(item), 0); - - return QModelIndex(); -} - -EsmFile* DataFilesModel::findItem(const QString &name) -{ - QList::ConstIterator it; - QList::ConstIterator itEnd = mFiles.constEnd(); - - int i = 0; - for (it = mFiles.constBegin(); it != itEnd; ++it) { - EsmFile *file = item(i); - ++i; - - if (name == file->fileName()) - return file; - } - - // Not found - return 0; -} - -EsmFile* DataFilesModel::item(int row) const -{ - if (row >= 0 && row < mFiles.count()) - return mFiles.at(row); - else - return 0; -} - -QStringList DataFilesModel::checkedItems() -{ - QStringList list; - - QList::ConstIterator it; - QList::ConstIterator itEnd = mFiles.constEnd(); - - int i = 0; - for (it = mFiles.constBegin(); it != itEnd; ++it) { - EsmFile *file = item(i); - ++i; - - QString name = file->fileName(); - - // Only add the items that are in the checked list and available - if (mCheckStates[name] == Qt::Checked && canBeChecked(file)) - list << name; - } - - return list; -} - -QStringList DataFilesModel::checkedItemsPaths() -{ - QStringList list; - - QList::ConstIterator it; - QList::ConstIterator itEnd = mFiles.constEnd(); - - int i = 0; - for (it = mFiles.constBegin(); it != itEnd; ++it) { - EsmFile *file = item(i); - ++i; - - if (mCheckStates[file->fileName()] == Qt::Checked && canBeChecked(file)) - list << file->path(); - } - - return list; -} - -void DataFilesModel::uncheckAll() -{ - emit layoutAboutToBeChanged(); - mCheckStates.clear(); - emit layoutChanged(); -} - -QStringList DataFilesModel::uncheckedItems() -{ - QStringList list; - QStringList checked = checkedItems(); - - QList::ConstIterator it; - QList::ConstIterator itEnd = mFiles.constEnd(); - - int i = 0; - for (it = mFiles.constBegin(); it != itEnd; ++it) { - EsmFile *file = item(i); - ++i; - - // Add the items that are not in the checked list - if (!checked.contains(file->fileName())) - list << file->fileName(); - } - - return list; -} - -bool DataFilesModel::canBeChecked(EsmFile *file) const -{ - //element can be checked if all its dependencies are - bool canBeChecked = true; - foreach (const QString &master, file->masters()) - { - if (!mCheckStates.contains(master) || mCheckStates[master] != Qt::Checked) - { - canBeChecked = false; - break; - } - } - return canBeChecked; -} diff --git a/components/fileorderlist/model/datafilesmodel.hpp b/components/fileorderlist/model/datafilesmodel.hpp deleted file mode 100644 index 0a07a536f..000000000 --- a/components/fileorderlist/model/datafilesmodel.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef DATAFILESMODEL_HPP -#define DATAFILESMODEL_HPP - -#include -#include -#include -#include - - -class EsmFile; - -class DataFilesModel : public QAbstractTableModel -{ - Q_OBJECT - -public: - explicit DataFilesModel(QObject *parent = 0); - virtual ~DataFilesModel(); - virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; - - bool moveRow(int oldrow, int row, const QModelIndex &parent = QModelIndex()); - - virtual Qt::ItemFlags flags(const QModelIndex &index) const; - - virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) 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); - void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); - - inline QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const - { return QAbstractTableModel::index(row, column, parent); } - - void setEncoding(const QString &encoding); - - void addFiles(const QString &path); - - void uncheckAll(); - - QStringList checkedItems(); - QStringList uncheckedItems(); - QStringList checkedItemsPaths(); - - Qt::CheckState checkState(const QModelIndex &index); - void setCheckState(const QModelIndex &index, Qt::CheckState state); - - QModelIndex indexFromItem(EsmFile *item) const; - EsmFile* findItem(const QString &name); - EsmFile* item(int row) const; - -signals: - void checkedItemsChanged(const QStringList &items); - -private: - bool canBeChecked(EsmFile *file) const; - void addFile(EsmFile *file); - - QList mFiles; - QHash mCheckStates; - - QString mEncoding; - -}; - -#endif // DATAFILESMODEL_HPP diff --git a/components/fileorderlist/model/esm/esmfile.cpp b/components/fileorderlist/model/esm/esmfile.cpp deleted file mode 100644 index 93d83091e..000000000 --- a/components/fileorderlist/model/esm/esmfile.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "esmfile.hpp" - -EsmFile::EsmFile(QString fileName, ModelItem *parent) - : ModelItem(parent) -{ - mFileName = fileName; - mSize = 0; - mVersion = 0.0f; -} - -void EsmFile::setFileName(const QString &fileName) -{ - mFileName = fileName; -} - -void EsmFile::setAuthor(const QString &author) -{ - mAuthor = author; -} - -void EsmFile::setSize(const int size) -{ - mSize = size; -} - -void EsmFile::setDates(const QDateTime &modified, const QDateTime &accessed) -{ - mModified = modified; - mAccessed = accessed; -} - -void EsmFile::setVersion(float version) -{ - mVersion = version; -} - -void EsmFile::setPath(const QString &path) -{ - mPath = path; -} - -void EsmFile::setMasters(const QStringList &masters) -{ - mMasters = masters; -} - -void EsmFile::setDescription(const QString &description) -{ - mDescription = description; -} diff --git a/components/fileorderlist/model/esm/esmfile.hpp b/components/fileorderlist/model/esm/esmfile.hpp deleted file mode 100644 index 52b3fbd00..000000000 --- a/components/fileorderlist/model/esm/esmfile.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef ESMFILE_HPP -#define ESMFILE_HPP - -#include -#include - -#include "../modelitem.hpp" - -class EsmFile : public ModelItem -{ - Q_OBJECT - Q_PROPERTY(QString filename READ fileName) - -public: - EsmFile(QString fileName = QString(), ModelItem *parent = 0); - - ~EsmFile() - {} - - void setFileName(const QString &fileName); - void setAuthor(const QString &author); - void setSize(const int size); - void setDates(const QDateTime &modified, const QDateTime &accessed); - void setVersion(const float version); - void setPath(const QString &path); - void setMasters(const QStringList &masters); - void setDescription(const QString &description); - - inline QString fileName() const { return mFileName; } - inline QString author() const { return mAuthor; } - inline int size() const { return mSize; } - inline QDateTime modified() const { return mModified; } - inline QDateTime accessed() const { return mAccessed; } - inline float version() const { return mVersion; } - inline QString path() const { return mPath; } - inline QStringList masters() const { return mMasters; } - inline QString description() const { return mDescription; } - - -private: - QString mFileName; - QString mAuthor; - int mSize; - QDateTime mModified; - QDateTime mAccessed; - float mVersion; - QString mPath; - QStringList mMasters; - QString mDescription; - -}; - - -#endif diff --git a/components/fileorderlist/model/modelitem.cpp b/components/fileorderlist/model/modelitem.cpp deleted file mode 100644 index 0ff7e45cb..000000000 --- a/components/fileorderlist/model/modelitem.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "modelitem.hpp" - -ModelItem::ModelItem(ModelItem *parent) - : mParentItem(parent) - , QObject(parent) -{ -} - -ModelItem::~ModelItem() -{ - qDeleteAll(mChildItems); -} - - -ModelItem *ModelItem::parent() -{ - return mParentItem; -} - -int ModelItem::row() const -{ - if (mParentItem) - return 1; - //return mParentItem->childRow(const_cast(this)); - //return mParentItem->mChildItems.indexOf(const_cast(this)); - - return -1; -} - - -int ModelItem::childCount() const -{ - return mChildItems.count(); -} - -int ModelItem::childRow(ModelItem *child) const -{ - Q_ASSERT(child); - - return mChildItems.indexOf(child); -} - -ModelItem *ModelItem::child(int row) -{ - return mChildItems.value(row); -} - - -void ModelItem::appendChild(ModelItem *item) -{ - mChildItems.append(item); -} - -void ModelItem::removeChild(int row) -{ - mChildItems.removeAt(row); -} diff --git a/components/fileorderlist/model/modelitem.hpp b/components/fileorderlist/model/modelitem.hpp deleted file mode 100644 index f4cb4322f..000000000 --- a/components/fileorderlist/model/modelitem.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef MODELITEM_HPP -#define MODELITEM_HPP - -#include -#include - -class ModelItem : public QObject -{ - Q_OBJECT - -public: - ModelItem(ModelItem *parent = 0); - ~ModelItem(); - - ModelItem *parent(); - int row() const; - - int childCount() const; - int childRow(ModelItem *child) const; - ModelItem *child(int row); - - void appendChild(ModelItem *child); - void removeChild(int row); - - //virtual bool acceptChild(ModelItem *child); - -protected: - ModelItem *mParentItem; - QList mChildItems; -}; - -#endif diff --git a/components/fileorderlist/model/pluginsproxymodel.cpp b/components/fileorderlist/model/pluginsproxymodel.cpp deleted file mode 100644 index 6be152b55..000000000 --- a/components/fileorderlist/model/pluginsproxymodel.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "pluginsproxymodel.hpp" - -PluginsProxyModel::PluginsProxyModel(QObject *parent) : - QSortFilterProxyModel(parent) -{ -} - -PluginsProxyModel::~PluginsProxyModel() -{ -} - -QVariant PluginsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (orientation != Qt::Vertical || role != Qt::DisplayRole) - return QSortFilterProxyModel::headerData(section, orientation, role); - return section + 1; -} diff --git a/components/fileorderlist/model/pluginsproxymodel.hpp b/components/fileorderlist/model/pluginsproxymodel.hpp deleted file mode 100644 index 8fde73236..000000000 --- a/components/fileorderlist/model/pluginsproxymodel.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef PLUGINSPROXYMODEL_HPP -#define PLUGINSPROXYMODEL_HPP - -#include - -class QVariant; - -class PluginsProxyModel : public QSortFilterProxyModel -{ - Q_OBJECT -public: - explicit PluginsProxyModel(QObject *parent = 0); - ~PluginsProxyModel(); - - QVariant headerData(int section, Qt::Orientation orientation, int role) const; -}; - -#endif // PLUGINSPROXYMODEL_HPP diff --git a/components/fileorderlist/utils/naturalsort.hpp b/components/fileorderlist/utils/naturalsort.hpp deleted file mode 100644 index 59271547a..000000000 --- a/components/fileorderlist/utils/naturalsort.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef NATURALSORT_H -#define NATURALSORT_H - -#include - -bool naturalSortLessThanCS( const QString &left, const QString &right ); -bool naturalSortLessThanCI( const QString &left, const QString &right ); -bool naturalSortGreaterThanCS( const QString &left, const QString &right ); -bool naturalSortGreaterThanCI( const QString &left, const QString &right ); - -#endif diff --git a/components/fileorderlist/utils/profilescombobox.hpp b/components/fileorderlist/utils/profilescombobox.hpp deleted file mode 100644 index 08ead9a7a..000000000 --- a/components/fileorderlist/utils/profilescombobox.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef PROFILESCOMBOBOX_HPP -#define PROFILESCOMBOBOX_HPP - -#include - -class QString; -class QRegExpValidator; - -class ProfilesComboBox : public QComboBox -{ - Q_OBJECT -public: - explicit ProfilesComboBox(QWidget *parent = 0); - void setEditEnabled(bool editable); - -signals: - void profileChanged(const QString &previous, const QString ¤t); - void profileRenamed(const QString &oldName, const QString &newName); - -private slots: - void slotEditingFinished(); - void slotIndexChanged(int index); - void slotTextChanged(const QString &text); - -private: - QString mOldProfile; - QRegExpValidator *mValidator; -}; - -#endif // PROFILESCOMBOBOX_HPP diff --git a/credits.txt b/credits.txt index 9a84c5327..c766c34c3 100644 --- a/credits.txt +++ b/credits.txt @@ -47,6 +47,7 @@ Marc Bouvier (CramitDeFrog) Marcin Hulist (Gohan) Mark Siewert (mark76) Mateusz Kołaczek (PL_kolek) +Michael Hogan (Xethik) Michael Mc Donnell Michael Papageorgiou (werdanith) Michał Bień (Glorf) diff --git a/files/ui/datafilespage.ui b/files/ui/datafilespage.ui index 041a9576d..949407759 100644 --- a/files/ui/datafilespage.ui +++ b/files/ui/datafilespage.ui @@ -7,107 +7,260 @@ 0 0 518 - 304 + 313 + + + 0 + 0 + + + + Qt::DefaultContextMenu + - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Filter: - - - - - - - + + + Content + + + + + + + + false + + + + + + + + + + + + 0 + 0 + + + + Qt::DefaultContextMenu + + + true + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + QAbstractItemView::DragDrop + + + Qt::MoveAction + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + Qt::ElideLeft + + + false + + + false + + + true + + + false + + + + + + + + + - + - + 0 0 - - Qt::Horizontal + + Project - - false + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + + 0 + + + 0 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Open + + + + + + + false + + + Create + + + + - - - - - Current Profile: - - - - - - - true - - - - 0 - 0 - - - - - - - - New Profile - - - &New Profile - - - true - - - - - - - Delete Profile - - - Delete Profile - - - Ctrl+D - - - true - - - - + + + + 1 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + + 0 + + + 0 + + + + + + + + Qt::NoFocus + + + Profile + + + false + + + + 6 + + + 3 + + + 9 + + + 0 + + + 6 + + + + + true + + + + 0 + 0 + + + + + + + + New Profile + + + &New Profile + + + true + + + + + + + Delete Profile + + + Delete Profile + + + Ctrl+D + + + true + + + + + @@ -140,6 +293,9 @@ + + true + Check Selection @@ -152,14 +308,9 @@ - LineEdit - QLineEdit -
components/fileorderlist/utils/lineedit.hpp
-
- - ProfilesComboBox + ContentSelectorView::ProfilesComboBox QComboBox -
components/fileorderlist/utils/profilescombobox.hpp
+
components/contentselector/view/profilescombobox.hpp