Files
swt-cctv/src/main/java/io/swtc/SwingCCTVManager.java

281 lines
11 KiB
Java

package io.swtc;
import com.github.sarxos.webcam.Webcam;
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.ipcam.*;
import io.swtc.networking.CameraConfig;
import io.swtc.networking.CameraSettings;
import io.swtc.proccessing.ui.IconSetter;
import io.swtc.proccessing.ui.ShowError;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.util.List;
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 {
System.setProperty("ipcam.connection.timeout", TIMEOUT_MS);
Webcam.setDriver(new WebcamCompositeDriver() {{
add(new WebcamDefaultDriver());
add(new IpCamDriver());
}});
loadSavedCameras();
}
private final JFrame frame;
private final JTable deviceTable;
private final DefaultTableModel tableModel;
private final SwingIFrame IFrame;
private boolean isRefreshing = false;
public SwingCCTVManager() {
frame = new JFrame("Dashboard");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1100, 600);
frame.setIconImage(IconSetter.getIcon());
this.IFrame = new SwingIFrame();
this.IFrame.show();
tableModel = new DefaultTableModel(new String[]{"Status", "Device Name", "Type", "Resolution", "Address"}, 0) {
@Override
public boolean isCellEditable(int r, int c) { return false; }
};
deviceTable = new JTable(tableModel);
setupTableAppearance();
setupDragAndDrop(); // Initialize DND
setupListeners();
JToolBar toolBar = new JToolBar();
setupBrandedToolbar(toolBar);
frame.add(toolBar, BorderLayout.SOUTH);
frame.add(new JScrollPane(deviceTable), BorderLayout.CENTER);
startAutoRefresh();
refreshTable();
}
private void setupBrandedToolbar(JToolBar toolBar) {
Image ogIcon = IconSetter.getIcon();
if (ogIcon != null) {
Image scaledIcon = ogIcon.getScaledInstance(32, 32, Image.SCALE_SMOOTH);
toolBar.add(new JLabel(new ImageIcon(scaledIcon)));
}
toolBar.add(new JLabel("SWT-CCTV"));
toolBar.add(Box.createRigidArea(new Dimension(10, 0)));
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 importCameras(List<CameraConfig> configs) {
if (configs.isEmpty()) {
ShowError.warning(frame, "Import Empty", "No valid camera configurations found in file.");
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();
}
private void setupTableAppearance() {
deviceTable.setRowHeight(30);
deviceTable.getColumnModel().getColumn(0).setMaxWidth(80);
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;
}
});
}
private synchronized void refreshTable() {
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();
}
private Object[] probeIpCamera(IpCamDevice ipDevice) {
String status = STATUS_OFFLINE; String resText = "N/A";
try {
URL url = ipDevice.getURL();
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() {
int row = deviceTable.getSelectedRow();
if (row == -1) return;
String name = (String) tableModel.getValueAt(row, 1);
if (STATUS_OFFLINE.equals(tableModel.getValueAt(row, 0))) {
ShowError.warning(frame, "Device Offline", "Cannot connect to '" + name + "'.");
return;
}
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() {
JPanel p = new JPanel(new GridLayout(2, 2, 5, 5));
JTextField n = 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) {
importCameras(List.of(new CameraConfig(n.getText(), u.getText())));
}
}
private void setupListeners() {
deviceTable.addMouseListener(new MouseAdapter() {
@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) {
SwingUtilities.invokeLater(() -> new SwingCCTVManager().open());
}
}