张世豪
2025-12-09 32524195d474b74e48916867b2a6c2f022a40d98
src/dikuai/Dikuaiguanli.java
@@ -6,6 +6,9 @@
import java.awt.datatransfer.*;
import java.awt.datatransfer.StringSelection;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import ui.UIConfig;
@@ -17,6 +20,8 @@
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Objects;
import java.util.Properties;
import lujing.Lunjingguihua;
import zhangaiwu.AddDikuai;
@@ -58,6 +63,8 @@
   private JButton addLandBtn;
   private static String currentWorkLandNumber;
   private static final String WORK_LAND_KEY = "currentWorkLandNumber";
   private static final String PROPERTIES_FILE = "set.properties";
   private static final Map<String, Boolean> boundaryPointVisibility = new HashMap<>();
   private ImageIcon workSelectedIcon;
   private ImageIcon workUnselectedIcon;
@@ -504,6 +511,7 @@
               boolean isCurrent = currentWorkLandNumber != null && currentWorkLandNumber.equals(landNumber);
               if (isCurrent) {
                  renderer.setBoundaryPointsVisible(desiredState);
                  renderer.setBoundaryPointSizeScale(desiredState ? 0.5d : 1.0d);
               }
            }
         }
@@ -583,17 +591,69 @@
      JScrollPane scrollPane = new JScrollPane(textArea);
      scrollPane.setPreferredSize(new Dimension(360, 240));
      int option = JOptionPane.showConfirmDialog(
         this,
         scrollPane,
         title,
         JOptionPane.OK_CANCEL_OPTION,
         JOptionPane.PLAIN_MESSAGE);
      if (option == JOptionPane.OK_OPTION) {
         return textArea.getText();
      Window owner = SwingUtilities.getWindowAncestor(this);
      JDialog dialog;
      if (owner instanceof Frame) {
         dialog = new JDialog((Frame) owner, title, true);
      } else if (owner instanceof Dialog) {
         dialog = new JDialog((Dialog) owner, title, true);
      } else {
         dialog = new JDialog((Frame) null, title, true);
      }
      return null;
      dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
      JPanel contentPanel = new JPanel(new BorderLayout());
      contentPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
      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("复制");
      final boolean[] confirmed = new boolean[] {false};
      final String[] resultHolder = new String[1];
      okButton.addActionListener(e -> {
         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);
      contentPanel.add(buttonPanel, BorderLayout.SOUTH);
      dialog.setContentPane(contentPanel);
      dialog.getRootPane().setDefaultButton(okButton);
      dialog.pack();
      dialog.setLocationRelativeTo(this);
      dialog.setVisible(true);
      return confirmed[0] ? resultHolder[0] : null;
   }
   private boolean saveFieldAndRefresh(Dikuai dikuai, String fieldName, String value) {
@@ -733,10 +793,26 @@
      switch (trimmed) {
         case "1":
         case "spiral":
         case "螺旋":
         case "螺旋模式":
            return "spiral";
         case "0":
         case "parallel":
         case "平行":
         case "平行模式":
         default:
            if (trimmed.contains("螺旋")) {
               return "spiral";
            }
            if (trimmed.contains("spiral")) {
               return "spiral";
            }
            if (trimmed.contains("parallel")) {
               return "parallel";
            }
            if (trimmed.contains("平行")) {
               return "parallel";
            }
            return "parallel";
      }
   }
@@ -1446,10 +1522,19 @@
   }
   public static void setCurrentWorkLand(String landNumber, String landName) {
      currentWorkLandNumber = landNumber;
      String sanitizedLandNumber = sanitizeLandNumber(landNumber);
      boolean changed = !Objects.equals(currentWorkLandNumber, sanitizedLandNumber);
      if (!changed) {
         String persisted = readPersistedWorkLandNumber();
         if (!Objects.equals(persisted, sanitizedLandNumber)) {
            changed = true;
         }
      }
      currentWorkLandNumber = sanitizedLandNumber;
      Dikuai dikuai = null;
      if (landNumber != null) {
         dikuai = Dikuai.getDikuai(landNumber);
      if (sanitizedLandNumber != null) {
         dikuai = Dikuai.getDikuai(sanitizedLandNumber);
         if (dikuai != null && (landName == null || "-1".equals(landName) || landName.trim().isEmpty())) {
            landName = dikuai.getLandName();
         }
@@ -1460,7 +1545,7 @@
      Shouye shouye = Shouye.getInstance();
      if (shouye != null) {
         if (landNumber == null) {
         if (sanitizedLandNumber == null) {
            shouye.updateCurrentAreaName(null);
         } else {
            shouye.updateCurrentAreaName(landName);
@@ -1470,24 +1555,85 @@
            renderer.applyLandMetadata(dikuai);
            String boundary = (dikuai != null) ? dikuai.getBoundaryCoordinates() : null;
            String plannedPath = (dikuai != null) ? dikuai.getPlannedPath() : null;
            List<Obstacledge.Obstacle> configuredObstacles = (landNumber != null) ? loadObstaclesFromConfig(landNumber) : Collections.emptyList();
            List<Obstacledge.Obstacle> configuredObstacles = (sanitizedLandNumber != null) ? loadObstaclesFromConfig(sanitizedLandNumber) : Collections.emptyList();
            if (configuredObstacles == null) {
               configuredObstacles = Collections.emptyList();
            }
            renderer.setCurrentBoundary(boundary, landNumber, landNumber == null ? null : landName);
            renderer.setCurrentBoundary(boundary, sanitizedLandNumber, sanitizedLandNumber == null ? null : landName);
            renderer.setCurrentPlannedPath(plannedPath);
            renderer.setCurrentObstacles(configuredObstacles, landNumber);
            boolean showBoundaryPoints = landNumber != null && boundaryPointVisibility.getOrDefault(landNumber, false);
            renderer.setCurrentObstacles(configuredObstacles, sanitizedLandNumber);
            boolean showBoundaryPoints = sanitizedLandNumber != null && boundaryPointVisibility.getOrDefault(sanitizedLandNumber, false);
            renderer.setBoundaryPointsVisible(showBoundaryPoints);
            renderer.setBoundaryPointSizeScale(showBoundaryPoints ? 0.5d : 1.0d);
         }
         shouye.refreshMowingIndicators();
      }
      if (changed) {
         persistCurrentWorkLand(sanitizedLandNumber);
      }
   }
   public static String getCurrentWorkLandNumber() {
      return currentWorkLandNumber;
   }
   public static String getPersistedWorkLandNumber() {
      return readPersistedWorkLandNumber();
   }
   private static String sanitizeLandNumber(String landNumber) {
      if (landNumber == null) {
         return null;
      }
      String trimmed = landNumber.trim();
      if (trimmed.isEmpty() || "-1".equals(trimmed)) {
         return null;
      }
      return trimmed;
   }
   private static void persistCurrentWorkLand(String landNumber) {
      synchronized (Dikuaiguanli.class) {
         Properties props = new Properties();
         try (FileInputStream in = new FileInputStream(PROPERTIES_FILE)) {
            props.load(in);
         } catch (IOException ignored) {
            // Use empty defaults when the configuration file is missing.
         }
         if (landNumber == null) {
            props.setProperty(WORK_LAND_KEY, "-1");
         } else {
            props.setProperty(WORK_LAND_KEY, landNumber);
         }
         try (FileOutputStream out = new FileOutputStream(PROPERTIES_FILE)) {
            props.store(out, "Current work land selection updated");
         } catch (IOException ex) {
            System.err.println("无法保存当前作业地块: " + ex.getMessage());
         }
      }
   }
   private static String readPersistedWorkLandNumber() {
      Properties props = new Properties();
      try (FileInputStream in = new FileInputStream(PROPERTIES_FILE)) {
         props.load(in);
         String value = props.getProperty(WORK_LAND_KEY);
         if (value == null) {
            return null;
         }
         String trimmed = value.trim();
         if (trimmed.isEmpty() || "-1".equals(trimmed)) {
            return null;
         }
         return trimmed;
      } catch (IOException ex) {
         return null;
      }
   }
   private ImageIcon loadIcon(String path, int width, int height) {
      try {
         ImageIcon rawIcon = new ImageIcon(path);