Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357#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 namespaceName = getNamespace();
mValidator->setNamespace(namespaceName);
int index = mId->text().indexOf("::");
if (index == -1) { // no namespace in old text mId->setText(QString::fromUtf8(namespaceName.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(namespaceName.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& worldData, QUndoStack& undoStack, const CSMWorld::UniversalId& id, bool relaxedIdRules) : mData(worldData) , 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(); }}