| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | boolean isCurrent = currentWorkLandNumber != null && currentWorkLandNumber.equals(landNumber); |
| | | if (isCurrent) { |
| | | renderer.setBoundaryPointsVisible(desiredState); |
| | | renderer.setBoundaryPointSizeScale(desiredState ? 0.5d : 1.0d); |
| | | } |
| | | } |
| | | } |
| | |
| | | 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) { |
| | |
| | | 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"; |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | 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(); |
| | | } |
| | |
| | | |
| | | Shouye shouye = Shouye.getInstance(); |
| | | if (shouye != null) { |
| | | if (landNumber == null) { |
| | | if (sanitizedLandNumber == null) { |
| | | shouye.updateCurrentAreaName(null); |
| | | } else { |
| | | shouye.updateCurrentAreaName(landName); |
| | |
| | | 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); |