package zhuye; import javax.swing.*; import java.awt.*; import java.awt.IllegalComponentStateException; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import gecaoji.Device; /** * 手持绘制边界的逐点采集对话框。 */ class HandheldBoundaryCaptureDialog extends JDialog { private final Shouye owner; private final JLabel instructionLabel; private final JButton confirmButton; private final JButton finishButton; private final JPanel mapPanel; private final Timer statusMonitor; private final Color enabledColor; private int nextPointIndex = 1; HandheldBoundaryCaptureDialog(Window parent, Shouye owner, JPanel mapPanel, Color enabledColor) { super(parent, "手持采集边界", ModalityType.APPLICATION_MODAL); this.owner = owner; this.mapPanel = mapPanel; this.enabledColor = enabledColor != null ? enabledColor : new Color(46, 139, 87); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); setResizable(false); setAlwaysOnTop(true); instructionLabel = new JLabel("", SwingConstants.CENTER); instructionLabel.setFont(new Font("微软雅黑", Font.BOLD, Math.max(11, (int) Math.round(16 * 0.7)))); instructionLabel.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); updateInstructionText(); confirmButton = new JButton("确定"); confirmButton.setFont(new Font("微软雅黑", Font.BOLD, 14)); confirmButton.setFocusPainted(false); confirmButton.setOpaque(true); confirmButton.setBorder(BorderFactory.createEmptyBorder(8, 18, 8, 18)); confirmButton.addActionListener(e -> handleConfirm()); finishButton = new JButton("结束"); finishButton.setFont(new Font("微软雅黑", Font.BOLD, 14)); finishButton.setFocusPainted(false); finishButton.setOpaque(true); finishButton.setBackground(new Color(255, 153, 0)); finishButton.setForeground(Color.WHITE); finishButton.setEnabled(false); finishButton.setVisible(false); finishButton.setBorder(BorderFactory.createEmptyBorder(8, 18, 8, 18)); finishButton.addActionListener(e -> handleFinish()); buildLayout(); alignButtonSizes(); getRootPane().setDefaultButton(confirmButton); pack(); Dimension initialSize = getSize(); if (initialSize != null && initialSize.width > 0) { setSize(new Dimension(initialSize.width * 2, initialSize.height)); } adjustPreferredSize(); positionNearMap(); updateActionButtons(); SwingUtilities.invokeLater(confirmButton::requestFocusInWindow); statusMonitor = new Timer(400, e -> refreshStatus()); statusMonitor.setRepeats(true); statusMonitor.start(); refreshStatus(); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { dispose(); } }); } private void buildLayout() { JPanel content = new JPanel(new BorderLayout()); content.setBorder(BorderFactory.createEmptyBorder(20, 24, 20, 24)); content.add(instructionLabel, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 16, 0)); buttonPanel.add(confirmButton); buttonPanel.add(finishButton); content.add(buttonPanel, BorderLayout.SOUTH); setContentPane(content); } private void adjustPreferredSize() { Dimension size = getSize(); if (size.height > 0) { int adjustedHeight = Math.max((int) (size.height * 0.7), 160); setSize(new Dimension(size.width, adjustedHeight)); } } private void positionNearMap() { final int margin = 16; if (owner != null && owner.isShowing()) { try { Point ownerLocation = owner.getLocationOnScreen(); Dimension ownerSize = owner.getSize(); Dimension dialogSize = getSize(); int x = ownerLocation.x + (ownerSize.width - dialogSize.width) / 2; int y = ownerLocation.y + ownerSize.height - dialogSize.height - margin; if (x < ownerLocation.x + margin) { x = ownerLocation.x + margin; } if (y < ownerLocation.y + margin) { y = ownerLocation.y + margin; } setLocation(x, y); return; } catch (IllegalComponentStateException ignored) { // fallback handled below } } else if (mapPanel != null && mapPanel.isShowing()) { try { Point mapLocation = mapPanel.getLocationOnScreen(); Dimension mapSize = mapPanel.getSize(); Dimension dialogSize = getSize(); int x = mapLocation.x + (mapSize.width - dialogSize.width) / 2; int y = mapLocation.y + mapSize.height - dialogSize.height - margin; setLocation(x, y); return; } catch (IllegalComponentStateException ignored) { // fallback handled below } } setLocationRelativeTo(owner); } private void handleConfirm() { if (!confirmButton.isEnabled()) { return; } int count = owner.captureHandheldBoundaryPoint(); if (count <= 0) { return; } nextPointIndex = count + 1; updateInstructionText(); updateActionButtons(); } private void handleFinish() { if (owner.finishHandheldBoundaryCapture()) { dispose(); } } @Override public void dispose() { if (statusMonitor != null) { statusMonitor.stop(); } super.dispose(); owner.handheldBoundaryCaptureDialogClosed(this); } private void refreshStatus() { boolean hasFix = isFixQualityAvailable(); boolean hasValidPosition = hasFix && hasValidCurrentPosition(); boolean duplicate = hasValidPosition && isDuplicateCurrentPosition(); boolean enabled = hasValidPosition && !duplicate; confirmButton.setEnabled(enabled); if (enabled) { confirmButton.setBackground(enabledColor); confirmButton.setForeground(Color.WHITE); } else { confirmButton.setBackground(new Color(200, 200, 200)); confirmButton.setForeground(new Color(130, 130, 130)); } if (!hasFix) { confirmButton.setToolTipText("当前定位质量不足,无法采集"); } else if (!hasValidPosition) { confirmButton.setToolTipText("当前定位数据无效,请稍后再试"); } else if (duplicate) { confirmButton.setToolTipText("当前坐标已采集,请移动到新的位置"); } else { confirmButton.setToolTipText(null); } } private boolean isDuplicateCurrentPosition() { return owner != null && owner.isCurrentHandheldPointDuplicate(); } private boolean hasValidCurrentPosition() { return owner != null && owner.hasValidRealtimeHandheldPosition(); } private void updateInstructionText() { instructionLabel.setText("是否采集当前点" + nextPointIndex); } private void alignButtonSizes() { Dimension confirmSize = confirmButton.getPreferredSize(); finishButton.setPreferredSize(confirmSize); finishButton.setMinimumSize(confirmSize); finishButton.setMaximumSize(confirmSize); } private void updateActionButtons() { int totalPoints = owner != null ? owner.getHandheldCapturedPointCount() : 0; boolean hasMinimumPoints = totalPoints >= 3; finishButton.setVisible(hasMinimumPoints); finishButton.setEnabled(hasMinimumPoints); confirmButton.setVisible(true); } private boolean isFixQualityAvailable() { Device device = Device.getGecaoji(); if (device == null) { return false; } String status = device.getPositioningStatus(); if (status == null) { return false; } return "4".equals(status.trim()); } }