package io.swtc; import com.github.sarxos.webcam.Webcam; import com.github.sarxos.webcam.WebcamCompositeDriver; import com.github.sarxos.webcam.ds.buildin.WebcamDefaultDriver; import com.github.sarxos.webcam.ds.ipcam.IpCamDeviceRegistry; import com.github.sarxos.webcam.ds.ipcam.IpCamDriver; import com.github.sarxos.webcam.ds.ipcam.IpCamMode; import io.swtc.networking.CameraConfig; import io.swtc.networking.CameraSettings; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.*; import java.net.MalformedURLException; import java.util.List; public class CCTVManager { static { Webcam.setDriver(new WebcamCompositeDriver() {{ add(new WebcamDefaultDriver()); add(new IpCamDriver()); }}); for (CameraConfig config : CameraSettings.load()) { try { IpCamDeviceRegistry.register(config.getName(), config.getUrl(), IpCamMode.PUSH); } catch (MalformedURLException e) { e.printStackTrace(); } } } public static void main(String[] args) { Display display = new Display(); Shell shell = new Shell(display); shell.setText("Dashboard"); shell.setSize(900, 600); renderUI(shell, display); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } private static void renderUI(Shell shell, Display display) { // Clear existing children if refreshing for (Control child : shell.getChildren()) child.dispose(); List webcams = Webcam.getWebcams(); int columnCount = Math.min(3, Math.max(1, webcams.size())); GridLayout mainLayout = new GridLayout(columnCount, true); mainLayout.marginWidth = 20; mainLayout.marginHeight = 20; shell.setLayout(mainLayout); // Header Section Composite header = new Composite(shell, SWT.NONE); header.setLayout(new GridLayout(2, false)); header.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, columnCount, 1)); Label title = new Label(header, SWT.NONE); title.setText("Connected Devices (" + webcams.size() + ")"); title.setFont(new Font(display, "Segoe UI", 16, SWT.BOLD)); title.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); Button addBtn = new Button(header, SWT.PUSH); addBtn.setText("+ Add IP Camera"); addBtn.addListener(SWT.Selection, e -> showAddCameraDialog(shell, display)); if (webcams.isEmpty()) { Label note = new Label(shell, SWT.NONE); note.setText("No cameras detected. Add an IP camera to begin."); } else { for (Webcam webcam : webcams) { createCameraCard(shell, display, webcam); } } shell.layout(true, true); } private static void createCameraCard(Composite parent, Display display, Webcam webcam) { // We check if its a IP Cam by getting the class, if it is then we show the delete button boolean isIpCam = webcam.getDevice().getClass().getSimpleName().contains("IpCam"); Group card = new Group(parent, SWT.NONE); card.setText(webcam.getName()); card.setLayout(new GridLayout(2, false)); card.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); Label info = new Label(card, SWT.WRAP); info.setText("Type: " + (isIpCam ? "Network IP" : "Local USB")); info.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); Button viewBtn = new Button(card, SWT.PUSH); viewBtn.setText("Launch"); viewBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); viewBtn.addListener(SWT.Selection, e -> new CameraWindow(display, webcam).open()); Button deleteBtn = new Button(card, SWT.PUSH); deleteBtn.setText("Delete"); deleteBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); // this is where we do that, this is where the ipcam class is used deleteBtn.setEnabled(isIpCam); deleteBtn.addListener(SWT.Selection, e -> { MessageBox mb = new MessageBox(parent.getShell(), SWT.ICON_QUESTION | SWT.YES | SWT.NO); mb.setText("Confirm"); mb.setMessage("Remove " + webcam.getName() + "?"); if (mb.open() == SWT.YES) { CameraSettings.delete(webcam.getName()); IpCamDeviceRegistry.unregister(webcam.getName()); renderUI(parent.getShell(), display); } }); } private static void showAddCameraDialog(Shell parent, Display display) { Shell dialog = new Shell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL); dialog.setText("Register New IP Camera"); dialog.setLayout(new GridLayout(2, false)); new Label(dialog, SWT.NONE).setText("Name:"); Text nameIn = new Text(dialog, SWT.BORDER); nameIn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); new Label(dialog, SWT.NONE).setText("MJPEG URL:"); Text urlIn = new Text(dialog, SWT.BORDER); urlIn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); urlIn.setMessage("http://10.0.0.x/mjpeg"); // Error message label Label errorLabel = new Label(dialog, SWT.NONE); errorLabel.setForeground(display.getSystemColor(SWT.COLOR_RED)); errorLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); errorLabel.setVisible(false); Button save = new Button(dialog, SWT.PUSH); save.setText("Add Camera"); save.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); // error handling for stoopid people save.addListener(SWT.Selection, e -> { String name = nameIn.getText().trim(); String urlString = urlIn.getText().trim(); if (name.isEmpty() || urlString.isEmpty()) { errorLabel.setText("Error: All fields are required."); errorLabel.setVisible(true); dialog.pack(); return; } try { if (!urlString.toLowerCase().startsWith("http://") && !urlString.toLowerCase().startsWith("https://")) { throw new MalformedURLException("URL must start with http:// or https://"); } java.net.URL validatedUrl = new java.net.URL(urlString); IpCamDeviceRegistry.register(name, validatedUrl.toExternalForm(), IpCamMode.PUSH); CameraSettings.save(new CameraConfig(name, validatedUrl.toExternalForm())); dialog.close(); renderUI(parent, display); } catch (MalformedURLException ex) { errorLabel.setText("Invalid URL: " + ex.getMessage()); errorLabel.setVisible(true); dialog.pack(); } catch (Exception ex) { errorLabel.setText("Registration failed: " + ex.getMessage()); errorLabel.setVisible(true); dialog.pack(); } }); dialog.pack(); dialog.open(); } }