Compare commits
1 Commits
STAB.c32b5
...
stabilisat
| Author | SHA1 | Date | |
|---|---|---|---|
| 40a6183529 |
@@ -2,26 +2,37 @@ package io.swtc;
|
|||||||
|
|
||||||
import com.github.sarxos.webcam.Webcam;
|
import com.github.sarxos.webcam.Webcam;
|
||||||
import com.github.sarxos.webcam.WebcamCompositeDriver;
|
import com.github.sarxos.webcam.WebcamCompositeDriver;
|
||||||
|
import com.github.sarxos.webcam.WebcamDevice;
|
||||||
import com.github.sarxos.webcam.ds.buildin.WebcamDefaultDriver;
|
import com.github.sarxos.webcam.ds.buildin.WebcamDefaultDriver;
|
||||||
import com.github.sarxos.webcam.ds.ipcam.IpCamDeviceRegistry;
|
import com.github.sarxos.webcam.ds.ipcam.*;
|
||||||
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.CameraConfig;
|
||||||
import io.swtc.networking.CameraSettings;
|
import io.swtc.networking.CameraSettings;
|
||||||
import io.swtc.proccessing.ui.IconSetter;
|
import io.swtc.proccessing.ui.IconSetter;
|
||||||
|
import io.swtc.proccessing.ui.ShowError;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.table.DefaultTableCellRenderer;
|
import javax.swing.table.DefaultTableCellRenderer;
|
||||||
import javax.swing.table.DefaultTableModel;
|
import javax.swing.table.DefaultTableModel;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.awt.datatransfer.DataFlavor;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SwingCCTVManager {
|
public class SwingCCTVManager {
|
||||||
|
|
||||||
|
private static final String TIMEOUT_MS = "1500";
|
||||||
|
private static final int REFRESH_INTERVAL = 30000;
|
||||||
|
private static final String STATUS_ONLINE = "ONLINE";
|
||||||
|
private static final String STATUS_OFFLINE = "OFFLINE";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
System.setProperty("ipcam.connection.timeout", TIMEOUT_MS);
|
||||||
Webcam.setDriver(new WebcamCompositeDriver() {{
|
Webcam.setDriver(new WebcamCompositeDriver() {{
|
||||||
add(new WebcamDefaultDriver());
|
add(new WebcamDefaultDriver());
|
||||||
add(new IpCamDriver());
|
add(new IpCamDriver());
|
||||||
@@ -33,227 +44,237 @@ public class SwingCCTVManager {
|
|||||||
private final JTable deviceTable;
|
private final JTable deviceTable;
|
||||||
private final DefaultTableModel tableModel;
|
private final DefaultTableModel tableModel;
|
||||||
private final SwingIFrame IFrame;
|
private final SwingIFrame IFrame;
|
||||||
|
private boolean isRefreshing = false;
|
||||||
|
|
||||||
public SwingCCTVManager() {
|
public SwingCCTVManager() {
|
||||||
frame = new JFrame("dashboard");
|
frame = new JFrame("Dashboard");
|
||||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
frame.setSize(1000, 600);
|
frame.setSize(1100, 600);
|
||||||
frame.setIconImage(IconSetter.getIcon());
|
frame.setIconImage(IconSetter.getIcon());
|
||||||
|
|
||||||
this.IFrame = new SwingIFrame();
|
this.IFrame = new SwingIFrame();
|
||||||
this.IFrame.show();
|
this.IFrame.show();
|
||||||
|
|
||||||
String[] columns = {"Status", "Device Name", "Type", "Resolution", "Address"};
|
tableModel = new DefaultTableModel(new String[]{"Status", "Device Name", "Type", "Resolution", "Address"}, 0) {
|
||||||
tableModel = new DefaultTableModel(columns, 0) {
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCellEditable(int r, int c) {
|
public boolean isCellEditable(int r, int c) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
deviceTable = new JTable(tableModel);
|
deviceTable = new JTable(tableModel);
|
||||||
|
|
||||||
deviceTable.setRowSelectionAllowed(true);
|
|
||||||
deviceTable.setFocusable(true);
|
|
||||||
deviceTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
|
||||||
|
|
||||||
setupTableAppearance();
|
setupTableAppearance();
|
||||||
|
setupDragAndDrop(); // Initialize DND
|
||||||
deviceTable.addMouseListener(new MouseAdapter() {
|
setupListeners();
|
||||||
@Override
|
|
||||||
public void mousePressed(MouseEvent e) {
|
|
||||||
deviceTable.requestFocusInWindow();
|
|
||||||
|
|
||||||
if (e.getClickCount() == 2 && deviceTable.getSelectedRow() != -1) {
|
|
||||||
launchSelected();
|
|
||||||
}
|
|
||||||
if (SwingUtilities.isRightMouseButton(e)) {
|
|
||||||
showContextMenu(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
JToolBar toolBar = new JToolBar();
|
JToolBar toolBar = new JToolBar();
|
||||||
|
setupBrandedToolbar(toolBar);
|
||||||
Image ogIcon = IconSetter.getIcon();
|
|
||||||
Image scaledIcon = ogIcon.getScaledInstance(32, 32, Image.SCALE_SMOOTH);
|
|
||||||
JLabel iconLabel = new JLabel(new ImageIcon(scaledIcon));
|
|
||||||
toolBar.add(iconLabel);
|
|
||||||
|
|
||||||
JLabel textLabel = new JLabel("SWT-CCTV");
|
|
||||||
toolBar.add(textLabel);
|
|
||||||
|
|
||||||
toolBar.add(Box.createRigidArea(new Dimension(10, 0))); // 20px horizontal padding
|
|
||||||
|
|
||||||
toolBar.addSeparator(new Dimension(10, 32)); // 10px width, 32px height
|
|
||||||
|
|
||||||
JButton btnAdd = new JButton("Add IP Cam");
|
|
||||||
JButton btnLaunch = new JButton("Launch Stream");
|
|
||||||
|
|
||||||
btnAdd.setPreferredSize(new Dimension(100, 32));
|
|
||||||
btnLaunch.setPreferredSize(new Dimension(120, 32));
|
|
||||||
|
|
||||||
toolBar.add(Box.createRigidArea(new Dimension(5,0)));
|
|
||||||
toolBar.add(btnAdd);
|
|
||||||
toolBar.addSeparator();
|
|
||||||
toolBar.add(btnLaunch);
|
|
||||||
|
|
||||||
frame.add(toolBar, BorderLayout.SOUTH);
|
frame.add(toolBar, BorderLayout.SOUTH);
|
||||||
frame.add(new JScrollPane(deviceTable), BorderLayout.CENTER);
|
frame.add(new JScrollPane(deviceTable), BorderLayout.CENTER);
|
||||||
|
|
||||||
btnAdd.addActionListener(e -> showAddCameraDialog());
|
|
||||||
btnLaunch.addActionListener(e -> launchSelected());
|
|
||||||
|
|
||||||
startAutoRefresh();
|
startAutoRefresh();
|
||||||
refreshTable();
|
refreshTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupTableAppearance() {
|
private void setupBrandedToolbar(JToolBar toolBar) {
|
||||||
deviceTable.getColumnModel().getColumn(0).setMaxWidth(80);
|
Image ogIcon = IconSetter.getIcon();
|
||||||
deviceTable.setRowHeight(30);
|
if (ogIcon != null) {
|
||||||
|
Image scaledIcon = ogIcon.getScaledInstance(32, 32, Image.SCALE_SMOOTH);
|
||||||
deviceTable.getColumnModel().getColumn(0)
|
toolBar.add(new JLabel(new ImageIcon(scaledIcon)));
|
||||||
.setCellRenderer(new DefaultTableCellRenderer() {
|
|
||||||
@Override
|
|
||||||
public Component getTableCellRendererComponent(
|
|
||||||
JTable t, Object v, boolean s, boolean f, int r, int c) {
|
|
||||||
|
|
||||||
Component comp = super.getTableCellRendererComponent(t, v, s, f, r, c);
|
|
||||||
setHorizontalAlignment(JLabel.CENTER);
|
|
||||||
comp.setForeground("ONLINE".equals(v)
|
|
||||||
? new Color(0, 150, 0)
|
|
||||||
: Color.RED);
|
|
||||||
return comp;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startAutoRefresh() {
|
|
||||||
new Timer(5000, e -> refreshTable()).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshTable() {
|
|
||||||
int[] selectedRows = deviceTable.getSelectedRows();
|
|
||||||
|
|
||||||
tableModel.setRowCount(0);
|
|
||||||
List<Webcam> webcams = Webcam.getWebcams();
|
|
||||||
|
|
||||||
for (Webcam w : webcams) {
|
|
||||||
boolean isIp = w.getDevice().getClass().getSimpleName().contains("IpCam");
|
|
||||||
String status = w.getDevice() != null ? "ONLINE" : "OFFLINE";
|
|
||||||
|
|
||||||
tableModel.addRow(new Object[]{
|
|
||||||
status,
|
|
||||||
w.getName(),
|
|
||||||
isIp ? "IP Stream" : "USB Hardware",
|
|
||||||
w.getViewSize().width + "x" + w.getViewSize().height,
|
|
||||||
isIp ? "Network" : "Local"
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int r : selectedRows) {
|
toolBar.add(new JLabel("SWT-CCTV"));
|
||||||
if (r < tableModel.getRowCount()) {
|
toolBar.add(Box.createRigidArea(new Dimension(10, 0)));
|
||||||
deviceTable.addRowSelectionInterval(r, r);
|
toolBar.addSeparator(new Dimension(10, 32));
|
||||||
|
|
||||||
|
JButton btnAdd = new JButton("Add IP Cam");
|
||||||
|
JButton btnImport = new JButton("Import Config"); // New Import Button
|
||||||
|
JButton btnLaunch = new JButton("Launch Stream");
|
||||||
|
|
||||||
|
btnAdd.setPreferredSize(new Dimension(100, 32));
|
||||||
|
btnImport.setPreferredSize(new Dimension(110, 32));
|
||||||
|
btnLaunch.setPreferredSize(new Dimension(120, 32));
|
||||||
|
|
||||||
|
toolBar.add(Box.createRigidArea(new Dimension(5, 0)));
|
||||||
|
toolBar.add(btnAdd);
|
||||||
|
toolBar.add(btnImport);
|
||||||
|
toolBar.addSeparator();
|
||||||
|
toolBar.add(btnLaunch);
|
||||||
|
|
||||||
|
btnAdd.addActionListener(e -> showAddCameraDialog());
|
||||||
|
btnImport.addActionListener(e -> showImportDialog());
|
||||||
|
btnLaunch.addActionListener(e -> launchSelected());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupDragAndDrop() {
|
||||||
|
deviceTable.setDragEnabled(true);
|
||||||
|
deviceTable.setTransferHandler(new TransferHandler() {
|
||||||
|
@Override
|
||||||
|
public boolean canImport(TransferSupport support) {
|
||||||
|
return support.isDataFlavorSupported(DataFlavor.javaFileListFlavor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean importData(TransferSupport support) {
|
||||||
|
if (!canImport(support)) return false;
|
||||||
|
try {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<File> files = (List<File>) support.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.getName().endsWith(".json")) {
|
||||||
|
List<CameraConfig> configs = CameraSettings.loadFromFile(file);
|
||||||
|
importCameras(configs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showImportDialog() {
|
||||||
|
JFileChooser chooser = new JFileChooser();
|
||||||
|
chooser.setDialogTitle("Select Camera Configuration JSON");
|
||||||
|
if (chooser.showOpenDialog(frame) == JFileChooser.APPROVE_OPTION) {
|
||||||
|
File file = chooser.getSelectedFile();
|
||||||
|
List<CameraConfig> configs = CameraSettings.loadFromFile(file);
|
||||||
|
importCameras(configs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showContextMenu(MouseEvent e) {
|
private void importCameras(List<CameraConfig> configs) {
|
||||||
int row = deviceTable.rowAtPoint(e.getPoint());
|
if (configs.isEmpty()) {
|
||||||
if (row >= 0) {
|
ShowError.warning(frame, "Import Empty", "No valid camera configurations found in file.");
|
||||||
deviceTable.setRowSelectionInterval(row, row);
|
return;
|
||||||
}
|
}
|
||||||
|
for (CameraConfig config : configs) {
|
||||||
|
try {
|
||||||
|
if (!IpCamDeviceRegistry.isRegistered(config.getName())) {
|
||||||
|
IpCamDeviceRegistry.register(config.getName(), config.getUrl(), IpCamMode.PUSH);
|
||||||
|
CameraSettings.save(config);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
refreshTable();
|
||||||
|
}
|
||||||
|
|
||||||
JPopupMenu menu = new JPopupMenu();
|
private void setupTableAppearance() {
|
||||||
JMenuItem ico = new JMenuItem("test");
|
deviceTable.setRowHeight(30);
|
||||||
JMenuItem launch = new JMenuItem("Launch Live Stream");
|
deviceTable.getColumnModel().getColumn(0).setMaxWidth(80);
|
||||||
JMenuItem delete = new JMenuItem("Remove Device");
|
deviceTable.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
|
||||||
|
@Override
|
||||||
|
public Component getTableCellRendererComponent(JTable t, Object v, boolean s, boolean f, int r, int c) {
|
||||||
|
Component comp = super.getTableCellRendererComponent(t, v, s, f, r, c);
|
||||||
|
setHorizontalAlignment(JLabel.CENTER);
|
||||||
|
comp.setForeground(STATUS_ONLINE.equals(v) ? new Color(0, 150, 0) : Color.RED);
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
launch.addActionListener(al -> launchSelected());
|
private synchronized void refreshTable() {
|
||||||
delete.addActionListener(al -> deleteSelected());
|
if (isRefreshing) return;
|
||||||
|
isRefreshing = true;
|
||||||
|
final int selectedRow = deviceTable.getSelectedRow();
|
||||||
|
new SwingWorker<Void, Object[]>() {
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground() {
|
||||||
|
for (WebcamDevice device : new WebcamDefaultDriver().getDevices()) {
|
||||||
|
Dimension res = (device.getResolutions().length > 0) ? device.getResolutions()[0] : new Dimension(0,0);
|
||||||
|
publish(new Object[]{STATUS_ONLINE, device.getName(), "USB Hardware", res.width + "x" + res.height, "Local"});
|
||||||
|
}
|
||||||
|
for (IpCamDevice ipDevice : IpCamDeviceRegistry.getIpCameras()) {
|
||||||
|
publish(probeIpCamera(ipDevice));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void process(List<Object[]> chunks) {
|
||||||
|
if (!Boolean.TRUE.equals(frame.getRootPane().getClientProperty("cleared"))) {
|
||||||
|
tableModel.setRowCount(0);
|
||||||
|
frame.getRootPane().putClientProperty("cleared", true);
|
||||||
|
}
|
||||||
|
for (Object[] row : chunks) tableModel.addRow(row);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
frame.getRootPane().putClientProperty("cleared", null);
|
||||||
|
if (selectedRow != -1 && selectedRow < tableModel.getRowCount()) {
|
||||||
|
deviceTable.setRowSelectionInterval(selectedRow, selectedRow);
|
||||||
|
}
|
||||||
|
isRefreshing = false;
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
menu.add(ico);
|
private Object[] probeIpCamera(IpCamDevice ipDevice) {
|
||||||
menu.add(launch);
|
String status = STATUS_OFFLINE; String resText = "N/A";
|
||||||
menu.addSeparator();
|
try {
|
||||||
menu.add(delete);
|
URL url = ipDevice.getURL();
|
||||||
menu.show(deviceTable, e.getX(), e.getY());
|
try (Socket socket = new Socket()) {
|
||||||
|
socket.connect(new InetSocketAddress(url.getHost(), url.getPort() != -1 ? url.getPort() : 80), 800);
|
||||||
|
Dimension d = ipDevice.getResolution();
|
||||||
|
if (d != null) { status = STATUS_ONLINE; resText = d.width + "x" + d.height; }
|
||||||
|
}
|
||||||
|
} catch (Exception e) { status = STATUS_OFFLINE; }
|
||||||
|
return new Object[]{status, ipDevice.getName(), "IP Stream", resText, "Network"};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void launchSelected() {
|
private void launchSelected() {
|
||||||
int row = deviceTable.getSelectedRow();
|
int row = deviceTable.getSelectedRow();
|
||||||
if (row == -1) return;
|
if (row == -1) return;
|
||||||
|
|
||||||
String name = (String) tableModel.getValueAt(row, 1);
|
String name = (String) tableModel.getValueAt(row, 1);
|
||||||
Webcam.getWebcams().stream()
|
if (STATUS_OFFLINE.equals(tableModel.getValueAt(row, 0))) {
|
||||||
.filter(w -> w.getName().equals(name))
|
ShowError.warning(frame, "Device Offline", "Cannot connect to '" + name + "'.");
|
||||||
.findFirst()
|
return;
|
||||||
.ifPresent(cam ->
|
|
||||||
new Thread(() -> IFrame.addCameraInternalFrame(cam)).start()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteSelected() {
|
|
||||||
int row = deviceTable.getSelectedRow();
|
|
||||||
if (row == -1) return;
|
|
||||||
|
|
||||||
String name = (String) tableModel.getValueAt(row, 1);
|
|
||||||
if (name.toLowerCase().contains("usb")) return;
|
|
||||||
|
|
||||||
CameraSettings.delete(name);
|
|
||||||
IpCamDeviceRegistry.unregister(name);
|
|
||||||
refreshTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void loadSavedCameras() {
|
|
||||||
for (CameraConfig config : CameraSettings.load()) {
|
|
||||||
try {
|
|
||||||
IpCamDeviceRegistry.register(
|
|
||||||
config.getName(),
|
|
||||||
config.getUrl(),
|
|
||||||
IpCamMode.PUSH
|
|
||||||
);
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
JOptionPane.showMessageDialog(
|
|
||||||
null,
|
|
||||||
"Malformed URL\n" + e.getMessage(),
|
|
||||||
"Malformed URL",
|
|
||||||
JOptionPane.ERROR_MESSAGE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
new Thread(() -> {
|
||||||
|
Webcam selected = Webcam.getWebcams().stream().filter(w -> w.getName().equals(name)).findFirst().orElse(null);
|
||||||
|
if (selected != null) IFrame.addCameraInternalFrame(selected);
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showAddCameraDialog() {
|
private void showAddCameraDialog() {
|
||||||
JPanel p = new JPanel(new GridLayout(2, 2, 5, 5));
|
JPanel p = new JPanel(new GridLayout(2, 2, 5, 5));
|
||||||
JTextField n = new JTextField();
|
JTextField n = new JTextField(); JTextField u = new JTextField();
|
||||||
JTextField u = new JTextField();
|
p.add(new JLabel("Name:")); p.add(n); p.add(new JLabel("URL:")); p.add(u);
|
||||||
|
if (JOptionPane.showConfirmDialog(frame, p, "Register IP Camera", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
|
||||||
p.add(new JLabel("Name:"));
|
importCameras(List.of(new CameraConfig(n.getText(), u.getText())));
|
||||||
p.add(n);
|
|
||||||
p.add(new JLabel("URL:"));
|
|
||||||
p.add(u);
|
|
||||||
|
|
||||||
int result = JOptionPane.showConfirmDialog(
|
|
||||||
frame, p, "Register IP Camera", JOptionPane.OK_CANCEL_OPTION
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result == JOptionPane.OK_OPTION) {
|
|
||||||
try {
|
|
||||||
IpCamDeviceRegistry.register(n.getText(), u.getText(), IpCamMode.PUSH);
|
|
||||||
CameraSettings.save(new CameraConfig(n.getText(), u.getText()));
|
|
||||||
refreshTable();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
JOptionPane.showMessageDialog(frame, "Error: " + ex.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void open() {
|
private void setupListeners() {
|
||||||
frame.setLocationRelativeTo(null);
|
deviceTable.addMouseListener(new MouseAdapter() {
|
||||||
frame.setVisible(true);
|
@Override
|
||||||
|
public void mousePressed(MouseEvent e) {
|
||||||
|
deviceTable.requestFocusInWindow();
|
||||||
|
if (e.getClickCount() == 2 && deviceTable.getSelectedRow() != -1) launchSelected();
|
||||||
|
if (SwingUtilities.isRightMouseButton(e)) showContextMenu(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showContextMenu(MouseEvent e) {
|
||||||
|
int row = deviceTable.rowAtPoint(e.getPoint());
|
||||||
|
if (row >= 0) deviceTable.setRowSelectionInterval(row, row);
|
||||||
|
JPopupMenu menu = new JPopupMenu();
|
||||||
|
JMenuItem launch = new JMenuItem("Launch Live Stream");
|
||||||
|
launch.addActionListener(al -> launchSelected());
|
||||||
|
menu.add(launch);
|
||||||
|
menu.show(deviceTable, e.getX(), e.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void loadSavedCameras() {
|
||||||
|
for (CameraConfig config : CameraSettings.load()) {
|
||||||
|
try { IpCamDeviceRegistry.register(config.getName(), config.getUrl(), IpCamMode.PUSH); } catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startAutoRefresh() { new Timer(REFRESH_INTERVAL, e -> refreshTable()).start(); }
|
||||||
|
|
||||||
|
public void open() { frame.setLocationRelativeTo(null); frame.setVisible(true); }
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SwingUtilities.invokeLater(() -> new SwingCCTVManager().open());
|
SwingUtilities.invokeLater(() -> new SwingCCTVManager().open());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ public class CameraConfig {
|
|||||||
public String url;
|
public String url;
|
||||||
|
|
||||||
// Default constructor for Jackson
|
// Default constructor for Jackson
|
||||||
|
public CameraConfig() {}
|
||||||
|
|
||||||
public CameraConfig(String name, String url) {
|
public CameraConfig(String name, String url) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|||||||
@@ -7,24 +7,32 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/*
|
|
||||||
* Some JSON stuff for camera config saving
|
|
||||||
* */
|
|
||||||
public class CameraSettings {
|
public class CameraSettings {
|
||||||
private static final File storage_file = new File("network_cameras.json");
|
private static final File STORAGE_FILE = new File("network_cameras.json");
|
||||||
private static final ObjectMapper mapper = new ObjectMapper();
|
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
public static List<CameraConfig> load() {
|
public static List<CameraConfig> load() {
|
||||||
if (!storage_file.exists() || storage_file.length() == 0) return new ArrayList<>();
|
return loadFromFile(STORAGE_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<CameraConfig> loadFromFile(File file) {
|
||||||
|
if (!file.exists() || file.length() == 0) return new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
return mapper.readValue(storage_file, new TypeReference<List<CameraConfig>>() {});
|
return MAPPER.readValue(file, new TypeReference<List<CameraConfig>>() {});
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
System.err.println("Error reading camera config: " + e.getMessage());
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a single camera. Prevents duplicates by name.
|
||||||
|
*/
|
||||||
public static void save(CameraConfig newCam) {
|
public static void save(CameraConfig newCam) {
|
||||||
List<CameraConfig> current = load();
|
List<CameraConfig> current = load();
|
||||||
|
// Prevent duplicate names in the local storage
|
||||||
|
current.removeIf(cam -> cam.getName().equalsIgnoreCase(newCam.getName()));
|
||||||
current.add(newCam);
|
current.add(newCam);
|
||||||
write(current);
|
write(current);
|
||||||
}
|
}
|
||||||
@@ -37,7 +45,7 @@ public class CameraSettings {
|
|||||||
|
|
||||||
private static void write(List<CameraConfig> list) {
|
private static void write(List<CameraConfig> list) {
|
||||||
try {
|
try {
|
||||||
mapper.writerWithDefaultPrettyPrinter().writeValue(storage_file, list);
|
MAPPER.writerWithDefaultPrettyPrinter().writeValue(STORAGE_FILE, list);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user