ui: auto-persist factory blueprints, drop Save/Load buttons
Load blueprints.toml in the BlueprintPanel constructor and write it in the destructor, matching the ship-layout blueprint lifecycle (startup load, shutdown save, silent write errors, modal on parse failure). Removes the Save/Load buttons and their slots. Implements REQ-UI-BLUEPRINT-SAVE/-LOAD/-PANEL. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VGNNLeFWhVzvxkK9qVXP2K
This commit is contained in:
@@ -53,23 +53,15 @@ BlueprintPanel::BlueprintPanel(Simulation* sim, const GameConfig* config, QWidge
|
|||||||
|
|
||||||
connect(m_createBtn, &QPushButton::clicked, this, &BlueprintPanel::onCreateClicked);
|
connect(m_createBtn, &QPushButton::clicked, this, &BlueprintPanel::onCreateClicked);
|
||||||
|
|
||||||
QHBoxLayout* ioLayout = new QHBoxLayout();
|
loadFromDisk();
|
||||||
m_saveBtn = new QPushButton(tr("Save"), this);
|
rebuildButtons();
|
||||||
m_loadBtn = new QPushButton(tr("Load"), this);
|
|
||||||
m_saveBtn->setFixedHeight(36);
|
|
||||||
m_loadBtn->setFixedHeight(36);
|
|
||||||
ioLayout->addWidget(m_saveBtn);
|
|
||||||
ioLayout->addWidget(m_loadBtn);
|
|
||||||
layout->addLayout(ioLayout);
|
|
||||||
|
|
||||||
connect(m_saveBtn, &QPushButton::clicked, this, &BlueprintPanel::onSaveClicked);
|
|
||||||
connect(m_loadBtn, &QPushButton::clicked, this, &BlueprintPanel::onLoadClicked);
|
|
||||||
|
|
||||||
registerForEvents();
|
registerForEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
BlueprintPanel::~BlueprintPanel()
|
BlueprintPanel::~BlueprintPanel()
|
||||||
{
|
{
|
||||||
|
saveToDisk();
|
||||||
unregisterForEvents();
|
unregisterForEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,65 +273,35 @@ void BlueprintPanel::rebuildButtons()
|
|||||||
refreshButtonStates();
|
refreshButtonStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlueprintPanel::onSaveClicked()
|
void BlueprintPanel::saveToDisk() const
|
||||||
{
|
{
|
||||||
|
// Persist on shutdown; write errors are silently ignored (REQ-UI-BLUEPRINT-SAVE).
|
||||||
const QString path = QCoreApplication::applicationDirPath() + "/blueprints.toml";
|
const QString path = QCoreApplication::applicationDirPath() + "/blueprints.toml";
|
||||||
|
QFile file(path);
|
||||||
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; }
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const std::string content = BlueprintSerializer::serialize(m_blueprints);
|
const std::string content = BlueprintSerializer::serialize(m_blueprints);
|
||||||
QFile file(path);
|
|
||||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
|
||||||
{
|
|
||||||
QMessageBox::critical(this, tr("Save Failed"),
|
|
||||||
tr("Could not open file for writing:\n%1").arg(path));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
file.write(QByteArray::fromStdString(content));
|
file.write(QByteArray::fromStdString(content));
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (...) {}
|
||||||
{
|
|
||||||
QMessageBox::critical(this, tr("Save Failed"),
|
|
||||||
tr("Failed to save blueprints:\n%1").arg(e.what()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlueprintPanel::onLoadClicked()
|
void BlueprintPanel::loadFromDisk()
|
||||||
{
|
{
|
||||||
QMessageBox box(this);
|
// Load at startup (REQ-UI-BLUEPRINT-LOAD). Missing file: start empty, no error.
|
||||||
box.setWindowTitle(tr("Load Blueprints"));
|
|
||||||
box.setText(tr("Load blueprints? This will replace all current blueprints."));
|
|
||||||
QPushButton* confirmBtn = box.addButton(tr("Confirm"), QMessageBox::AcceptRole);
|
|
||||||
box.addButton(tr("Cancel"), QMessageBox::RejectRole);
|
|
||||||
box.exec();
|
|
||||||
if (box.clickedButton() != confirmBtn) { return; }
|
|
||||||
|
|
||||||
const QString path = QCoreApplication::applicationDirPath() + "/blueprints.toml";
|
const QString path = QCoreApplication::applicationDirPath() + "/blueprints.toml";
|
||||||
|
QFile file(path);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return; }
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
QFile file(path);
|
m_blueprints = BlueprintSerializer::deserialize(file.readAll().toStdString());
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
|
||||||
{
|
|
||||||
QMessageBox::critical(this, tr("Load Failed"),
|
|
||||||
tr("Could not open file:\n%1").arg(path));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const std::string content = file.readAll().toStdString();
|
|
||||||
std::vector<Blueprint> loaded = BlueprintSerializer::deserialize(content);
|
|
||||||
|
|
||||||
if (m_activeIndex >= 0)
|
|
||||||
{
|
|
||||||
EventManager::getInstance()->sendEventImmediately(
|
|
||||||
std::make_shared<ExitBlueprintModeRequestedEvent>());
|
|
||||||
m_activeIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_blueprints = std::move(loaded);
|
|
||||||
rebuildButtons();
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
QMessageBox::critical(this, tr("Load Failed"),
|
QMessageBox::critical(this, tr("Load Failed"),
|
||||||
tr("Failed to load blueprints:\n%1").arg(e.what()));
|
tr("Failed to load blueprints:\n%1").arg(e.what()));
|
||||||
|
m_blueprints.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ private slots:
|
|||||||
void onCreateClicked();
|
void onCreateClicked();
|
||||||
void onDeleteBlueprintClicked(int index);
|
void onDeleteBlueprintClicked(int index);
|
||||||
void onBlueprintButtonClicked(int index);
|
void onBlueprintButtonClicked(int index);
|
||||||
void onSaveClicked();
|
|
||||||
void onLoadClicked();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onSelectionChanged(const std::vector<BuildingId>& ids);
|
void onSelectionChanged(const std::vector<BuildingId>& ids);
|
||||||
@@ -48,6 +46,8 @@ private:
|
|||||||
int computeBlueprintCost(const Blueprint& bp) const;
|
int computeBlueprintCost(const Blueprint& bp) const;
|
||||||
void rebuildButtons();
|
void rebuildButtons();
|
||||||
void refreshButtonStates();
|
void refreshButtonStates();
|
||||||
|
void loadFromDisk();
|
||||||
|
void saveToDisk() const;
|
||||||
|
|
||||||
Simulation* m_sim;
|
Simulation* m_sim;
|
||||||
const GameConfig* m_config;
|
const GameConfig* m_config;
|
||||||
@@ -57,8 +57,6 @@ private:
|
|||||||
std::vector<Blueprint> m_blueprints;
|
std::vector<Blueprint> m_blueprints;
|
||||||
std::vector<QPushButton*> m_blueprintButtons;
|
std::vector<QPushButton*> m_blueprintButtons;
|
||||||
QPushButton* m_createBtn;
|
QPushButton* m_createBtn;
|
||||||
QPushButton* m_saveBtn;
|
|
||||||
QPushButton* m_loadBtn;
|
|
||||||
QWidget* m_buttonsContainer;
|
QWidget* m_buttonsContainer;
|
||||||
QVBoxLayout* m_buttonsLayout;
|
QVBoxLayout* m_buttonsLayout;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user