Commit 31fcc689 authored by Andrey Filippov's avatar Andrey Filippov

Implementing quasi-parallel processing using GUI and MCP

parent 30b9d3f9
......@@ -3407,13 +3407,19 @@ public class CLTParameters {
}
public boolean showJDialog() {
return showJDialog(false);
return showJDialog(false, GenericJTabbedDialogMcp.isDefaultMcpMode());
}
// codex 2026-01-27: optional modeless dialog for MCP/GUI co-use
public boolean showJDialog(boolean nonBlocking) {
return showJDialog(nonBlocking, GenericJTabbedDialogMcp.isDefaultMcpMode());
}
// codex 2026-01-28: allow forcing GUI vs MCP mode per call
public boolean showJDialog(boolean nonBlocking, boolean useMcp) {
// GenericDialog gd = new GenericDialog("Set CLT parameters");
GenericJTabbedDialogMcp gd = new GenericJTabbedDialogMcp("Set CLT parameters",1090,900, !nonBlocking); // codex 2026-01-25
gd.setMcpMode(useMcp);
gd.addTab ("General", "General parameters");
gd.addNumericField("Nominal (rectilinear) disparity between side of square cameras (pix)", this.disparity, 3,7,"pix",
"Used when rendering 4 images");
......
......@@ -1197,14 +1197,23 @@ public class EyesisCorrectionParameters {
public boolean showCLTBatchDialog(String title,
CLTParameters clt_parameters) {
return showCLTBatchDialog(title, clt_parameters, false);
return showCLTBatchDialog(title, clt_parameters, false, GenericJTabbedDialogMcp.isDefaultMcpMode());
}
// codex 2026-01-27: optional modeless dialog for MCP/GUI co-use
public boolean showCLTBatchDialog(String title,
CLTParameters clt_parameters,
boolean nonBlocking) {
return showCLTBatchDialog(title, clt_parameters, nonBlocking, GenericJTabbedDialogMcp.isDefaultMcpMode());
}
// codex 2026-01-28: allow forcing GUI vs MCP mode per call
public boolean showCLTBatchDialog(String title,
CLTParameters clt_parameters,
boolean nonBlocking,
boolean useMcp) {
GenericJTabbedDialogMcp gd = new GenericJTabbedDialogMcp(title,1000,1000, !nonBlocking); // codex 2026-01-25
gd.setMcpMode(useMcp);
updateAuxFromMain();
......@@ -1792,7 +1801,8 @@ public class EyesisCorrectionParameters {
base_path=base_path.resolve(Paths.get(dir_map.get("rootDirectory")));
File base_dir = new File(base_path.toString());
if (!base_dir.exists()) {
base_dir.mkdirs(); // codex 2026-01-28: mkdirs side-effect (consider guarding)
System.out.println("Root directory "+base_path.toString()+" does not exist, ignoring "+seq_str);
return null;
}
}
// set sourceDirectory:
......@@ -1808,7 +1818,8 @@ public class EyesisCorrectionParameters {
Path source_path = Paths.get(this.sourceDirectory);
File source_dir = new File(source_path.toString());
if (!source_dir.exists()) {
source_dir.mkdirs(); // codex 2026-01-28: mkdirs side-effect (consider guarding)
System.out.println("Source directory "+source_path.toString()+" does not exist, ignoring "+seq_str);
return null;
}
useCuasSeedDir = false;
......@@ -1821,7 +1832,8 @@ public class EyesisCorrectionParameters {
File dir_file = new File(dir_path.toString());
if ((i != KEY_INDEX_UAS_LOGS) && (i != KEY_INDEX_SKY_MASK)) { // cuasUasLogs, cuasSkyMask are files, not directories
if (!dir_file.exists()) {
dir_file.mkdirs(); // codex 2026-01-28: mkdirs side-effect (consider guarding)
System.out.println(KEY_DIRS[i]+" directory "+dir_path.toString()+" does not exist, ignoring "+seq_str);
return null;
}
}
dir_string = dir_path.toString();
......
......@@ -12,7 +12,9 @@ import ij.IJ;
public class GenericJTabbedDialogMcp extends GenericJTabbedDialog{
// codex 2026-01-25: MCP dialog capture state
private static boolean defaultMcpMode = false;
private static long dialogTimeoutMs = 30000L;
public boolean mcp_mode = false;
private boolean mcpCanceled = false;
private final List<McpDialogField> mcpFields = new ArrayList<McpDialogField>();
private final String dialogTitle;
private String currentTab = "";
......@@ -42,6 +44,14 @@ public class GenericJTabbedDialogMcp extends GenericJTabbedDialog{
public static boolean isDefaultMcpMode() {
return defaultMcpMode;
}
// codex 2026-01-28: configurable MCP dialog submit timeout (0 = wait forever)
public static void setDialogTimeoutMs(long timeoutMs) {
dialogTimeoutMs = timeoutMs;
}
// codex 2026-01-28: override MCP mode per dialog instance
public void setMcpMode(boolean enabled) {
this.mcp_mode = enabled;
}
private void addMcpField(McpDialogField field) {
mcpFields.add(field);
......@@ -121,6 +131,16 @@ public class GenericJTabbedDialogMcp extends GenericJTabbedDialog{
else super.addChoice(label, items, defaultItem, tooltip, count);
}
@Override
public void addChoice(String label, String[] items, String defaultItem) {
addChoice(label, items, defaultItem, null, 0);
}
@Override
public void addChoice(String label, String[] items, String defaultItem, String tooltip) {
addChoice(label, items, defaultItem, tooltip, 0);
}
@Override
public void addDefaultButtons() { // not used
if (mcp_mode) {
......@@ -149,7 +169,10 @@ public class GenericJTabbedDialogMcp extends GenericJTabbedDialog{
if (mcp_mode) {
// codex 2026-01-25: publish dialog schema to MCP registry
readIndex = 0;
McpDialogRegistry.setCurrent(new McpDialogSession(dialogTitle, mcpFields));
boolean applied = McpDialogRegistry.setCurrent(new McpDialogSession(dialogTitle, mcpFields));
if (!applied) {
System.out.println("MCP: dialog already active, ignoring \"" + dialogTitle + "\"");
}
}
else super.buildDialog();
}
......@@ -253,6 +276,17 @@ public class GenericJTabbedDialogMcp extends GenericJTabbedDialog{
public boolean showDialog() {
if (mcp_mode) {
buildDialog();
McpDialogSession session = McpDialogRegistry.getCurrent();
if (session != null) {
long timeout = dialogTimeoutMs;
Boolean ok = (timeout <= 0) ? session.awaitSubmit(Long.MAX_VALUE) : session.awaitSubmit(timeout);
if (ok != null && !ok.booleanValue()) {
mcpCanceled = true;
} else {
mcpCanceled = false;
}
}
McpDialogRegistry.setCurrent(null);
return true;
}
else return super.showDialog();
......@@ -279,7 +313,7 @@ public class GenericJTabbedDialogMcp extends GenericJTabbedDialog{
@Override
public boolean wasCanceled() {
if (mcp_mode) {
return false;
return mcpCanceled;
}
else return super.wasCanceled();
}
......
......@@ -12,6 +12,7 @@ public class SyncCommand {
public AtomicInteger stopRequested = new AtomicInteger(0); // 0 - not requested, 1 - ASAP, 2 - gracefully
public String buttonLabel = "";
public boolean confirm = true;
public boolean fromMcp = false;
// codex 2026-01-27: MCP-controlled pause/confirm
private boolean mcpMode = false;
private boolean confirmPending = false;
......
......@@ -8,19 +8,58 @@ public class McpDialogRegistry {
private McpDialogRegistry() {
}
public static void setCurrent(McpDialogSession session) {
public static boolean setCurrent(McpDialogSession session) {
if (session == null) {
CURRENT.set(null);
return true;
}
McpDialogSession existing = CURRENT.get();
if (existing != null) {
return false;
}
CURRENT.set(session);
return true;
}
public static McpDialogSession getCurrent() {
return CURRENT.get();
}
public static void setValue(String label, String value) {
public static boolean setValue(String label, String value) {
McpDialogSession session = CURRENT.get();
if (session == null) {
return;
return false;
}
session.setValue(label, value);
return true;
}
public static boolean setValueForId(String id, String label, String value) {
McpDialogSession session = CURRENT.get();
if (session == null || id == null || !id.equals(session.getId())) {
return false;
}
session.setValue(label, value);
return true;
}
public static boolean submitCurrent(boolean ok) {
McpDialogSession session = CURRENT.get();
if (session == null) {
return false;
}
session.submit(ok);
CURRENT.set(null);
return true;
}
public static boolean submitForId(String id, boolean ok) {
McpDialogSession session = CURRENT.get();
if (session == null || id == null || !id.equals(session.getId())) {
return false;
}
session.submit(ok);
CURRENT.set(null);
return true;
}
}
......@@ -8,10 +8,13 @@ import java.util.Map;
import java.util.UUID;
public class McpDialogSession {
public static final int debugLevel = -1; // name in the same case in most other places. Compares if (debugLevel >-3)
private final String id;
private final String title;
private final List<McpDialogField> fields;
private final Map<String, String> valuesByLabel;
private final Object submitLock = new Object();
private Boolean submittedOk = null;
public McpDialogSession(String title, List<McpDialogField> fields) {
this.id = UUID.randomUUID().toString();
......@@ -37,6 +40,41 @@ public class McpDialogSession {
return;
}
valuesByLabel.put(label, value);
if (debugLevel > -3) {
System.out.println("setValue("+label+","+value+")");
}
}
public void submit(boolean ok) {
synchronized (submitLock) {
submittedOk = Boolean.valueOf(ok);
submitLock.notifyAll();
if (debugLevel > -3) {
System.out.println("submit("+ok+")");
}
}
}
public Boolean awaitSubmit(long timeoutMs) {
synchronized (submitLock) {
if (submittedOk != null) {
return submittedOk;
}
long deadline = System.currentTimeMillis() + timeoutMs;
while (submittedOk == null) {
long remaining = deadline - System.currentTimeMillis();
if (remaining <= 0) {
break;
}
try {
submitLock.wait(remaining);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
return submittedOk;
}
}
public String getValue(String label) {
......
......@@ -72,9 +72,9 @@ public class McpFsAccess {
if (configPath != null && !configPath.trim().isEmpty()) {
Path configFile = Paths.get(configPath).toAbsolutePath().normalize();
roots.add(configFile);
Path configDir = configFile.getParent();
if (configDir != null) {
roots.add(configDir);
Path configDirFileParent = configFile.getParent();
if (configDirFileParent != null) {
roots.add(configDirFileParent);
}
addRootsFromConfig(configFile, roots);
}
......
......@@ -51,6 +51,7 @@ public class McpServer {
server.createContext("/mcp/status", new StatusHandler());
server.createContext("/mcp/dialog", new DialogHandler());
server.createContext("/mcp/dialog/values", new DialogValuesHandler());
server.createContext("/mcp/dialog/submit", new DialogSubmitHandler());
server.createContext("/mcp/button", new ButtonHandler());
server.createContext("/mcp/interrupt", new InterruptHandler());
server.createContext("/mcp/interrupt/confirm", new InterruptConfirmHandler());
......@@ -62,8 +63,10 @@ public class McpServer {
server.createContext("/mcp/fs/glob", new FsGlobHandler());
server.setExecutor(null);
server.start();
if (Eyesis_Correction.MCP_DEBUG_LEVEL >= Eyesis_Correction.MINIMAL_DEBUG_MCP) {
System.out.println("MCP: server started on http://127.0.0.1:" + port);
}
}
private class StatusHandler implements HttpHandler {
@Override
......@@ -89,14 +92,40 @@ public class McpServer {
return;
}
Map<String, String> params = parseParams(exchange);
String id = params.get("id");
String label = params.get("label");
String value = params.get("value");
if (label == null) {
sendJson(exchange, 400, "{\"ok\":false,\"error\":\"Missing label\"}");
return;
}
McpDialogRegistry.setValue(label, value);
boolean applied = (id == null) ? McpDialogRegistry.setValue(label, value) : McpDialogRegistry.setValueForId(id, label, value);
if (applied) {
if (Eyesis_Correction.MCP_DEBUG_LEVEL >= Eyesis_Correction.MINIMAL_DEBUG_MCP) {
System.out.println("MCP: dialog value label=\"" + label + "\"");
}
sendJson(exchange, 200, "{\"ok\":true}");
} else {
sendJson(exchange, 409, "{\"ok\":false,\"error\":\"No active dialog or id mismatch\"}");
}
}
}
private class DialogSubmitHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
if (!"POST".equalsIgnoreCase(exchange.getRequestMethod())) {
sendJson(exchange, 405, "{\"ok\":false,\"error\":\"POST required\"}");
return;
}
Map<String, String> params = parseParams(exchange);
String id = params.get("id");
boolean ok = parseBool(params.get("ok"), true);
boolean applied = (id == null) ? McpDialogRegistry.submitCurrent(ok) : McpDialogRegistry.submitForId(id, ok);
if (applied && Eyesis_Correction.MCP_DEBUG_LEVEL >= Eyesis_Correction.MINIMAL_DEBUG_MCP) {
System.out.println("MCP: dialog submit ok=" + ok);
}
sendJson(exchange, 200, applied ? "{\"ok\":true}" : "{\"ok\":false,\"error\":\"No active dialog\"}");
}
}
......@@ -113,7 +142,10 @@ public class McpServer {
sendJson(exchange, 400, "{\"ok\":false,\"error\":\"Missing label\"}");
return;
}
owner.triggerCommand(label);
owner.triggerCommand(label, true);
if (Eyesis_Correction.MCP_DEBUG_LEVEL >= Eyesis_Correction.MINIMAL_DEBUG_MCP) {
System.out.println("MCP: button \"" + label + "\"");
}
sendJson(exchange, 200, "{\"ok\":true}");
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment