Files
WebClient/src/main/java/org/openautonomousconnection/webclient/ui/BrowserUI.java

237 lines
7.7 KiB
Java
Raw Normal View History

package org.openautonomousconnection.webclient.ui;
2026-02-08 22:36:42 +01:00
import org.openautonomousconnection.oacswing.component.OACButton;
import org.openautonomousconnection.oacswing.component.OACFrame;
import org.openautonomousconnection.oacswing.component.OACPanel;
import org.openautonomousconnection.oacswing.component.OACTextField;
import org.openautonomousconnection.oacswing.component.design.DesignManager;
import javax.swing.*;
import java.awt.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
/**
* A simple multi-tab browser UI:
* - Tab headers live in the custom title bar (OACTitleBar / OACTabbedPane).
* - Tab content (JavaFX WebView) lives in the frame content area.
* - Address bar controls the currently selected tab.
*/
public class BrowserUI extends OACFrame {
private static final int TITLE_BAR_HEIGHT = 42;
private final OACTextField addressField;
private final OACButton goButton;
private final OACButton newTabButton;
private final OACButton closeTabButton;
private final OACButton backButton;
private final OACButton forwardButton;
private final OACButton reloadButton;
private final CardLayout cardLayout;
private final OACPanel pageHost;
private final Map<String, BrowserTab> tabsByKey = new LinkedHashMap<>();
private int tabCounter = 0;
/**
* Creates the browser UI and wires tab selection and address bar to tab content.
*/
public BrowserUI() {
super("OAC Browser");
// Content pane must be offset because your title bar is an overlay in the layered pane.
JComponent content = (JComponent) getContentPane();
content.setLayout(new BorderLayout());
content.setBorder(BorderFactory.createEmptyBorder(TITLE_BAR_HEIGHT, 0, 0, 0));
// Address bar (top of content area)
OACPanel navBar = new OACPanel(new BorderLayout(8, 0));
navBar.setBorder(BorderFactory.createEmptyBorder(8, 10, 8, 10));
OACPanel leftControls = new OACPanel(new FlowLayout(FlowLayout.LEFT, 6, 0));
backButton = new OACButton("");
forwardButton = new OACButton("");
reloadButton = new OACButton("");
leftControls.add(backButton);
leftControls.add(forwardButton);
leftControls.add(reloadButton);
addressField = new OACTextField();
goButton = new OACButton("Go");
OACPanel rightControls = new OACPanel(new FlowLayout(FlowLayout.RIGHT, 6, 0));
newTabButton = new OACButton("+");
closeTabButton = new OACButton("");
rightControls.add(newTabButton);
rightControls.add(closeTabButton);
navBar.add(leftControls, BorderLayout.WEST);
navBar.add(addressField, BorderLayout.CENTER);
navBar.add(goButton, BorderLayout.EAST);
navBar.add(rightControls, BorderLayout.EAST);
// Fix: BorderLayout only allows one EAST; wrap Go+RightControls in a single panel
OACPanel east = new OACPanel(new FlowLayout(FlowLayout.RIGHT, 6, 0));
east.add(goButton);
east.add(newTabButton);
east.add(closeTabButton);
navBar.add(east, BorderLayout.EAST);
content.add(navBar, BorderLayout.NORTH);
// Page host
cardLayout = new CardLayout();
pageHost = new OACPanel(cardLayout);
content.add(pageHost, BorderLayout.CENTER);
// Wire title bar tab selection to content host
getTitleBar().getTabs().addChangeListener(e -> onHeaderTabChanged());
// Wire address bar actions
addressField.addActionListener(e -> navigateCurrent(addressField.getText()));
goButton.addActionListener(e -> navigateCurrent(addressField.getText()));
// Wire navigation buttons
backButton.addActionListener(e -> {
BrowserTab tab = getCurrentTab();
if (tab != null) tab.goBack();
});
forwardButton.addActionListener(e -> {
BrowserTab tab = getCurrentTab();
if (tab != null) tab.goForward();
});
reloadButton.addActionListener(e -> {
BrowserTab tab = getCurrentTab();
if (tab != null) tab.reload();
});
newTabButton.addActionListener(e -> openNewTab("web://info.oac/"));
2026-02-08 22:36:42 +01:00
closeTabButton.addActionListener(e -> closeCurrentTab());
// Create first tab
DesignManager.apply(this);
}
/**
* Opens a new tab and navigates to the given URL.
*
* @param url initial URL
*/
public void openNewTab(String url) {
String key = nextTabKey();
BrowserTab tab = new BrowserTab(url, newLocation -> SwingUtilities.invokeLater(() -> {
BrowserTab current = getCurrentTab();
if (current != null && Objects.equals(current.getKey(), key)) {
addressField.setText(newLocation);
}
}));
tabsByKey.put(key, tab);
// Real page content in center host
pageHost.add(tab.getView(), key);
// Header tab in title bar: DO NOT place the real page here (title bar is only ~42px high).
getTitleBar().addTab(key, new OACPanel());
// Select it
int idx = getTitleBar().getTabs().getTabCount() - 1;
getTitleBar().getTabs().setSelectedIndex(idx);
// Navigate
tab.loadUrl(url);
2026-02-08 22:36:42 +01:00
// Show content
cardLayout.show(pageHost, key);
pageHost.revalidate();
pageHost.repaint();
// Update address field immediately
addressField.setText(url);
}
/**
* Navigates the current tab to the given input (URL or host).
*
* @param input user input
*/
public void navigateCurrent(String input) {
BrowserTab tab = getCurrentTab();
if (tab == null) return;
String url = normalizeUrl(input);
addressField.setText(url);
tab.loadUrl(url);
2026-02-08 22:36:42 +01:00
}
/**
* Closes the currently selected tab.
*/
public void closeCurrentTab() {
int idx = getTitleBar().getTabs().getSelectedIndex();
if (idx < 0) return;
String key = getTitleBar().getTabs().getTitleAt(idx);
BrowserTab removed = tabsByKey.remove(key);
if (removed != null) {
removed.dispose();
pageHost.remove(removed.getView());
}
getTitleBar().getTabs().removeTabAt(idx);
// If no tabs left, open a new one
if (getTitleBar().getTabs().getTabCount() == 0) {
openNewTab("web://info.oac/");
2026-02-08 22:36:42 +01:00
return;
}
// Show selected tab content
onHeaderTabChanged();
}
private void onHeaderTabChanged() {
BrowserTab tab = getCurrentTab();
if (tab == null) return;
cardLayout.show(pageHost, tab.getKey());
pageHost.revalidate();
pageHost.repaint();
// Sync address bar
String loc = tab.getLocation();
if (loc != null && !loc.isBlank()) {
addressField.setText(loc);
}
}
public BrowserTab getCurrentTab() {
int idx = getTitleBar().getTabs().getSelectedIndex();
if (idx < 0) return null;
String key = getTitleBar().getTabs().getTitleAt(idx);
return tabsByKey.get(key);
}
private String nextTabKey() {
tabCounter++;
return "Tab " + tabCounter;
}
private static String normalizeUrl(String input) {
String s = input == null ? "" : input.trim();
if (s.isEmpty()) return "web://info.oac/";
if (s.startsWith("web://")) {
// Ensure trailing slash for "host only" URLs
String rest = s.substring("web://".length());
if (!rest.contains("/")) return s + "/";
return s;
}
return "web://" + s + (s.contains("/") ? "" : "/");
2026-02-08 22:36:42 +01:00
}
}