张世豪
12 小时以前 13d032241e1a2938a8be4f64c9171e1240e9ea1e
src/dikuai/Dikuaiguanli.java
@@ -11,8 +11,6 @@
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import ui.UIConfig;
import ui.UIUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
@@ -25,6 +23,9 @@
import lujing.Lunjingguihua;
import lujing.MowingPathGenerationPage;
import publicway.Fuzhibutton;
import publicway.Lookbutton;
import publicway.buttonset;
import zhangaiwu.AddDikuai;
import zhangaiwu.Obstacledge;
import zhuye.MapRenderer;
@@ -314,10 +315,13 @@
      contentPanel.add(mowingSafetyDistancePanel);
      contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
      // 返回点坐标(带修改按钮)
      contentPanel.add(createCardInfoItemWithButton("返回点坐标:",
         getDisplayValue(dikuai.getReturnPointCoordinates(), "未设置"),
         "修改", e -> editReturnPoint(dikuai)));
      // 往返点路径(带查看图标按钮)
      JPanel returnPathPanel = createCardInfoItemWithIconButton("往返点路径:",
         createViewButton(e -> editReturnPath(dikuai)));
      configureInteractiveLabel(getInfoItemTitleLabel(returnPathPanel),
         () -> editReturnPath(dikuai),
         "点击查看/编辑往返点路径");
      contentPanel.add(returnPathPanel);
   contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
      ObstacleSummary obstacleSummary = getObstacleSummaryFromCache(dikuai.getLandNumber());
@@ -333,8 +337,9 @@
      contentPanel.add(obstaclePanel);
   contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
      // 地块边界坐标(带显示顶点按钮)
      JPanel boundaryPanel = createBoundaryInfoItem(dikuai);
      // 地块边界坐标(带查看按钮)
      JPanel boundaryPanel = createCardInfoItemWithIconButton("地块边界:",
         createViewButton(e -> editBoundaryCoordinates(dikuai)));
      configureInteractiveLabel(getInfoItemTitleLabel(boundaryPanel),
         () -> editBoundaryCoordinates(dikuai),
         "点击查看/编辑地块边界坐标");
@@ -358,14 +363,6 @@
   contentPanel.add(baseStationPanel);
   contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
   JPanel boundaryOriginalPanel = createCardInfoItemWithIconButton("边界原始坐标:",
      createViewButton(e -> editBoundaryOriginalCoordinates(dikuai)));
   configureInteractiveLabel(getInfoItemTitleLabel(boundaryOriginalPanel),
      () -> editBoundaryOriginalCoordinates(dikuai),
      "点击查看/编辑边界原始坐标");
   contentPanel.add(boundaryOriginalPanel);
      contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
      JPanel completedTrackPanel = createCardInfoItemWithButton("已完成割草路径:",
         getTruncatedValue(dikuai.getMowingTrack(), 12, "未记录"),
         createViewButton(e -> showCompletedMowingTrackDialog(dikuai)));
@@ -750,6 +747,20 @@
   }
   private String promptCoordinateEditing(String title, String initialValue) {
      return promptCoordinateEditing(title, initialValue, null);
   }
   private String promptCoordinateEditing(String title, String initialValue, Dikuai dikuai) {
      // 判断是否是往返点路径对话框
      boolean isReturnPathDialog = title != null && title.contains("往返点路径");
      if (isReturnPathDialog) {
         Window owner = SwingUtilities.getWindowAncestor(this);
         Wangfanpathpage page = new Wangfanpathpage(owner, title, initialValue, dikuai);
         page.setVisible(true);
         return page.getResult();
      }
      JTextArea textArea = new JTextArea(prepareCoordinateForEditor(initialValue));
      textArea.setLineWrap(true);
      textArea.setWrapStyleWord(true);
@@ -758,7 +769,8 @@
      textArea.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
      JScrollPane scrollPane = new JScrollPane(textArea);
      scrollPane.setPreferredSize(new Dimension(360, 240));
      // 如果是往返点路径对话框,高度调整为适应两个文本域
      scrollPane.setPreferredSize(new Dimension(360, isReturnPathDialog ? 100 : 240));
      Window owner = SwingUtilities.getWindowAncestor(this);
      JDialog dialog;
@@ -771,54 +783,224 @@
      }
      dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
      JPanel contentPanel = new JPanel(new BorderLayout());
      JPanel contentPanel = new JPanel();
      contentPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
      contentPanel.add(scrollPane, BorderLayout.CENTER);
      if (isReturnPathDialog) {
         contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
         // 减小边距以增加文本域宽度 (98%左右)
         contentPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
         // 1. 原始往返路径坐标区域
         String rawCoords = dikuai != null ? prepareCoordinateForEditor(dikuai.getReturnPathRawCoordinates()) : "";
         int rawCount = 0;
         if (rawCoords != null && !rawCoords.isEmpty() && !"-1".equals(rawCoords)) {
            rawCount = rawCoords.split(";").length;
         }
         JPanel rawHeaderPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
         rawHeaderPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
         rawHeaderPanel.setBackground(BACKGROUND_COLOR);
         rawHeaderPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 30));
         JLabel rawTitleLabel = new JLabel("原始往返路径坐标 (" + rawCount + "点)  ");
         rawTitleLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
         rawHeaderPanel.add(rawTitleLabel);
         // 原始坐标复制按钮
         final String finalRawCoords = rawCoords;
         JButton rawCopyBtn = Fuzhibutton.createCopyButton(
            () -> {
               if (finalRawCoords == null || finalRawCoords.isEmpty() || "-1".equals(finalRawCoords)) return null;
               return finalRawCoords;
            },
            "复制",
            new Color(230, 250, 240)
         );
         rawCopyBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12));
         rawCopyBtn.setPreferredSize(new Dimension(50, 24));
         rawCopyBtn.setMargin(new Insets(0,0,0,0));
         rawHeaderPanel.add(rawCopyBtn);
         contentPanel.add(rawHeaderPanel);
         contentPanel.add(Box.createVerticalStrut(5));
         JTextArea rawTextArea = new JTextArea(rawCoords);
         rawTextArea.setLineWrap(true);
         rawTextArea.setWrapStyleWord(true);
         rawTextArea.setFont(new Font("微软雅黑", Font.PLAIN, 13));
         rawTextArea.setEditable(false); // 原始坐标通常不可编辑
         rawTextArea.setRows(4);
         rawTextArea.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
         JScrollPane rawScroll = new JScrollPane(rawTextArea);
         rawScroll.setAlignmentX(Component.LEFT_ALIGNMENT);
         // 设置最大宽度允许扩展,首选宽度适中
         rawScroll.setPreferredSize(new Dimension(300, 100));
         rawScroll.setMaximumSize(new Dimension(Integer.MAX_VALUE, 100));
         contentPanel.add(rawScroll);
         contentPanel.add(Box.createVerticalStrut(15));
         // 2. 优化后往返路径坐标区域
         String optCoords = prepareCoordinateForEditor(initialValue);
         int optCount = 0;
         if (optCoords != null && !optCoords.isEmpty() && !"-1".equals(optCoords)) {
            optCount = optCoords.split(";").length;
         }
         JPanel optHeaderPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
         optHeaderPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
         optHeaderPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 30));
         JLabel optTitleLabel = new JLabel("优化后往返路径坐标 (" + optCount + "点)  ");
         optTitleLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
         optHeaderPanel.add(optTitleLabel);
         // 优化坐标复制按钮 - 动态获取文本域内容
         JButton optCopyBtn = Fuzhibutton.createCopyButton(
            () -> {
               String text = textArea.getText();
               if (text == null || text.trim().isEmpty() || "-1".equals(text.trim())) return null;
               return text;
            },
            "复制",
            new Color(230, 250, 240)
         );
         optCopyBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12));
         optCopyBtn.setPreferredSize(new Dimension(50, 24));
         optCopyBtn.setMargin(new Insets(0,0,0,0));
         optHeaderPanel.add(optCopyBtn);
         contentPanel.add(optHeaderPanel);
         contentPanel.add(Box.createVerticalStrut(5));
         // 使用传入的 textArea (已初始化为 initialValue)
         textArea.setRows(4);
         scrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
         scrollPane.setPreferredSize(new Dimension(300, 100));
         scrollPane.setMaximumSize(new Dimension(Integer.MAX_VALUE, 100));
         contentPanel.add(scrollPane);
      } else {
         contentPanel.setLayout(new BorderLayout());
         contentPanel.add(scrollPane, BorderLayout.CENTER);
      }
      JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
      JButton okButton = new JButton("确定");
      JButton cancelButton = new JButton("取消");
      JButton copyButton = new JButton("复制");
      JButton okButton;
      JButton cancelButton;
      JButton copyButton = null; // 初始化为null
      if (isReturnPathDialog) {
         // 往返点路径对话框:使用 buttonset 风格的确定按钮,图标按钮
         okButton = buttonset.createStyledButton("去绘制", new Color(70, 130, 220));
         // 取消按钮使用 closepage.png 图标
         cancelButton = new JButton();
         ImageIcon closeIcon = loadIcon("image/closepage.png", 25, 25);
         if (closeIcon != null) {
            cancelButton.setIcon(closeIcon);
         } else {
            cancelButton.setText("关闭");
         }
         cancelButton.setFont(new Font("微软雅黑", Font.PLAIN, 11));
         cancelButton.setForeground(PRIMARY_COLOR);
         cancelButton.setBorder(BorderFactory.createEmptyBorder());
         cancelButton.setContentAreaFilled(false);
         cancelButton.setFocusPainted(false);
         cancelButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
         cancelButton.addMouseListener(new MouseAdapter() {
            public void mouseEntered(MouseEvent e) { cancelButton.setOpaque(true); cancelButton.setBackground(new Color(255, 240, 240)); }
            public void mouseExited(MouseEvent e) { cancelButton.setOpaque(false); }
         });
         // 使用 Fuzhibutton 创建复制按钮 (这里不再需要底部的复制按钮,因为上面已经有了)
         // copyButton = ...
      } else {
         // 其他对话框保持原有样式
         okButton = new JButton("确定");
         cancelButton = new JButton("取消");
         copyButton = new JButton("复制");
         // 其他对话框的复制按钮逻辑
         copyButton.addActionListener(e -> {
            String text = textArea.getText();
            if (text == null) {
               text = "";
            }
            String trimmed = text.trim();
            if (trimmed.isEmpty() || "-1".equals(trimmed)) {
               JOptionPane.showMessageDialog(dialog, title + " 未设置", "提示", JOptionPane.INFORMATION_MESSAGE);
               return;
            }
            try {
               StringSelection selection = new StringSelection(text);
               Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
               clipboard.setContents(selection, selection);
               JOptionPane.showMessageDialog(dialog, title + " 已复制到剪贴板", "提示", JOptionPane.INFORMATION_MESSAGE);
            } catch (Exception ex) {
               JOptionPane.showMessageDialog(dialog, "复制失败: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
            }
         });
      }
      final boolean[] confirmed = new boolean[] {false};
      final String[] resultHolder = new String[1];
      okButton.addActionListener(e -> {
         resultHolder[0] = textArea.getText();
         confirmed[0] = true;
         dialog.dispose();
         if (isReturnPathDialog) {
            // 往返点路径对话框:标记为打开绘制页面
            // 如果文本域中已经有坐标,表示要重新绘制
            String currentText = textArea.getText();
            if (currentText != null && !currentText.trim().isEmpty() && !"-1".equals(currentText.trim())) {
               // 有坐标,表示重新绘制
               resultHolder[0] = "__OPEN_DRAW_PAGE_REFRESH__";
            } else {
               // 没有坐标,正常绘制
               resultHolder[0] = "__OPEN_DRAW_PAGE__";
            }
            confirmed[0] = true;
            dialog.dispose();
         } else {
            resultHolder[0] = textArea.getText();
            confirmed[0] = true;
            dialog.dispose();
         }
      });
      cancelButton.addActionListener(e -> dialog.dispose());
      copyButton.addActionListener(e -> {
         String text = textArea.getText();
         if (text == null) {
            text = "";
         }
         String trimmed = text.trim();
         if (trimmed.isEmpty() || "-1".equals(trimmed)) {
            JOptionPane.showMessageDialog(dialog, title + " 未设置", "提示", JOptionPane.INFORMATION_MESSAGE);
            return;
         }
         try {
            StringSelection selection = new StringSelection(text);
            Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
            clipboard.setContents(selection, selection);
            JOptionPane.showMessageDialog(dialog, title + " 已复制到剪贴板", "提示", JOptionPane.INFORMATION_MESSAGE);
         } catch (Exception ex) {
            JOptionPane.showMessageDialog(dialog, "复制失败: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
         }
      });
      buttonPanel.add(okButton);
      buttonPanel.add(cancelButton);
      buttonPanel.add(copyButton);
      if (copyButton != null) {
         buttonPanel.add(copyButton);
      }
      contentPanel.add(buttonPanel, BorderLayout.SOUTH);
      contentPanel.add(buttonPanel, isReturnPathDialog ? null : BorderLayout.SOUTH);
      if (isReturnPathDialog) {
         // 对于 BoxLayout,直接添加到底部
         JPanel bottomWrapper = new JPanel(new BorderLayout());
         bottomWrapper.add(buttonPanel, BorderLayout.EAST);
         contentPanel.add(bottomWrapper);
      }
      dialog.setContentPane(contentPanel);
      dialog.getRootPane().setDefaultButton(okButton);
      dialog.pack();
      // 如果是往返点路径对话框,设置宽度为首页的90%,高度保持不变
      if (isReturnPathDialog) {
         Shouye shouye = Shouye.getInstance();
         if (shouye != null && shouye.getWidth() > 0) {
            int homeWidth = shouye.getWidth();
            int dialogWidth = (int)(homeWidth * 0.9);
            Dimension currentSize = dialog.getSize();
            dialog.setSize(dialogWidth, currentSize.height);
         }
      }
      dialog.setLocationRelativeTo(this);
      dialog.setVisible(true);
@@ -846,17 +1028,35 @@
      if (dikuai == null) {
         return;
      }
      String edited = promptCoordinateEditing("查看 / 编辑地块边界坐标", dikuai.getBoundaryCoordinates());
      Window owner = SwingUtilities.getWindowAncestor(this);
      // 获取地块管理对话框,准备在打开边界编辑页面时关闭
      Window managementWindow = null;
      if (owner instanceof JDialog) {
         managementWindow = owner;
      }
      // 打开边界编辑页面
      Dikuanbianjipage page = new Dikuanbianjipage(owner, "地块边界管理页面", dikuai.getBoundaryCoordinates(), dikuai);
      page.setVisible(true);
      // 关闭地块管理页面
      if (managementWindow != null) {
         managementWindow.dispose();
      }
      // 获取编辑结果并保存
      String edited = page.getResult();
      if (edited == null) {
         return;
      }
      String normalized = normalizeCoordinateInput(edited);
      if (!saveFieldAndRefresh(dikuai, "boundaryCoordinates", normalized)) {
         JOptionPane.showMessageDialog(this, "无法更新地块边界坐标", "错误", JOptionPane.ERROR_MESSAGE);
         JOptionPane.showMessageDialog(null, "无法更新地块边界坐标", "错误", JOptionPane.ERROR_MESSAGE);
         return;
      }
      String message = "-1".equals(normalized) ? "地块边界坐标已清空" : "地块边界坐标已更新";
      JOptionPane.showMessageDialog(this, message, "成功", JOptionPane.INFORMATION_MESSAGE);
      JOptionPane.showMessageDialog(null, message, "成功", JOptionPane.INFORMATION_MESSAGE);
   }
   private void editPlannedPath(Dikuai dikuai) {
@@ -893,22 +1093,6 @@
      JOptionPane.showMessageDialog(this, message, "成功", JOptionPane.INFORMATION_MESSAGE);
   }
   private void editBoundaryOriginalCoordinates(Dikuai dikuai) {
      if (dikuai == null) {
         return;
      }
      String edited = promptCoordinateEditing("查看 / 编辑边界原始坐标", dikuai.getBoundaryOriginalCoordinates());
      if (edited == null) {
         return;
      }
      String normalized = normalizeCoordinateInput(edited);
      if (!saveFieldAndRefresh(dikuai, "boundaryOriginalCoordinates", normalized)) {
         JOptionPane.showMessageDialog(this, "无法更新边界原始坐标", "错误", JOptionPane.ERROR_MESSAGE);
         return;
      }
      String message = "-1".equals(normalized) ? "边界原始坐标已清空" : "边界原始坐标已更新";
      JOptionPane.showMessageDialog(this, message, "成功", JOptionPane.INFORMATION_MESSAGE);
   }
   private void editMowingPattern(Dikuai dikuai) {
      if (dikuai == null) {
@@ -1620,27 +1804,8 @@
   }
   private JButton createViewButton(ActionListener listener) {
      JButton btn = new JButton();
      ImageIcon lookIcon = loadIcon("image/look.png", 25, 25);
      if (lookIcon != null) {
         btn.setIcon(lookIcon);
      } else {
         btn.setText("查看");
      }
      btn.setFont(new Font("微软雅黑", Font.PLAIN, 11));
      btn.setForeground(PRIMARY_COLOR);
      btn.setBorder(BorderFactory.createEmptyBorder());
      btn.setContentAreaFilled(false);
      btn.setFocusPainted(false);
      btn.setCursor(new Cursor(Cursor.HAND_CURSOR));
      btn.addMouseListener(new MouseAdapter() {
         public void mouseEntered(MouseEvent e) { btn.setOpaque(true); btn.setBackground(new Color(230, 250, 240)); }
         public void mouseExited(MouseEvent e) { btn.setOpaque(false); }
      });
      if (listener != null) {
         btn.addActionListener(listener);
      }
      return btn;
      // 使用 Lookbutton 类创建查看按钮
      return Lookbutton.createViewButton(listener, new Color(230, 250, 240));
   }
   private JButton createPrimaryFooterButton(String text) {
@@ -1861,13 +2026,52 @@
      });
   }
   private void editReturnPoint(Dikuai dikuai) {
      FanhuiDialog fd = new FanhuiDialog(SwingUtilities.getWindowAncestor(this), dikuai);
      fd.setVisible(true);
      // 如果对话框已更新数据,刷新显示
      if (fd.isUpdated()) {
         loadDikuaiData();
   private void editReturnPath(Dikuai dikuai) {
      if (dikuai == null) {
         return;
      }
      String edited = promptCoordinateEditing("查看 / 编辑往返点路径", dikuai.getReturnPathCoordinates(), dikuai);
      if (edited == null) {
         return;
      }
      // 检查是否是特殊标记,表示点击了"去绘制"按钮
      if ("__OPEN_DRAW_PAGE__".equals(edited) || "__OPEN_DRAW_PAGE_REFRESH__".equals(edited)) {
         // 获取地块管理对话框
         Window owner = SwingUtilities.getWindowAncestor(this);
         Window managementWindow = null;
         if (owner instanceof JDialog) {
            managementWindow = owner;
         }
         // 获取地块管理对话框的父窗口(主窗口),作为绘制页面的父窗口
         Window drawPageOwner = null;
         if (managementWindow != null) {
            drawPageOwner = managementWindow.getOwner();
         }
         if (drawPageOwner == null && owner != null) {
            drawPageOwner = owner.getOwner();
         }
         if (drawPageOwner == null) {
            drawPageOwner = owner;
         }
         // 先关闭地块管理页面
         if (managementWindow != null) {
            managementWindow.dispose();
         }
         // 然后打开绘制页面,如果是重新绘制,传递标记
         boolean isRefresh = "__OPEN_DRAW_PAGE_REFRESH__".equals(edited);
         Huizhiwanfanpath.showDrawReturnPathDialog(drawPageOwner, dikuai, isRefresh);
         return;
      }
      String normalized = normalizeCoordinateInput(edited);
      if (!saveFieldAndRefresh(dikuai, "returnPathCoordinates", normalized)) {
         JOptionPane.showMessageDialog(this, "无法更新往返点路径", "错误", JOptionPane.ERROR_MESSAGE);
         return;
      }
      String message = "-1".equals(normalized) ? "往返点路径已清空" : "往返点路径已更新";
      JOptionPane.showMessageDialog(this, message, "成功", JOptionPane.INFORMATION_MESSAGE);
   }
   /**
@@ -2265,4 +2469,6 @@
         return new ArrayList<>(names);
      }
   }
}