Renamed esxSelector to contentSelector
Fixed datafilespage model implementation in launcher Filtered addons in table view by selected game fileactorid
parent
7b7dfa122d
commit
cfdc19c427
@ -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<ModelItem*>(this));
|
||||
//return mParentItem->mChildItems.indexOf(const_cast<ModelItem*>(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);
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
#include "contentselector.hpp"
|
||||
|
||||
#include "../model/contentmodel.hpp"
|
||||
#include "../model/esmfile.hpp"
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMenu>
|
||||
#include <QContextMenuEvent>
|
||||
|
||||
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)));
|
||||
|
||||
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<QSortFilterProxyModel *>(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 ContentSelectorView::ContentSelector::slotAddonTableItemClicked(const QModelIndex &index)
|
||||
{
|
||||
QAbstractItemModel *const model = addonView->model();
|
||||
QSortFilterProxyModel *proxy = dynamic_cast<QSortFilterProxyModel *>(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);
|
||||
}
|
@ -1,608 +0,0 @@
|
||||
#include <QTextDecoder>
|
||||
#include <QTextCodec>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QtAlgorithms>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
|
||||
#include "esmfile.hpp"
|
||||
|
||||
#include "datafilesmodel.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
EsxModel::DataFilesModel::DataFilesModel(QObject *parent) :
|
||||
QAbstractTableModel(parent)
|
||||
{
|
||||
mEncoding = QString("win1252");
|
||||
}
|
||||
|
||||
EsxModel::DataFilesModel::~DataFilesModel()
|
||||
{
|
||||
}
|
||||
|
||||
int EsxModel::DataFilesModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : mFiles.count();
|
||||
}
|
||||
|
||||
int EsxModel::DataFilesModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : 1;
|
||||
}
|
||||
|
||||
const EsxModel::EsmFile* EsxModel::DataFilesModel::findItem(const QString &name)
|
||||
{
|
||||
for (int i = 0; i < mFiles.size(); ++i)
|
||||
{
|
||||
const EsmFile *file = item(i);
|
||||
|
||||
if (name == file->fileName())
|
||||
return file;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const EsxModel::EsmFile* EsxModel::DataFilesModel::item(int row) const
|
||||
{
|
||||
if (row >= 0 && row < mFiles.count())
|
||||
return mFiles.at(row);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Qt::ItemFlags EsxModel::DataFilesModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
const EsmFile *file = item(index.row());
|
||||
|
||||
if (!file)
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
Qt::ItemFlags dragDropFlags = Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
|
||||
Qt::ItemFlags checkFlags = Qt::ItemIsUserCheckable | Qt::ItemIsEditable;
|
||||
Qt::ItemFlags defaultFlags = Qt::ItemIsDropEnabled | Qt::ItemIsSelectable;
|
||||
|
||||
if (canBeChecked(file))
|
||||
return defaultFlags | dragDropFlags | checkFlags | Qt::ItemIsEnabled;
|
||||
else
|
||||
return defaultFlags;
|
||||
}
|
||||
|
||||
QVariant EsxModel::DataFilesModel::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:
|
||||
{
|
||||
|
||||
switch (column)
|
||||
{
|
||||
case 0:
|
||||
return file->fileName();
|
||||
case 1:
|
||||
return file->author();
|
||||
case 2:
|
||||
return file->modified().toString(Qt::ISODate);
|
||||
case 3:
|
||||
return file->version();
|
||||
case 4:
|
||||
return file->path();
|
||||
case 5:
|
||||
return file->masters().join(", ");
|
||||
case 6:
|
||||
return file->description();
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::ToolTipRole:
|
||||
{
|
||||
if (column != 0)
|
||||
return QVariant();
|
||||
|
||||
if (file->version() == 0.0f)
|
||||
return QVariant(); // Data not set
|
||||
|
||||
QString tooltip =
|
||||
QString("<b>Author:</b> %1<br/> \
|
||||
<b>Version:</b> %2<br/> \
|
||||
<br/><b>Description:</b><br/>%3<br/> \
|
||||
<br/><b>Dependencies: </b>%4<br/>")
|
||||
.arg(file->author())
|
||||
.arg(QString::number(file->version()))
|
||||
.arg(file->description())
|
||||
.arg(file->masters().join(", "));
|
||||
|
||||
|
||||
return tooltip;
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::UserRole:
|
||||
{
|
||||
if (file->masters().size() == 0)
|
||||
return "game";
|
||||
else
|
||||
return "addon";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::UserRole + 1:
|
||||
//return check state here
|
||||
break;
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool EsxModel::DataFilesModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return false;
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::EditRole:
|
||||
{
|
||||
const EsmFile *file = item(index.row());
|
||||
|
||||
// iterate loop to repopulate file pointer with data in string list.
|
||||
QStringList list = value.toStringList();
|
||||
for (int i = 0; i <999; ++i)
|
||||
{
|
||||
file->setProperty(i, value.at(i));
|
||||
}
|
||||
|
||||
//populate master list here (emit data changed for each master and
|
||||
//each item (other than the dropped item) which share each of the masters
|
||||
file->masters().append(masterList);
|
||||
|
||||
emit dataChanged(index, index);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::UserRole + 1:
|
||||
{
|
||||
EsmFile *file = item(index.row());
|
||||
//set file's checkstate to the passed checkstate
|
||||
emit dataChanged(index, index);
|
||||
|
||||
for (int i = 0; i < mFiles.size(); ++i)
|
||||
if (mFiles.at(i)->getMasters().contains(file->fileName()))
|
||||
emit dataChanged(QAbstractTableModel::index(i,0), QAbstractTableModel::index(i,0));
|
||||
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::CheckStateRole:
|
||||
{
|
||||
EsmFile *file = item(index.row());
|
||||
|
||||
if ((value.toInt() == Qt::Checked) && !file->isChecked())
|
||||
file->setChecked(true);
|
||||
else if (value.toInt() == Qt::Checked && file->isChecked())
|
||||
file->setChecked(false);
|
||||
else if (value.toInt() == Qt::UnChecked)
|
||||
file->setChecked(false);
|
||||
|
||||
emit dataChanged(index, index);
|
||||
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EsxModel::DataFilesModel::insertRows(int row, int count, const QModelIndex &parent)
|
||||
{
|
||||
if (parent.isValid())
|
||||
return false;
|
||||
|
||||
beginInsertRows(QModelIndex(),row, row+count-1);
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
mFiles.insert(row, new EsmFile());
|
||||
} endInsertRows();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EsxModel::DataFilesModel::removeRows(int row, int count, const QModelIndex &parent)
|
||||
{
|
||||
if (parent.isValid())
|
||||
return false;
|
||||
|
||||
beginRemoveRows(QModelIndex(), row, row+count-1);
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
delete mFiles.takeAt(row);
|
||||
} endRemoveRows();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Qt::DropActions EsxModel::DataFilesModel::supportedDropActions() const
|
||||
{
|
||||
return Qt::CopyAction | Qt::MoveAction;
|
||||
}
|
||||
|
||||
QStringList EsxModel::DataFilesModel::mimeTypes() const
|
||||
{
|
||||
QStringList types;
|
||||
types << "application/omwcontent";
|
||||
return types;
|
||||
}
|
||||
|
||||
QMimeData *EsxModel::DataFilesModel::mimeData(const QModelIndexList &indexes) const
|
||||
{
|
||||
QMimeData *mimeData = new QMimeData();
|
||||
QByteArray encodedData;
|
||||
|
||||
QDataStream stream (&encodedData, QIODevice::WriteOnly);
|
||||
|
||||
foreach (const QModelIndex &index, indexes)
|
||||
{
|
||||
if (index.isValid())
|
||||
{
|
||||
EsmFile *file = item (index.row());
|
||||
|
||||
for (int i = 0; i < file->propertyCount(); ++i)
|
||||
stream << data(index, Qt::DisplayRole).toString();
|
||||
|
||||
EsmFile *file = item(index.row());
|
||||
stream << file->getMasters();
|
||||
}
|
||||
}
|
||||
|
||||
mimeData->setData("application/omwcontent", encodedData);
|
||||
|
||||
return mimeData;
|
||||
}
|
||||
|
||||
bool EsxModel::DataFilesModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
|
||||
{
|
||||
if (action == Qt::IgnoreAction)
|
||||
return true;
|
||||
|
||||
if (action != Qt::MoveAction)
|
||||
return false;
|
||||
|
||||
if (!data->hasFormat("application/omwcontent"))
|
||||
return false;
|
||||
|
||||
int dropRow = row;
|
||||
|
||||
if (dropRow == -1)
|
||||
{
|
||||
if (parent.isValid())
|
||||
dropRow = parent.row();
|
||||
else
|
||||
dropRow = rowCount(QModelIndex());
|
||||
}
|
||||
|
||||
if (parent.isValid())
|
||||
qDebug() << "parent: " << parent.data().toString();
|
||||
qDebug() << "dragged file: " << (qobject_cast<const EsmFile *>(data))->fileName();
|
||||
// qDebug() << "inserting file: " << droppedfile->fileName() << " ahead of " << file->fileName();
|
||||
insertRows (dropRow, 1, QModelIndex());
|
||||
|
||||
|
||||
const EsmFile *draggedFile = qobject_cast<const EsmFile *>(data);
|
||||
|
||||
int dragRow = -1;
|
||||
|
||||
for (int i = 0; i < mFiles.size(); ++i)
|
||||
if (draggedFile->fileName() == mFiles.at(i)->fileName())
|
||||
{
|
||||
dragRow = i;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mFiles.count(); ++i)
|
||||
{
|
||||
qDebug() << "index: " << i << "file: " << item(i)->fileName();
|
||||
qDebug() << mFiles.at(i)->fileName();
|
||||
}
|
||||
|
||||
qDebug() << "drop row: " << dropRow << "; drag row: " << dragRow;
|
||||
// const EsmFile *file = qobject_cast<const EsmFile *>(data);
|
||||
// int index = mFiles.indexOf(file);
|
||||
//qDebug() << "file name: " << file->fileName() << "; index: " << index;
|
||||
mFiles.swap(dropRow, dragRow);
|
||||
//setData(index(startRow, 0), varFile);
|
||||
emit dataChanged(index(0,0), index(rowCount(),0));
|
||||
return true;
|
||||
}
|
||||
|
||||
void EsxModel::DataFilesModel::setEncoding(const QString &encoding)
|
||||
{
|
||||
mEncoding = encoding;
|
||||
}
|
||||
|
||||
void EsxModel::DataFilesModel::setCheckState(const QModelIndex &index, Qt::CheckState state)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
QString name = item(index.row())->fileName();
|
||||
mCheckStates[name] = state;
|
||||
|
||||
// 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());
|
||||
|
||||
}
|
||||
|
||||
Qt::CheckState EsxModel::DataFilesModel::checkState(const QModelIndex &index)
|
||||
{
|
||||
return mCheckStates[item(index.row())->fileName()];
|
||||
}
|
||||
|
||||
bool EsxModel::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 EsxModel::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");
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
//!!!!!!!!!!!!!!!!!!!!!!!
|
||||
bool lessThanEsmFile(const EsxModel::EsmFile *e1, const EsxModel::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 EsxModel::EsmFile *e1, const EsxModel::EsmFile *e2)
|
||||
{
|
||||
if (e1->modified().toString(Qt::ISODate) < e2->modified().toString(Qt::ISODate))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
//!!!!!!!!!!!!!!!!!!!!!!!
|
||||
void EsxModel::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 EsxModel::DataFilesModel::addFile(const EsmFile *file)
|
||||
{
|
||||
emit beginInsertRows(QModelIndex(), mFiles.count(), mFiles.count());
|
||||
mFiles.append(file);
|
||||
emit endInsertRows();
|
||||
}
|
||||
|
||||
void EsxModel::DataFilesModel::addFiles(const QString &path)
|
||||
{
|
||||
QDir dir(path);
|
||||
QStringList filters;
|
||||
filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon";
|
||||
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<ESM::Header::MasterData> 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 addon file: " << e.what();
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete decoder;
|
||||
}
|
||||
|
||||
QModelIndex EsxModel::DataFilesModel::indexFromItem(const EsmFile *item) const
|
||||
{
|
||||
if (item)
|
||||
//return createIndex(mFiles.indexOf(item), 0);
|
||||
return index(mFiles.indexOf(item),0);
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
EsxModel::EsmFileList EsxModel::DataFilesModel::checkedItems()
|
||||
{
|
||||
EsmFileList list;
|
||||
|
||||
EsmFileList::ConstIterator it;
|
||||
EsmFileList::ConstIterator itEnd = mFiles.constEnd();
|
||||
|
||||
for (it = mFiles.constBegin(); it != itEnd; ++it)
|
||||
{
|
||||
// Only add the items that are in the checked list and available
|
||||
if (mCheckStates[(*it)->fileName()] == Qt::Checked && canBeChecked(*it))
|
||||
list << (*it);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
QStringList EsxModel::DataFilesModel::checkedItemsPaths()
|
||||
{
|
||||
QStringList list;
|
||||
|
||||
EsmFileList::ConstIterator it;
|
||||
EsmFileList::ConstIterator itEnd = mFiles.constEnd();
|
||||
|
||||
int i = 0;
|
||||
for (it = mFiles.constBegin(); it != itEnd; ++it) {
|
||||
const EsmFile *file = item(i);
|
||||
++i;
|
||||
|
||||
if (mCheckStates[file->fileName()] == Qt::Checked && canBeChecked(file))
|
||||
list << file->path();
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
void EsxModel::DataFilesModel::uncheckAll()
|
||||
{
|
||||
emit layoutAboutToBeChanged();
|
||||
mCheckStates.clear();
|
||||
emit layoutChanged();
|
||||
}
|
||||
|
||||
/*
|
||||
EsxModel::EsmFileList EsxModel::DataFilesModel::uncheckedItems()
|
||||
{
|
||||
EsmFileList list;
|
||||
EsmFileList checked = checkedItems();
|
||||
|
||||
EsmFileList::ConstIterator it;
|
||||
|
||||
for (it = mFiles.constBegin(); it != mFiles.constEnd(); ++it)
|
||||
{
|
||||
const EsmFile *file = *it;
|
||||
|
||||
// Add the items that are not in the checked list
|
||||
if (!checked.contains(file))
|
||||
list << file;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
*/
|
||||
bool EsxModel::DataFilesModel::canBeChecked(const EsmFile *file) const
|
||||
{
|
||||
//element can be checked if all its dependencies are
|
||||
foreach (const QString &master, file->masters())
|
||||
{
|
||||
if (!mCheckStates.contains(master) || mCheckStates[master] != Qt::Checked)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
#ifndef DATAFILESMODEL_HPP
|
||||
#define DATAFILESMODEL_HPP
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
|
||||
namespace EsxModel
|
||||
{
|
||||
class EsmFile;
|
||||
|
||||
typedef QList<const EsmFile *> EsmFileList;
|
||||
|
||||
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 removeRows(int row, int count, const QModelIndex &parent);
|
||||
bool insertRows(int row, int count, const QModelIndex &parent);
|
||||
|
||||
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
|
||||
{
|
||||
QModelIndex idx = QAbstractTableModel::index(row, 0, parent);
|
||||
return idx;
|
||||
}
|
||||
|
||||
void setEncoding(const QString &encoding);
|
||||
|
||||
void addFiles(const QString &path);
|
||||
|
||||
void uncheckAll();
|
||||
|
||||
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);
|
||||
|
||||
EsmFileList checkedItems();
|
||||
EsmFileList uncheckedItems();
|
||||
QStringList checkedItemsPaths();
|
||||
|
||||
Qt::CheckState checkState(const QModelIndex &index);
|
||||
void setCheckState(const QModelIndex &index, Qt::CheckState state);
|
||||
|
||||
QModelIndex indexFromItem(const EsmFile *item) const;
|
||||
const EsmFile* findItem(const QString &name);
|
||||
const EsmFile* item(int row) const;
|
||||
|
||||
signals:
|
||||
void checkedItemsChanged(const EsmFileList &items);
|
||||
|
||||
private:
|
||||
|
||||
bool canBeChecked(const EsmFile *file) const;
|
||||
void addFile(const EsmFile *file);
|
||||
|
||||
EsmFileList mFiles;
|
||||
QHash<QString, Qt::CheckState> mCheckStates;
|
||||
|
||||
QString mEncoding;
|
||||
|
||||
};
|
||||
}
|
||||
#endif // DATAFILESMODEL_HPP
|
@ -1,13 +0,0 @@
|
||||
#include "masterproxymodel.hpp"
|
||||
#include <QMimeData>
|
||||
#include <QDebug>
|
||||
|
||||
EsxModel::MasterProxyModel::MasterProxyModel(QObject *parent, QAbstractTableModel* model) :
|
||||
QSortFilterProxyModel(parent)
|
||||
{
|
||||
setFilterRegExp(QString("game"));
|
||||
setFilterRole (Qt::UserRole);
|
||||
|
||||
if (model)
|
||||
setSourceModel (model);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#ifndef MASTERPROXYMODEL_HPP
|
||||
#define MASTERPROXYMODEL_HPP
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStringList>
|
||||
#include <QMimeData>
|
||||
|
||||
class QAbstractTableModel;
|
||||
|
||||
namespace EsxModel
|
||||
{
|
||||
class MasterProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MasterProxyModel(QObject *parent = 0, QAbstractTableModel *model = 0);
|
||||
// virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
void slotSourceModelChanged(QModelIndex topLeft, QModelIndex botRight);
|
||||
};
|
||||
}
|
||||
#endif // MASTERPROXYMODEL_HPP
|
@ -1,69 +0,0 @@
|
||||
#include "modelitem.hpp"
|
||||
|
||||
EsxModel::ModelItem::ModelItem(ModelItem *parent)
|
||||
: mParentItem(parent)
|
||||
{
|
||||
}
|
||||
/*
|
||||
EsxModel::ModelItem::ModelItem(const ModelItem *parent)
|
||||
// : mParentItem(parent)
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
EsxModel::ModelItem::~ModelItem()
|
||||
{
|
||||
qDeleteAll(mChildItems);
|
||||
}
|
||||
|
||||
|
||||
EsxModel::ModelItem *EsxModel::ModelItem::parent() const
|
||||
{
|
||||
return mParentItem;
|
||||
}
|
||||
|
||||
bool EsxModel::ModelItem::hasFormat(const QString &mimetype) const
|
||||
{
|
||||
if (mimetype == "application/omwcontent")
|
||||
return true;
|
||||
|
||||
return QMimeData::hasFormat(mimetype);
|
||||
}
|
||||
int EsxModel::ModelItem::row() const
|
||||
{
|
||||
if (mParentItem)
|
||||
return 1;
|
||||
//return mParentItem->childRow(const_cast<ModelItem*>(this));
|
||||
//return mParentItem->mChildItems.indexOf(const_cast<ModelItem*>(this));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int EsxModel::ModelItem::childCount() const
|
||||
{
|
||||
return mChildItems.count();
|
||||
}
|
||||
|
||||
int EsxModel::ModelItem::childRow(ModelItem *child) const
|
||||
{
|
||||
Q_ASSERT(child);
|
||||
|
||||
return mChildItems.indexOf(child);
|
||||
}
|
||||
|
||||
EsxModel::ModelItem *EsxModel::ModelItem::child(int row)
|
||||
{
|
||||
return mChildItems.value(row);
|
||||
}
|
||||
|
||||
|
||||
void EsxModel::ModelItem::appendChild(ModelItem *item)
|
||||
{
|
||||
mChildItems.append(item);
|
||||
}
|
||||
|
||||
void EsxModel::ModelItem::removeChild(int row)
|
||||
{
|
||||
mChildItems.removeAt(row);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
#include "pluginsproxymodel.hpp"
|
||||
#include "contentmodel.hpp"
|
||||
#include <QDebug>
|
||||
|
||||
EsxModel::PluginsProxyModel::PluginsProxyModel(QObject *parent, ContentModel *model) :
|
||||
QSortFilterProxyModel(parent)
|
||||
{
|
||||
setFilterRegExp (QString("addon"));
|
||||
setFilterRole (Qt::UserRole);
|
||||
setDynamicSortFilter (true);
|
||||
|
||||
if (model)
|
||||
setSourceModel (model);
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
#ifndef PLUGINSPROXYMODEL_HPP
|
||||
#define PLUGINSPROXYMODEL_HPP
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class QVariant;
|
||||
class QAbstractTableModel;
|
||||
|
||||
namespace EsxModel
|
||||
{
|
||||
class ContentModel;
|
||||
|
||||
class PluginsProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit PluginsProxyModel(QObject *parent = 0, ContentModel *model = 0);
|
||||
~PluginsProxyModel();
|
||||
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
|
||||
bool removeRows(int row, int count, const QModelIndex &parent);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // PLUGINSPROXYMODEL_HPP
|
@ -1,6 +0,0 @@
|
||||
#include "sourcemodel.h"
|
||||
|
||||
SourceModel::SourceModel(QObject *parent) :
|
||||
QAbstractTableClass(parent)
|
||||
{
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#ifndef SOURCEMODEL_H
|
||||
#define SOURCEMODEL_H
|
||||
|
||||
#include <QAbstractTableClass>
|
||||
|
||||
class SourceModel : public QAbstractTableClass
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SourceModel(QObject *parent = 0);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
};
|
||||
|
||||
#endif // SOURCEMODEL_H
|
@ -1,148 +0,0 @@
|
||||
#include "contentselector.hpp"
|
||||
|
||||
#include "../model/datafilesmodel.hpp"
|
||||
#include "../model/contentmodel.hpp"
|
||||
#include "../model/esmfile.hpp"
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMenu>
|
||||
#include <QContextMenuEvent>
|
||||
|
||||
EsxView::ContentSelector::ContentSelector(QWidget *parent) :
|
||||
QDialog(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
buildSourceModel();
|
||||
buildMasterView();
|
||||
buildPluginsView();
|
||||
buildProfilesView();
|
||||
|
||||
updateViews();
|
||||
|
||||
}
|
||||
|
||||
void EsxView::ContentSelector::buildSourceModel()
|
||||
{
|
||||
mContentModel = new EsxModel::ContentModel();
|
||||
connect(mContentModel, SIGNAL(layoutChanged()), this, SLOT(updateViews()));
|
||||
}
|
||||
|
||||
void EsxView::ContentSelector::buildMasterView()
|
||||
{
|
||||
mMasterProxyModel = new QSortFilterProxyModel(this);
|
||||
mMasterProxyModel->setFilterRegExp(QString("game"));
|
||||
mMasterProxyModel->setFilterRole (Qt::UserRole);
|
||||
mMasterProxyModel->setSourceModel (mContentModel);
|
||||
|
||||
masterView->setPlaceholderText(QString("Select a game file..."));
|
||||
masterView->setModel(mMasterProxyModel);
|
||||
|
||||
connect(masterView, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentMasterIndexChanged(int)));
|
||||
|
||||
masterView->setCurrentIndex(-1);
|
||||
masterView->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
void EsxView::ContentSelector::buildPluginsView()
|
||||
{
|
||||
mPluginsProxyModel = new QSortFilterProxyModel(this);
|
||||
mPluginsProxyModel->setFilterRegExp (QString("addon"));
|
||||
mPluginsProxyModel->setFilterRole (Qt::UserRole);
|
||||
mPluginsProxyModel->setDynamicSortFilter (true);
|
||||
mPluginsProxyModel->setSourceModel (mContentModel);
|
||||
|
||||
pluginView->setModel(mPluginsProxyModel);
|
||||
|
||||
connect(pluginView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(slotPluginTableItemClicked(const QModelIndex &)));
|
||||
}
|
||||
|
||||
void EsxView::ContentSelector::buildProfilesView()
|
||||
{
|
||||
profilesComboBox->setPlaceholderText(QString("Select a profile..."));
|
||||
connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentProfileIndexChanged(int)));
|
||||
}
|
||||
|
||||
void EsxView::ContentSelector::updateViews()
|
||||
{
|
||||
// Ensure the columns are hidden because sort() re-enables them
|
||||
pluginView->setColumnHidden(1, true);
|
||||
pluginView->setColumnHidden(2, true);
|
||||
pluginView->setColumnHidden(3, true);
|
||||
pluginView->setColumnHidden(4, true);
|
||||
pluginView->setColumnHidden(5, true);
|
||||
pluginView->setColumnHidden(6, true);
|
||||
pluginView->setColumnHidden(7, true);
|
||||
pluginView->setColumnHidden(8, true);
|
||||
pluginView->resizeColumnsToContents();
|
||||
}
|
||||
|
||||
void EsxView::ContentSelector::addFiles(const QString &path)
|
||||
{
|
||||
mContentModel->addFiles(path);
|
||||
mContentModel->sort(3); // Sort by date accessed
|
||||
masterView->setCurrentIndex(-1);
|
||||
mContentModel->uncheckAll();
|
||||
}
|
||||
|
||||
void EsxView::ContentSelector::setEncoding(const QString &encoding)
|
||||
{
|
||||
mContentModel->setEncoding(encoding);
|
||||
}
|
||||
|
||||
QStringList EsxView::ContentSelector::checkedItemsPaths()
|
||||
{
|
||||
QStringList itemPaths;
|
||||
|
||||
foreach( const EsxModel::EsmFile *file, mContentModel->checkedItems())
|
||||
itemPaths << file->path();
|
||||
|
||||
return itemPaths;
|
||||
}
|
||||
|
||||
void EsxView::ContentSelector::slotCurrentProfileIndexChanged(int index)
|
||||
{
|
||||
emit profileChanged(index);
|
||||
}
|
||||
|
||||
void EsxView::ContentSelector::slotCurrentMasterIndexChanged(int index)
|
||||
{
|
||||
static int oldIndex = -1;
|
||||
|
||||
QAbstractItemModel *const model = masterView->model();
|
||||
QSortFilterProxyModel *proxy = dynamic_cast<QSortFilterProxyModel *>(model);
|
||||
|
||||
if (proxy)
|
||||
proxy->setDynamicSortFilter(false);
|
||||
|
||||
if (oldIndex > -1)
|
||||
qDebug() << "clearing old master check state";
|
||||
model->setData(model->index(oldIndex, 0), false, Qt::UserRole + 1);
|
||||
|
||||
oldIndex = index;
|
||||
|
||||
qDebug() << "setting new master check state";
|
||||
model->setData(model->index(index, 0), true, Qt::UserRole + 1);
|
||||
|
||||
if (proxy)
|
||||
proxy->setDynamicSortFilter(true);
|
||||
}
|
||||
|
||||
void EsxView::ContentSelector::slotPluginTableItemClicked(const QModelIndex &index)
|
||||
{
|
||||
QAbstractItemModel *const model = pluginView->model();
|
||||
QSortFilterProxyModel *proxy = dynamic_cast<QSortFilterProxyModel *>(model);
|
||||
|
||||
if (proxy)
|
||||
proxy->setDynamicSortFilter(false);
|
||||
|
||||
if (model->data(index, Qt::CheckStateRole).toInt() == Qt::Unchecked)
|
||||
model->setData(index, Qt::Checked, Qt::CheckStateRole);
|
||||
else
|
||||
model->setData(index, Qt::Unchecked, Qt::CheckStateRole);
|
||||
|
||||
if (proxy)
|
||||
proxy->setDynamicSortFilter(true);
|
||||
}
|
Loading…
Reference in New Issue