15#include <QSvgGenerator>
28constexpr int kMaxExportPadding = 2000;
39 if (command ==
"load_circuit") {
40 return handleLoadCircuit(params, requestId);
41 }
else if (command ==
"save_circuit") {
42 return handleSaveCircuit(params, requestId);
43 }
else if (command ==
"new_circuit") {
44 return handleNewCircuit(params, requestId);
45 }
else if (command ==
"close_circuit") {
46 return handleCloseCircuit(params, requestId);
47 }
else if (command ==
"get_tab_count") {
48 return handleGetTabCount(params, requestId);
49 }
else if (command ==
"export_image") {
50 return handleExportImage(params, requestId);
51 }
else if (command ==
"export_arduino") {
52 return handleExportArduino(params, requestId);
53 }
else if (command ==
"export_systemverilog") {
54 return handleExportSystemVerilog(params, requestId);
61QJsonObject FileHandler::handleLoadCircuit(
const QJsonObject ¶ms,
const QJsonValue &requestId)
72 QString filename = params.value(
"filename").toString();
81 },
"load circuit", requestId);
84QJsonObject FileHandler::handleSaveCircuit(
const QJsonObject ¶ms,
const QJsonValue &requestId)
95 QString filename = params.value(
"filename").toString();
97 if (!filename.endsWith(
".panda", Qt::CaseInsensitive)) {
108 },
"save circuit", requestId);
111QJsonObject FileHandler::handleNewCircuit(
const QJsonObject &,
const QJsonValue &requestId)
126 },
"create new circuit", requestId);
129QJsonObject FileHandler::handleCloseCircuit(
const QJsonObject &,
const QJsonValue &requestId)
136 QTabWidget *tabWidget =
m_mainWindow->findChild<QTabWidget *>(
"tab");
143 if (tabWidget->count() == 0) {
152 int currentIndex = tabWidget->currentIndex();
154 QWidget *tabWidget_widget = tabWidget->widget(currentIndex);
155 tabWidget->removeTab(currentIndex);
156 if (tabWidget_widget) {
157 tabWidget_widget->deleteLater();
161 },
"close circuit", requestId);
164QJsonObject FileHandler::handleGetTabCount(
const QJsonObject &,
const QJsonValue &requestId)
171 QTabWidget *tabWidget =
m_mainWindow->findChild<QTabWidget *>(
"tab");
178 result[
"tab_count"] = tabWidget->count();
181 },
"get tab count", requestId);
184QJsonObject FileHandler::handleExportImage(
const QJsonObject ¶ms,
const QJsonValue &requestId)
199 QString filename = params.value(
"filename").toString();
200 QString format = params.value(
"format").toString().toLower();
201 const int padding = std::clamp(params.value(
"padding").toInt(20), 0, kMaxExportPadding);
208 if (format !=
"png" && format !=
"svg" && format !=
"pdf") {
213 QRectF sceneRect = scene->itemsBoundingRect();
218 if (sceneRect.isEmpty()) {
222 sceneRect.adjust(-padding, -padding, padding, padding);
224 if (format ==
"svg") {
225 QSvgGenerator generator;
226 generator.setFileName(filename);
227 generator.setSize(sceneRect.size().toSize());
228 generator.setViewBox(sceneRect);
229 generator.setTitle(
"wiRedPanda Circuit");
230 generator.setDescription(
"Circuit exported from wiRedPanda");
232 QPainter painter(&generator);
233 if (!painter.isActive()) {
234 return createErrorResponse(QString(
"Failed to open SVG file for writing: %1").arg(filename),
237 scene->render(&painter, QRectF(), sceneRect);
240 const QFileInfo svgInfo(filename);
241 if (!svgInfo.exists() || svgInfo.size() == 0) {
244 }
else if (format ==
"pdf") {
245 QPdfWriter pdfWriter(filename);
246 pdfWriter.setTitle(
"wiRedPanda Circuit");
247 pdfWriter.setCreator(
"wiRedPanda");
249 pdfWriter.setResolution(72);
250 pdfWriter.setPageSize(QPageSize(sceneRect.size(), QPageSize::Point));
251 pdfWriter.setPageMargins(QMarginsF(0, 0, 0, 0));
253 QPainter painter(&pdfWriter);
254 if (!painter.isActive()) {
255 return createErrorResponse(QString(
"Failed to open PDF file for writing: %1").arg(filename),
258 painter.setRenderHint(QPainter::Antialiasing);
259 scene->render(&painter, QRectF(), sceneRect);
268 if (!image.save(filename,
"PNG")) {
273 result[
"exported_file"] = filename;
274 result[
"format"] = format;
275 result[
"size"] = QString(
"%1x%2").arg(image.width()).arg(image.height());
281 result[
"exported_file"] = filename;
282 result[
"format"] = format;
283 result[
"size"] = QString(
"%1x%2").arg(sceneRect.width()).arg(sceneRect.height());
286 },
"export image", requestId);
289QJsonObject FileHandler::handleExportArduino(
const QJsonObject ¶ms,
const QJsonValue &requestId)
300 QString filename = params.value(
"filename").toString();
310 result[
"exported_file"] = filename;
311 result[
"format"] =
"arduino";
314 },
"export Arduino code", requestId);
317QJsonObject FileHandler::handleExportSystemVerilog(
const QJsonObject ¶ms,
const QJsonValue &requestId)
328 QString filename = params.value(
"filename").toString();
338 result[
"exported_file"] = filename;
339 result[
"format"] =
"systemverilog";
342 },
"export SystemVerilog code", requestId);
CircuitExporter: render a Scene to PDF or PNG image.
Main application window providing menus, toolbars, and tab management.
Main circuit editing scene with undo/redo and user interaction.
WorkSpace widget: the complete circuit editing environment for one tab.
QJsonObject createSuccessResponse(const QJsonObject &result={}, const QJsonValue &requestId=QJsonValue()) const
QJsonObject tryCommand(Fn &&fn, const QString &action, const QJsonValue &requestId=QJsonValue())
Wraps fn in a try/catch, returning an error response on exception.
BaseHandler(MainWindow *mainWindow, const MCPValidator *validator)
QJsonObject createErrorResponse(const QString &error, const QJsonValue &requestId=QJsonValue(), int code=JsonRpcError::InternalError) const
MainWindow * m_mainWindow
bool validateParameters(const QJsonObject ¶ms, const QStringList &required) const
bool validateNonEmptyString(const QJsonValue &value, const QString ¶mName, QString &errorMsg) const
FileHandler(MainWindow *mainWindow, const MCPValidator *validator)
QJsonObject handleCommand(const QString &command, const QJsonObject ¶ms, const QJsonValue &requestId) override
JSON Schema validator for MCP commands and responses using native json-schema-validator.
The top-level application window hosting the tab bar, menus, element palette, and editor.
Simulation * simulation()
Returns the simulation engine associated with this scene.
void stop()
Stops the simulation timer.
QImage renderScaledImage(Scene *scene, const QRectF &paddedRect)
Renders scene into a transparent-filled QImage bounded by kMaxImageDimension.
constexpr int SceneNotAvailable
No active circuit scene to operate on.
constexpr int MethodNotFound
The requested method does not exist or is unavailable.
constexpr int OperationFailed
Generic Qt API / handler operation failure (catch-all for tryCommand).
constexpr int InternalError
Internal JSON-RPC error (last-resort).
constexpr int FileError
File save/load/path error.
constexpr int ValidationError
Semantic validation failure (e.g. port index out of range, enum value not allowed).
constexpr int InvalidParams
Invalid method parameters (missing required, wrong type, etc.).