1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-01 03:21:41 +00:00
OpenMW/apps/opencs/view/world/genericcreator.cpp
2022-10-31 21:04:01 +01:00

357 lines
9.4 KiB
C++

#include "genericcreator.hpp"
#include <memory>
#include <utility>
#include <QComboBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QUndoStack>
#include <apps/opencs/model/world/universalid.hpp>
#include <components/misc/strings/lower.hpp>
#include "../../model/world/commands.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/idtable.hpp"
#include "idvalidator.hpp"
void CSVWorld::GenericCreator::update()
{
mErrors = getErrors();
mCreate->setToolTip(QString::fromUtf8(mErrors.c_str()));
mId->setToolTip(QString::fromUtf8(mErrors.c_str()));
mCreate->setEnabled(mErrors.empty() && !mLocked);
}
void CSVWorld::GenericCreator::setManualEditing(bool enabled)
{
mId->setVisible(enabled);
}
void CSVWorld::GenericCreator::insertAtBeginning(QWidget* widget, bool stretched)
{
mLayout->insertWidget(0, widget, stretched ? 1 : 0);
}
void CSVWorld::GenericCreator::insertBeforeButtons(QWidget* widget, bool stretched)
{
mLayout->insertWidget(mLayout->count() - 2, widget, stretched ? 1 : 0);
// Reset tab order relative to buttons.
setTabOrder(widget, mCreate);
setTabOrder(mCreate, mCancel);
}
std::string CSVWorld::GenericCreator::getId() const
{
return mId->text().toUtf8().constData();
}
std::string CSVWorld::GenericCreator::getClonedId() const
{
return mClonedId;
}
std::string CSVWorld::GenericCreator::getIdValidatorResult() const
{
std::string errors;
if (!mId->hasAcceptableInput())
errors = mValidator->getError();
return errors;
}
void CSVWorld::GenericCreator::configureCreateCommand(CSMWorld::CreateCommand& command) const {}
void CSVWorld::GenericCreator::pushCommand(std::unique_ptr<CSMWorld::CreateCommand> command, const std::string& id)
{
mUndoStack.push(command.release());
}
CSMWorld::Data& CSVWorld::GenericCreator::getData() const
{
return mData;
}
QUndoStack& CSVWorld::GenericCreator::getUndoStack()
{
return mUndoStack;
}
const CSMWorld::UniversalId& CSVWorld::GenericCreator::getCollectionId() const
{
return mListId;
}
std::string CSVWorld::GenericCreator::getNamespace() const
{
CSMWorld::Scope scope = CSMWorld::Scope_Content;
if (mScope)
{
scope = static_cast<CSMWorld::Scope>(mScope->itemData(mScope->currentIndex()).toInt());
}
else
{
if (mScopes & CSMWorld::Scope_Project)
scope = CSMWorld::Scope_Project;
else if (mScopes & CSMWorld::Scope_Session)
scope = CSMWorld::Scope_Session;
}
switch (scope)
{
case CSMWorld::Scope_Content:
return "";
case CSMWorld::Scope_Project:
return "project::";
case CSMWorld::Scope_Session:
return "session::";
}
return "";
}
void CSVWorld::GenericCreator::updateNamespace()
{
std::string namespace_ = getNamespace();
mValidator->setNamespace(namespace_);
int index = mId->text().indexOf("::");
if (index == -1)
{
// no namespace in old text
mId->setText(QString::fromUtf8(namespace_.c_str()) + mId->text());
}
else
{
std::string oldNamespace = Misc::StringUtils::lowerCase(mId->text().left(index).toUtf8().constData());
if (oldNamespace == "project" || oldNamespace == "session")
mId->setText(QString::fromUtf8(namespace_.c_str()) + mId->text().mid(index + 2));
}
}
void CSVWorld::GenericCreator::addScope(const QString& name, CSMWorld::Scope scope, const QString& tooltip)
{
mScope->addItem(name, static_cast<int>(scope));
mScope->setItemData(mScope->count() - 1, tooltip, Qt::ToolTipRole);
}
CSVWorld::GenericCreator::GenericCreator(
CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id, bool relaxedIdRules)
: mData(data)
, mUndoStack(undoStack)
, mListId(id)
, mLocked(false)
, mClonedType(CSMWorld::UniversalId::Type_None)
, mScopes(CSMWorld::Scope_Content)
, mScope(nullptr)
, mScopeLabel(nullptr)
, mCloneMode(false)
{
// If the collection ID has a parent type, use it instead.
// It will change IDs with Record/SubRecord class (used for creators in Dialogue subviews)
// to IDs with general RecordList class (used for creators in Table subviews).
CSMWorld::UniversalId::Type listParentType = CSMWorld::UniversalId::getParentType(mListId.getType());
if (listParentType != CSMWorld::UniversalId::Type_None)
{
mListId = listParentType;
}
mLayout = new QHBoxLayout;
mLayout->setContentsMargins(0, 0, 0, 0);
mId = new QLineEdit;
mId->setValidator(mValidator = new IdValidator(relaxedIdRules, this));
mLayout->addWidget(mId, 1);
mCreate = new QPushButton("Create");
mLayout->addWidget(mCreate);
mCancel = new QPushButton("Cancel");
mLayout->addWidget(mCancel);
setLayout(mLayout);
connect(mCancel, &QPushButton::clicked, this, &GenericCreator::done);
connect(mCreate, &QPushButton::clicked, this, &GenericCreator::create);
connect(mId, &QLineEdit::textChanged, this, &GenericCreator::textChanged);
connect(mId, &QLineEdit::returnPressed, this, &GenericCreator::inputReturnPressed);
connect(&mData, &CSMWorld::Data::idListChanged, this, &GenericCreator::dataIdListChanged);
}
void CSVWorld::GenericCreator::setEditorMaxLength(int length)
{
mId->setMaxLength(length);
}
void CSVWorld::GenericCreator::setEditLock(bool locked)
{
mLocked = locked;
update();
}
void CSVWorld::GenericCreator::reset()
{
mCloneMode = false;
mId->setText("");
update();
updateNamespace();
}
std::string CSVWorld::GenericCreator::getErrors() const
{
std::string errors;
if (!mId->hasAcceptableInput())
errors = mValidator->getError();
else if (mData.hasId(getId()))
errors = "ID is already in use";
return errors;
}
void CSVWorld::GenericCreator::textChanged(const QString& text)
{
update();
}
void CSVWorld::GenericCreator::inputReturnPressed()
{
if (mCreate->isEnabled())
{
create();
}
}
void CSVWorld::GenericCreator::create()
{
if (!mLocked)
{
std::string id = getId();
std::unique_ptr<CSMWorld::CreateCommand> command;
if (mCloneMode)
{
command = std::make_unique<CSMWorld::CloneCommand>(
dynamic_cast<CSMWorld::IdTable&>(*mData.getTableModel(mListId)), mClonedId, id, mClonedType);
}
else
{
command = std::make_unique<CSMWorld::CreateCommand>(
dynamic_cast<CSMWorld::IdTable&>(*mData.getTableModel(mListId)), id);
}
configureCreateCommand(*command);
pushCommand(std::move(command), id);
emit done();
emit requestFocus(id);
}
}
void CSVWorld::GenericCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type)
{
mCloneMode = true;
mClonedId = originId;
mClonedType = type;
}
void CSVWorld::GenericCreator::touch(const std::vector<CSMWorld::UniversalId>& ids)
{
// Combine multiple touch commands into one "macro" command
mUndoStack.beginMacro("Touch Records");
CSMWorld::IdTable& table = dynamic_cast<CSMWorld::IdTable&>(*mData.getTableModel(mListId));
for (const CSMWorld::UniversalId& uid : ids)
{
CSMWorld::TouchCommand* touchCmd = new CSMWorld::TouchCommand(table, uid.getId());
mUndoStack.push(touchCmd);
}
// Execute
mUndoStack.endMacro();
}
void CSVWorld::GenericCreator::toggleWidgets(bool active) {}
void CSVWorld::GenericCreator::focus()
{
mId->setFocus();
}
void CSVWorld::GenericCreator::setScope(unsigned int scope)
{
mScopes = scope;
int count = (mScopes & CSMWorld::Scope_Content) + (mScopes & CSMWorld::Scope_Project)
+ (mScopes & CSMWorld::Scope_Session);
// scope selector widget
if (count > 1)
{
mScope = new QComboBox(this);
insertAtBeginning(mScope, false);
if (mScopes & CSMWorld::Scope_Content)
addScope("Content", CSMWorld::Scope_Content, "Record will be stored in the currently edited content file.");
if (mScopes & CSMWorld::Scope_Project)
addScope("Project", CSMWorld::Scope_Project,
"Record will be stored in a local project file.<p>"
"Record will be created in the reserved namespace \"project\".<p>"
"Record is available when running OpenMW via OpenCS.");
if (mScopes & CSMWorld::Scope_Session)
addScope("Session", CSMWorld::Scope_Session,
"Record exists only for the duration of the current editing session.<p>"
"Record will be created in the reserved namespace \"session\".<p>"
"Record is not available when running OpenMW via OpenCS.");
connect(mScope, qOverload<int>(&QComboBox::currentIndexChanged), this, &GenericCreator::scopeChanged);
mScopeLabel = new QLabel("Scope", this);
insertAtBeginning(mScopeLabel, false);
mScope->setCurrentIndex(0);
}
else
{
delete mScope;
mScope = nullptr;
delete mScopeLabel;
mScopeLabel = nullptr;
}
updateNamespace();
}
void CSVWorld::GenericCreator::scopeChanged(int index)
{
update();
updateNamespace();
}
void CSVWorld::GenericCreator::dataIdListChanged()
{
// If the original ID of cloned record was removed, cancel the creator
if (mCloneMode && !mData.hasId(mClonedId))
{
emit done();
}
}