mirror of https://github.com/OpenMW/openmw.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
241 lines
7.1 KiB
C++
241 lines
7.1 KiB
C++
#include "extendedcommandconfigurator.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#include <QCheckBox>
|
|
#include <QGroupBox>
|
|
#include <QLayout>
|
|
#include <QPushButton>
|
|
|
|
#include "../../model/doc/document.hpp"
|
|
|
|
#include "../../model/world/commanddispatcher.hpp"
|
|
#include "../../model/world/data.hpp"
|
|
|
|
#include <apps/opencs/model/world/universalid.hpp>
|
|
|
|
CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(
|
|
CSMDoc::Document& document, const CSMWorld::UniversalId& id, QWidget* parent)
|
|
: QWidget(parent)
|
|
, mNumUsedCheckBoxes(0)
|
|
, mNumChecked(0)
|
|
, mMode(Mode_None)
|
|
, mData(document.getData())
|
|
, mEditLock(false)
|
|
{
|
|
mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this);
|
|
|
|
connect(&mData, &CSMWorld::Data::idListChanged, this, &ExtendedCommandConfigurator::dataIdListChanged);
|
|
|
|
mPerformButton = new QPushButton(this);
|
|
mPerformButton->setDefault(true);
|
|
mPerformButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
|
connect(mPerformButton, &QPushButton::clicked, this, &ExtendedCommandConfigurator::performExtendedCommand);
|
|
|
|
mCancelButton = new QPushButton("Cancel", this);
|
|
mCancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
|
connect(mCancelButton, &QPushButton::clicked, this, &ExtendedCommandConfigurator::done);
|
|
|
|
mTypeGroup = new QGroupBox(this);
|
|
|
|
QGridLayout* groupLayout = new QGridLayout(mTypeGroup);
|
|
groupLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
|
mTypeGroup->setLayout(groupLayout);
|
|
|
|
QHBoxLayout* mainLayout = new QHBoxLayout(this);
|
|
mainLayout->setSizeConstraint(QLayout::SetNoConstraint);
|
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
|
mainLayout->addWidget(mTypeGroup);
|
|
mainLayout->addWidget(mPerformButton);
|
|
mainLayout->addWidget(mCancelButton);
|
|
}
|
|
|
|
void CSVWorld::ExtendedCommandConfigurator::configure(
|
|
CSVWorld::ExtendedCommandConfigurator::Mode mode, const std::vector<std::string>& selectedIds)
|
|
{
|
|
mMode = mode;
|
|
if (mMode != Mode_None)
|
|
{
|
|
mPerformButton->setText((mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert");
|
|
mSelectedIds = selectedIds;
|
|
mCommandDispatcher->setSelection(mSelectedIds);
|
|
|
|
setupCheckBoxes(mCommandDispatcher->getExtendedTypes());
|
|
setupGroupLayout();
|
|
lockWidgets(mEditLock);
|
|
}
|
|
}
|
|
|
|
void CSVWorld::ExtendedCommandConfigurator::setEditLock(bool locked)
|
|
{
|
|
if (mEditLock != locked)
|
|
{
|
|
mEditLock = locked;
|
|
lockWidgets(mEditLock);
|
|
}
|
|
}
|
|
|
|
void CSVWorld::ExtendedCommandConfigurator::resizeEvent(QResizeEvent* event)
|
|
{
|
|
QWidget::resizeEvent(event);
|
|
setupGroupLayout();
|
|
}
|
|
|
|
void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout()
|
|
{
|
|
if (mMode == Mode_None)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int groupWidth = mTypeGroup->geometry().width();
|
|
QGridLayout* layout = qobject_cast<QGridLayout*>(mTypeGroup->layout());
|
|
|
|
// Find the optimal number of rows to place the checkboxes within the available space
|
|
int divider = 1;
|
|
do
|
|
{
|
|
while (layout->itemAt(0) != nullptr)
|
|
{
|
|
layout->removeItem(layout->itemAt(0));
|
|
}
|
|
|
|
int counter = 0;
|
|
int itemsPerRow = mNumUsedCheckBoxes / divider;
|
|
CheckBoxMap::const_iterator current = mTypeCheckBoxes.begin();
|
|
CheckBoxMap::const_iterator end = mTypeCheckBoxes.end();
|
|
for (; current != end; ++current)
|
|
{
|
|
if (counter < mNumUsedCheckBoxes)
|
|
{
|
|
int row = counter / itemsPerRow;
|
|
int column = counter - (counter / itemsPerRow) * itemsPerRow;
|
|
layout->addWidget(current->first, row, column);
|
|
}
|
|
++counter;
|
|
}
|
|
divider *= 2;
|
|
} while (groupWidth < mTypeGroup->sizeHint().width() && divider <= mNumUsedCheckBoxes);
|
|
}
|
|
|
|
void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vector<CSMWorld::UniversalId>& types)
|
|
{
|
|
// Make sure that we have enough checkboxes
|
|
int numTypes = static_cast<int>(types.size());
|
|
int numCheckBoxes = static_cast<int>(mTypeCheckBoxes.size());
|
|
if (numTypes > numCheckBoxes)
|
|
{
|
|
for (int i = numTypes - numCheckBoxes; i > 0; --i)
|
|
{
|
|
QCheckBox* checkBox = new QCheckBox(mTypeGroup);
|
|
connect(checkBox, &QCheckBox::stateChanged, this, &ExtendedCommandConfigurator::checkBoxStateChanged);
|
|
mTypeCheckBoxes.insert(std::make_pair(checkBox, CSMWorld::UniversalId::Type_None));
|
|
}
|
|
}
|
|
|
|
// Set up the checkboxes
|
|
int counter = 0;
|
|
CheckBoxMap::iterator current = mTypeCheckBoxes.begin();
|
|
CheckBoxMap::iterator end = mTypeCheckBoxes.end();
|
|
for (; current != end; ++current)
|
|
{
|
|
if (counter < numTypes)
|
|
{
|
|
CSMWorld::UniversalId type = types[counter];
|
|
current->first->setText(QString::fromUtf8(type.getTypeName().c_str()));
|
|
current->first->setChecked(true);
|
|
current->second = std::move(type);
|
|
++counter;
|
|
}
|
|
else
|
|
{
|
|
current->first->hide();
|
|
}
|
|
}
|
|
mNumChecked = mNumUsedCheckBoxes = numTypes;
|
|
}
|
|
|
|
void CSVWorld::ExtendedCommandConfigurator::lockWidgets(bool locked)
|
|
{
|
|
mPerformButton->setEnabled(!mEditLock && mNumChecked > 0);
|
|
|
|
CheckBoxMap::const_iterator current = mTypeCheckBoxes.begin();
|
|
CheckBoxMap::const_iterator end = mTypeCheckBoxes.end();
|
|
for (int i = 0; current != end && i < mNumUsedCheckBoxes; ++current, ++i)
|
|
{
|
|
current->first->setEnabled(!mEditLock);
|
|
}
|
|
}
|
|
|
|
void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand()
|
|
{
|
|
std::vector<CSMWorld::UniversalId> types;
|
|
|
|
CheckBoxMap::const_iterator current = mTypeCheckBoxes.begin();
|
|
CheckBoxMap::const_iterator end = mTypeCheckBoxes.end();
|
|
for (; current != end; ++current)
|
|
{
|
|
if (current->first->isChecked())
|
|
{
|
|
types.push_back(current->second);
|
|
}
|
|
}
|
|
|
|
mCommandDispatcher->setExtendedTypes(types);
|
|
if (mMode == Mode_Delete)
|
|
{
|
|
mCommandDispatcher->executeExtendedDelete();
|
|
}
|
|
else
|
|
{
|
|
mCommandDispatcher->executeExtendedRevert();
|
|
}
|
|
emit done();
|
|
}
|
|
|
|
void CSVWorld::ExtendedCommandConfigurator::checkBoxStateChanged(int state)
|
|
{
|
|
switch (state)
|
|
{
|
|
case Qt::Unchecked:
|
|
--mNumChecked;
|
|
break;
|
|
case Qt::Checked:
|
|
++mNumChecked;
|
|
break;
|
|
case Qt::PartiallyChecked: // Not used
|
|
break;
|
|
}
|
|
|
|
mPerformButton->setEnabled(mNumChecked > 0);
|
|
}
|
|
|
|
void CSVWorld::ExtendedCommandConfigurator::dataIdListChanged()
|
|
{
|
|
bool idsRemoved = false;
|
|
for (int i = 0; i < static_cast<int>(mSelectedIds.size()); ++i)
|
|
{
|
|
if (!mData.hasId(mSelectedIds[i]))
|
|
{
|
|
std::swap(mSelectedIds[i], mSelectedIds.back());
|
|
mSelectedIds.pop_back();
|
|
idsRemoved = true;
|
|
--i;
|
|
}
|
|
}
|
|
|
|
// If all selected IDs were removed, cancel the configurator
|
|
if (mSelectedIds.empty())
|
|
{
|
|
emit done();
|
|
return;
|
|
}
|
|
|
|
if (idsRemoved)
|
|
{
|
|
mCommandDispatcher->setSelection(mSelectedIds);
|
|
}
|
|
}
|