From 7135b9d2114a2eb5ba004bbb0c042de59eb9316a Mon Sep 17 00:00:00 2001 From: Pablinux Date: Wed, 19 Nov 2025 10:47:04 -0500 Subject: [PATCH] =?UTF-8?q?1=20feat:=20Implementaci=C3=B3n=20de=20logging?= =?UTF-8?q?=20y=20c=C3=B3digo=20de=20verificaci=C3=B3n=20din=C3=A1mico=20?= =?UTF-8?q?=20=20=202=20=20=20=203=20-=20Se=20a=C3=B1ade=20un=20sistema=20?= =?UTF-8?q?de=20logging=20que=20guarda=20todos=20los=20eventos=20y=20error?= =?UTF-8?q?es=20en=20el=20archivo=20'hikvision-player.log'.=20=20=20=204?= =?UTF-8?q?=20-=20Se=20implementa=20un=20visor=20de=20logs=20en=20la=20pes?= =?UTF-8?q?ta=C3=B1a=20'Configuraci=C3=B3n'=20que=20lee=20y=20muestra=20el?= =?UTF-8?q?=20contenido=20del=20archivo=20de=20=20=20=20=20=20log.=20=20?= =?UTF-8?q?=20=205=20-=20Se=20a=C3=B1ade=20un=20bot=C3=B3n=20'Limpiar=20Lo?= =?UTF-8?q?g'=20para=20borrar=20el=20archivo=20de=20log=20y=20refrescar=20?= =?UTF-8?q?el=20visor.=20=20=20=206=20-=20Se=20mejora=20el=20detalle=20de?= =?UTF-8?q?=20los=20mensajes=20de=20error=20en=20los=20logs=20para=20inclu?= =?UTF-8?q?ir=20IP,=20puerto=20y=20canal,=20haci=C3=A9ndolos=20m=C3=A1s=20?= =?UTF-8?q?=20=20=20=20=20informativos.=20=20=20=207=20-=20Se=20a=C3=B1ade?= =?UTF-8?q?=20un=20checkbox=20en=20la=20UI=20para=20habilitar=20o=20deshab?= =?UTF-8?q?ilitar=20el=20uso=20del=20c=C3=B3digo=20de=20verificaci=C3=B3n?= =?UTF-8?q?=20del=20stream.=20=20=20=208=20-=20La=20inicializaci=C3=B3n=20?= =?UTF-8?q?del=20SDK=20ahora=20utiliza=20condicionalmente=20el=20c=C3=B3di?= =?UTF-8?q?go=20de=20verificaci=C3=B3n=20basado=20en=20esta=20=20=20=20=20?= =?UTF-8?q?=20configuraci=C3=B3n.=20=20=20=209=20-=20Se=20actualiza=20la?= =?UTF-8?q?=20carga=20y=20guardado=20de=20la=20configuraci=C3=B3n=20para?= =?UTF-8?q?=20incluir=20el=20estado=20del=20nuevo=20checkbox.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../telcotronics/hikvision/player/panel.form | 446 +++++++++++ .../telcotronics/hikvision/player/panel.java | 741 ++++++++++++++++++ 2 files changed, 1187 insertions(+) create mode 100644 src/main/java/com/telcotronics/hikvision/player/panel.form create mode 100644 src/main/java/com/telcotronics/hikvision/player/panel.java diff --git a/src/main/java/com/telcotronics/hikvision/player/panel.form b/src/main/java/com/telcotronics/hikvision/player/panel.form new file mode 100644 index 0000000..1353b59 --- /dev/null +++ b/src/main/java/com/telcotronics/hikvision/player/panel.form @@ -0,0 +1,446 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/com/telcotronics/hikvision/player/panel.java b/src/main/java/com/telcotronics/hikvision/player/panel.java new file mode 100644 index 0000000..b6ac782 --- /dev/null +++ b/src/main/java/com/telcotronics/hikvision/player/panel.java @@ -0,0 +1,741 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/GUIForms/JFrame.java to edit this template + */ +package com.telcotronics.hikvision.player; + +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.NativeLong; +import com.sun.jna.Pointer; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; +import java.util.concurrent.ExecutionException; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +/** + * + * @author pablinux + */ +public class panel extends javax.swing.JFrame { + + // SDK de Hikvision + private HCNetSDK hcNetSDK; + private NativeLong userID; + private NativeLong realHandle; + private Canvas videoCanvas; + private ConfigManager config; + + private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(panel.class.getName()); + + public panel() { + + initComponents(); + setupLogging(); // Configure logging to file + config = new ConfigManager(); + loadConfigToUI(); + + // Add action listener for the checkbox + ck_habilitaVerificacionCode.addActionListener(e -> { + txt_videoCrypt.setEnabled(ck_habilitaVerificacionCode.isSelected()); + }); + // Set initial state of txt_videoCrypt based on checkbox + txt_videoCrypt.setEnabled(ck_habilitaVerificacionCode.isSelected()); + + initSDK(); + + addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + setupVideo(); + } + + @Override + public void windowClosing(WindowEvent e) { + cleanup(); + } + }); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jPopupMenu1 = new javax.swing.JPopupMenu(); + menu_copiar = new javax.swing.JMenuItem(); + jTabbedPane1 = new javax.swing.JTabbedPane(); + jPanel1 = new javax.swing.JPanel(); + panel_video = new javax.swing.JPanel(); + jPanel2 = new javax.swing.JPanel(); + bt_conectar = new javax.swing.JButton(); + bt_reproducir = new javax.swing.JButton(); + jPanel3 = new javax.swing.JPanel(); + jPanel4 = new javax.swing.JPanel(); + cb_channel = new javax.swing.JComboBox<>(); + txt_puerto = new javax.swing.JTextField(); + txt_ip = new javax.swing.JTextField(); + jLabel3 = new javax.swing.JLabel(); + jLabel4 = new javax.swing.JLabel(); + jLabel5 = new javax.swing.JLabel(); + bt_cargarConfig = new javax.swing.JButton(); + jPanel5 = new javax.swing.JPanel(); + txt_pasword = new javax.swing.JTextField(); + txt_usr = new javax.swing.JTextField(); + jLabel1 = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); + bt_guardarConfig = new javax.swing.JButton(); + jPanel6 = new javax.swing.JPanel(); + jLabel6 = new javax.swing.JLabel(); + txt_videoCrypt = new javax.swing.JTextField(); + ck_habilitaVerificacionCode = new javax.swing.JCheckBox(); + jScrollPane1 = new javax.swing.JScrollPane(); + txtPane_consola = new javax.swing.JTextPane(); + bt_limpiarLogs = new javax.swing.JButton(); + + menu_copiar.setText("Copiar"); + menu_copiar.addActionListener(this::menu_copiarActionPerformed); + jPopupMenu1.add(menu_copiar); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + jTabbedPane1.addChangeListener(this::jTabbedPane1StateChanged); + + panel_video.setBackground(new java.awt.Color(0, 0, 0)); + panel_video.setLayout(new java.awt.BorderLayout()); + + jPanel2.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + bt_conectar.setText("Conectar"); + bt_conectar.addActionListener(this::bt_conectarActionPerformed); + + bt_reproducir.setText("play"); + bt_reproducir.setEnabled(false); + bt_reproducir.addActionListener(this::bt_reproducirActionPerformed); + + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addComponent(bt_conectar) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(bt_reproducir) + .addContainerGap(544, Short.MAX_VALUE)) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bt_conectar) + .addComponent(bt_reproducir)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(panel_video, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(panel_video, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + + jTabbedPane1.addTab("Vision en directo", jPanel1); + + jPanel4.setBackground(new java.awt.Color(153, 153, 153)); + + cb_channel.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "1", "2", "3", "4" })); + + jLabel3.setText("IP"); + + jLabel4.setText("PUERTO"); + + jLabel5.setText("CANAL"); + + javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4); + jPanel4.setLayout(jPanel4Layout); + jPanel4Layout.setHorizontalGroup( + jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addGap(14, 14, 14) + .addComponent(jLabel3) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txt_ip, javax.swing.GroupLayout.PREFERRED_SIZE, 266, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel4) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(txt_puerto, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jLabel5) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cb_channel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel4Layout.setVerticalGroup( + jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txt_ip, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txt_puerto, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(cb_channel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel3) + .addComponent(jLabel4) + .addComponent(jLabel5)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + bt_cargarConfig.setText("Cargar Configuracion"); + bt_cargarConfig.addActionListener(this::bt_cargarConfigActionPerformed); + + jPanel5.setBackground(new java.awt.Color(204, 204, 204)); + + jLabel1.setText("Usuario"); + + jLabel2.setText("Contraseña"); + + javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5); + jPanel5.setLayout(jPanel5Layout); + jPanel5Layout.setHorizontalGroup( + jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel5Layout.createSequentialGroup() + .addGap(37, 37, 37) + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txt_usr, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txt_pasword, javax.swing.GroupLayout.PREFERRED_SIZE, 241, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(34, Short.MAX_VALUE)) + ); + jPanel5Layout.setVerticalGroup( + jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel5Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txt_pasword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txt_usr, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel1) + .addComponent(jLabel2)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + bt_guardarConfig.setText("Guardar Configuracion"); + bt_guardarConfig.addActionListener(this::bt_guardarConfigActionPerformed); + + jPanel6.setBackground(new java.awt.Color(204, 204, 204)); + + jLabel6.setText("Codigo de Verificacion"); + + ck_habilitaVerificacionCode.setText("Contraseña de Ecriptacion de flujo de video"); + + javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6); + jPanel6.setLayout(jPanel6Layout); + jPanel6Layout.setHorizontalGroup( + jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel6Layout.createSequentialGroup() + .addContainerGap() + .addComponent(ck_habilitaVerificacionCode) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel6) + .addGap(18, 18, 18) + .addComponent(txt_videoCrypt, javax.swing.GroupLayout.PREFERRED_SIZE, 177, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(43, 43, 43)) + ); + jPanel6Layout.setVerticalGroup( + jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel6Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel6) + .addComponent(txt_videoCrypt, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(ck_habilitaVerificacionCode)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + txtPane_consola.setComponentPopupMenu(jPopupMenu1); + jScrollPane1.setViewportView(txtPane_consola); + + bt_limpiarLogs.setText("Limpiar Log"); + bt_limpiarLogs.addActionListener(this::bt_limpiarLogsActionPerformed); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jScrollPane1) + .addComponent(jPanel4, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel5, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel6, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel3Layout.createSequentialGroup() + .addComponent(bt_cargarConfig, javax.swing.GroupLayout.PREFERRED_SIZE, 216, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(bt_guardarConfig, javax.swing.GroupLayout.PREFERRED_SIZE, 216, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bt_limpiarLogs, javax.swing.GroupLayout.PREFERRED_SIZE, 164, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel5, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 340, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bt_cargarConfig, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bt_guardarConfig, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bt_limpiarLogs, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + + jTabbedPane1.addTab("Configuracion", jPanel3); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 728, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jTabbedPane1) + ); + + pack(); + }// //GEN-END:initComponents + + private void bt_conectarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bt_conectarActionPerformed + if (bt_conectar.getText().equals("Conectar")) { + connectToDVRAsync(); + //bt_conectar.setText("Desconectar"); + //bt_reproducir.setEnabled(true); + } else { + bt_reproducir.setEnabled(false); + bt_conectar.setText("Conectar"); + stopPreview(); // ⚠️ AGREGA ESTO + disconnectFromDVR(); + } + + }//GEN-LAST:event_bt_conectarActionPerformed + + private void bt_reproducirActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bt_reproducirActionPerformed + if (bt_reproducir.getText().equals("play")) { + startPreviewAsync(); + bt_reproducir.setText("Stop"); + } else { + stopPreview(); + bt_reproducir.setText("play"); + } + }//GEN-LAST:event_bt_reproducirActionPerformed + + private void bt_guardarConfigActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bt_guardarConfigActionPerformed + saveConfigFromUI(); + }//GEN-LAST:event_bt_guardarConfigActionPerformed + + private void bt_cargarConfigActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bt_cargarConfigActionPerformed + config = new ConfigManager(); // Recarga desde el archivo + loadConfigToUI(); + JOptionPane.showMessageDialog(this, + "Configuración recargada desde config.properties", + "Éxito", JOptionPane.INFORMATION_MESSAGE); + }//GEN-LAST:event_bt_cargarConfigActionPerformed + + private void jTabbedPane1StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jTabbedPane1StateChanged + if(jTabbedPane1.getSelectedIndex()==1){ + cargar_logs(); + } + }//GEN-LAST:event_jTabbedPane1StateChanged + + private void bt_limpiarLogsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bt_limpiarLogsActionPerformed + try { + // Close all handlers on the root logger to release the file lock + for (java.util.logging.Handler handler : java.util.logging.Logger.getLogger("").getHandlers()) { + handler.close(); + } + // Delete the file + java.nio.file.Files.deleteIfExists(java.nio.file.Paths.get("hikvision-player.log")); + // Re-initialize logging to create a new file + setupLogging(); + // Refresh the text pane + cargar_logs(); + logger.info("Log file cleared."); + } catch (java.io.IOException e) { + logger.log(java.util.logging.Level.SEVERE, "Failed to clear log file", e); + JOptionPane.showMessageDialog(this, "Error al limpiar el log: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + } + }//GEN-LAST:event_bt_limpiarLogsActionPerformed + + private void menu_copiarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menu_copiarActionPerformed + String textoACopiar = txtPane_consola.getText(); + // 1. Obtener el portapapeles del sistema. + Clipboard portapapeles = Toolkit.getDefaultToolkit().getSystemClipboard(); + + // 2. Crear un objeto StringSelection con el texto. + StringSelection seleccion = new StringSelection(textoACopiar); + + // 3. Colocar el StringSelection en el portapapeles. + portapapeles.setContents(seleccion, null); + + System.out.println("El texto se ha copiado al portapapeles."); + }//GEN-LAST:event_menu_copiarActionPerformed + + private void initSDK() { + try { + System.setProperty("jna.library.path", "./lib"); + hcNetSDK = HCNetSDK.INSTANCE; + + // >>> INICIO: CONFIGURAR CLAVE DE ENCRIPTACIÓN ANTES DE INICIALIZAR + if (config.getEnableVerificationCode()) { + String verificationCode = config.getVerificationCode(); + if (verificationCode != null && !verificationCode.isEmpty()) { + logger.info("Intentando configurar código de verificación..."); + HCNetSDK.NET_DVR_LOCAL_PROTECT_KEY_CFG keyCfg = new HCNetSDK.NET_DVR_LOCAL_PROTECT_KEY_CFG(); + System.arraycopy(verificationCode.getBytes(), 0, keyCfg.byProtectKey, 0, verificationCode.length()); + + boolean success = hcNetSDK.NET_DVR_SetSDKLocalCfg(HCNetSDK.NET_SDK_LOCAL_CFG_TYPE_PROTECT_KEY, keyCfg.getPointer()); + if (success) { + logger.info("Código de verificación configurado exitosamente."); + } else { + logger.severe("FALLO al configurar código de verificación. Error SDK: " + hcNetSDK.NET_DVR_GetLastError()); + } + } + } + // <<< FIN: CONFIGURAR CLAVE DE ENCRIPTACIÓN + + boolean init = hcNetSDK.NET_DVR_Init(); + if (init) { + logger.info("SDK inicializado correctamente"); + } else { + logger.severe("Error al inicializar SDK. Error SDK: " + hcNetSDK.NET_DVR_GetLastError()); + } + } catch (Exception e) { + logger.log(java.util.logging.Level.SEVERE, "Error al cargar SDK", e); + JOptionPane.showMessageDialog(this, + "Error al cargar el SDK: " + e.getMessage(), + "Error", JOptionPane.ERROR_MESSAGE); + } + } + + private void setupVideo() { + // Asegurarse de que panel_video use BorderLayout para que el Canvas ocupe todo el panel + panel_video.setLayout(new BorderLayout()); + + videoCanvas = new Canvas(); + videoCanvas.setBackground(Color.BLACK); + + // AGREGAR LISTENER PARA HABILITAR EL BOTÓN CUANDO EL CANVAS ESTÉ LISTO + videoCanvas.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + // Una vez que el canvas tiene tamaño, habilitamos el botón de reproducir + // si ya estamos conectados. + if (userID != null && userID.longValue() > -1) { + bt_reproducir.setEnabled(true); + } + // Opcional: remover el listener para que no se ejecute más + videoCanvas.removeComponentListener(this); + } + }); + + // Hacer que el canvas sea visible y agregalo al panel + panel_video.removeAll(); + panel_video.add(videoCanvas, BorderLayout.CENTER); + videoCanvas.setVisible(true); + + panel_video.revalidate(); + panel_video.repaint(); + } + + private void connectToDVRAsync() { + // Deshabilitar botón mientras conecta + bt_conectar.setEnabled(false); + bt_conectar.setText("Conectando..."); + + DVRConnectionWorker worker = new DVRConnectionWorker( + hcNetSDK, + config.getDvrIP(), + config.getDvrPort(), + config.getUsername(), + config.getPassword() + ); + + worker.execute(); + + // Manejar el resultado cuando termine + new Thread(() -> { + try { + ConnectionResult result = worker.get(); + + SwingUtilities.invokeLater(() -> { + if (result.success) { + userID = result.userID; + logger.info("Conectado. Canales: " + result.deviceInfo.byChanNum); + + JOptionPane.showMessageDialog(this, + "Conectado exitosamente\n" + + "Canales analógicos: " + result.deviceInfo.byChanNum + "\n" + + "Canales IP: " + result.deviceInfo.byIPChanNum, + "Éxito", JOptionPane.INFORMATION_MESSAGE); + + bt_conectar.setText("Desconectar"); + // NO habilitar play aquí. El listener se encargará. + // Si el canvas ya tiene tamaño, el listener ya se disparó. + // Si no, se disparará pronto. + if (videoCanvas.getWidth() > 0 && videoCanvas.getHeight() > 0) { + bt_reproducir.setEnabled(true); + } + + } else { + String errorMessage = String.format("Error al conectar. Código: %d. IP: %s, Puerto: %d", + result.errorCode, config.getDvrIP(), config.getDvrPort()); + logger.severe(errorMessage); + JOptionPane.showMessageDialog(this, + errorMessage, + "Error", JOptionPane.ERROR_MESSAGE); + + bt_conectar.setText("Conectar"); + bt_reproducir.setEnabled(false); + } + bt_conectar.setEnabled(true); + }); + + } catch (InterruptedException | ExecutionException e) { + SwingUtilities.invokeLater(() -> { + logger.severe("Error en conexión: " + e.getMessage()); + bt_conectar.setText("Conectar"); + bt_conectar.setEnabled(true); + bt_reproducir.setEnabled(false); + }); + } + }).start(); + } + + private void startPreviewAsync() { + if (userID == null || userID.intValue() < 0) { + JOptionPane.showMessageDialog(this, + "Primero conecte al DVR", + "Advertencia", JOptionPane.WARNING_MESSAGE); + return; + } + + bt_reproducir.setEnabled(false); + bt_reproducir.setText("Iniciando..."); + + PreviewWorker worker = new PreviewWorker( + hcNetSDK, + userID, + config.getChannel(), + config.getStreamType(), + videoCanvas + ); + + worker.execute(); + + new Thread(() -> { + try { + PreviewResult result = worker.get(); + + SwingUtilities.invokeLater(() -> { + if (result.success) { + realHandle = result.realHandle; + logger.info("Preview iniciado en canal " + config.getChannel()); + bt_reproducir.setText("Parar"); + } else { + String errorMessage = String.format("Error al iniciar video. Código: %d. Canal: %d", + result.errorCode, config.getChannel()); + logger.severe(errorMessage); + JOptionPane.showMessageDialog(this, + errorMessage, + "Error", JOptionPane.ERROR_MESSAGE); + bt_reproducir.setText("play"); + } + bt_reproducir.setEnabled(true); + }); + + } catch (InterruptedException | ExecutionException e) { + SwingUtilities.invokeLater(() -> { + logger.severe("Error en preview: " + e.getMessage()); + bt_reproducir.setText("play"); + bt_reproducir.setEnabled(true); + }); + } + }).start(); + } + + private void stopPreview() { + if (realHandle != null && realHandle.intValue() >= 0) { + hcNetSDK.NET_DVR_StopRealPlay(realHandle); + logger.info("Preview detenido"); + realHandle = null; + } + } + + private void disconnectFromDVR() { + stopPreview(); + if (userID != null && userID.intValue() >= 0) { + hcNetSDK.NET_DVR_Logout(userID); + logger.info("Desconectado del DVR"); + userID = null; + } + } + + private void cleanup() { + disconnectFromDVR(); + if (hcNetSDK != null) { + hcNetSDK.NET_DVR_Cleanup(); + logger.info("SDK limpiado"); + } + } + + // Cargar configuración a los campos de la UI + private void loadConfigToUI() { + txt_ip.setText(config.getDvrIP()); + txt_puerto.setText(String.valueOf(config.getDvrPort())); + txt_usr.setText(config.getUsername()); + txt_pasword.setText(config.getPassword()); + cb_channel.setSelectedItem(String.valueOf(config.getChannel())); + txt_videoCrypt.setText(config.getVerificationCode()); + ck_habilitaVerificacionCode.setSelected(config.getEnableVerificationCode()); + txt_videoCrypt.setEnabled(ck_habilitaVerificacionCode.isSelected()); // Set initial state + } + +// Guardar configuración desde los campos de la UI + private void saveConfigFromUI() { + try { + config.setDvrIP(txt_ip.getText().trim()); + config.setDvrPort(Integer.parseInt(txt_puerto.getText().trim())); + config.setUsername(txt_usr.getText().trim()); + config.setPassword(txt_pasword.getText().trim()); + config.setChannel(Integer.parseInt((String) cb_channel.getSelectedItem())); + config.setVerificationCode(txt_videoCrypt.getText().trim()); + config.setEnableVerificationCode(ck_habilitaVerificacionCode.isSelected()); + config.saveConfig(); + + JOptionPane.showMessageDialog(this, + "Configuración guardada exitosamente", + "Éxito", JOptionPane.INFORMATION_MESSAGE); + + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, + "Error: Puerto y Canal deben ser números", + "Error", JOptionPane.ERROR_MESSAGE); + } + } + + private void setupLogging() { + try { + java.util.logging.FileHandler fileHandler = new java.util.logging.FileHandler("hikvision-player.log", true); // true for append + java.util.logging.SimpleFormatter formatter = new java.util.logging.SimpleFormatter(); + fileHandler.setFormatter(formatter); + java.util.logging.Logger.getLogger("").addHandler(fileHandler); + logger.info("Logging to file configured."); + } catch (java.io.IOException | SecurityException e) { + logger.log(java.util.logging.Level.SEVERE, "Failed to set up logging to file", e); + } + } + + private void cargar_logs(){ + try { + String content = new String(java.nio.file.Files.readAllBytes(java.nio.file.Paths.get("hikvision-player.log"))); + txtPane_consola.setText(content); + } catch (java.io.IOException e) { + txtPane_consola.setText("Error al cargar el archivo de log: " + e.getMessage()); + } + } + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + /* Set the Nimbus look and feel */ + // + /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. + * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html + */ + try { + for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { + if ("Nimbus".equals(info.getName())) { + javax.swing.UIManager.setLookAndFeel(info.getClassName()); + break; + } + } + } catch (ReflectiveOperationException | javax.swing.UnsupportedLookAndFeelException ex) { + logger.log(java.util.logging.Level.SEVERE, null, ex); + } + // + + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> new panel().setVisible(true)); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton bt_cargarConfig; + private javax.swing.JButton bt_conectar; + private javax.swing.JButton bt_guardarConfig; + private javax.swing.JButton bt_limpiarLogs; + private javax.swing.JButton bt_reproducir; + private javax.swing.JComboBox cb_channel; + private javax.swing.JCheckBox ck_habilitaVerificacionCode; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; + private javax.swing.JLabel jLabel5; + private javax.swing.JLabel jLabel6; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private javax.swing.JPanel jPanel4; + private javax.swing.JPanel jPanel5; + private javax.swing.JPanel jPanel6; + private javax.swing.JPopupMenu jPopupMenu1; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JTabbedPane jTabbedPane1; + private javax.swing.JMenuItem menu_copiar; + private javax.swing.JPanel panel_video; + private javax.swing.JTextPane txtPane_consola; + private javax.swing.JTextField txt_ip; + private javax.swing.JTextField txt_pasword; + private javax.swing.JTextField txt_puerto; + private javax.swing.JTextField txt_usr; + private javax.swing.JTextField txt_videoCrypt; + // End of variables declaration//GEN-END:variables +}