// src/com/minecraftlauncher/ui/InstalledVersionsDialog.java package com.minecraftlauncher.ui; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; public class InstalledVersionsDialog extends JDialog { private static final String MINECRAFT_DIR = System.getProperty("user.home") + "/.minecraft"; private JList versionsList; private DefaultListModel listModel; private JButton deleteButton; private JButton refreshButton; private JLabel sizeLabel; public InstalledVersionsDialog(JFrame parent) { super(parent, "Versions Installées", true); initializeComponents(); setupLayout(); setupEventListeners(); loadInstalledVersions(); setSize(500, 400); setLocationRelativeTo(parent); setResizable(true); } private void initializeComponents() { // Liste des versions listModel = new DefaultListModel<>(); versionsList = new JList<>(listModel); versionsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); versionsList.setFont(new Font("SansSerif", Font.PLAIN, 12)); versionsList.setBackground(Color.WHITE); versionsList.setForeground(Color.BLACK); versionsList.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); // Boutons deleteButton = new JButton("Supprimer"); deleteButton.setEnabled(false); styleButton(deleteButton, new Color(220, 38, 38), new Color(185, 28, 28)); // Rouge refreshButton = new JButton("Actualiser"); styleButton(refreshButton, new Color(37, 99, 235), new Color(29, 78, 216)); // Bleu JButton closeButton = new JButton("Fermer"); styleButton(closeButton, new Color(107, 114, 128), new Color(75, 85, 99)); // Gris // Label d'information sizeLabel = new JLabel("Aucune version installée"); sizeLabel.setFont(new Font("SansSerif", Font.PLAIN, 11)); sizeLabel.setForeground(new Color(107, 114, 128)); // Événements des boutons closeButton.addActionListener(e -> dispose()); } private void styleButton(JButton button, Color bgColor, Color hoverColor) { button.setBackground(bgColor); button.setForeground(Color.WHITE); button.setFocusPainted(false); button.setBorderPainted(false); button.setFont(new Font("SansSerif", Font.BOLD, 11)); button.setCursor(new Cursor(Cursor.HAND_CURSOR)); button.setBorder(BorderFactory.createEmptyBorder(8, 16, 8, 16)); // Effet hover button.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseEntered(java.awt.event.MouseEvent evt) { button.setBackground(hoverColor); } public void mouseExited(java.awt.event.MouseEvent evt) { button.setBackground(bgColor); } }); } private void setupLayout() { setLayout(new BorderLayout(10, 10)); // Panel principal JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); // Titre JLabel titleLabel = new JLabel("Versions de Minecraft Installées"); titleLabel.setFont(new Font("SansSerif", Font.BOLD, 16)); titleLabel.setHorizontalAlignment(SwingConstants.CENTER); titleLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 15, 0)); // Liste avec scroll JScrollPane scrollPane = new JScrollPane(versionsList); scrollPane.setBorder(BorderFactory.createLineBorder(new Color(75, 85, 99), 1)); scrollPane.setPreferredSize(new Dimension(400, 250)); // Panel des boutons JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0)); buttonPanel.add(deleteButton); buttonPanel.add(refreshButton); buttonPanel.add(new JButton("Fermer") {{ styleButton(this, new Color(107, 114, 128), new Color(75, 85, 99)); addActionListener(e -> dispose()); }}); // Panel du bas avec info et boutons JPanel bottomPanel = new JPanel(new BorderLayout()); bottomPanel.add(sizeLabel, BorderLayout.WEST); bottomPanel.add(buttonPanel, BorderLayout.EAST); mainPanel.add(titleLabel, BorderLayout.NORTH); mainPanel.add(scrollPane, BorderLayout.CENTER); mainPanel.add(bottomPanel, BorderLayout.SOUTH); add(mainPanel); } private void setupEventListeners() { // Sélection dans la liste versionsList.addListSelectionListener(e -> { if (!e.getValueIsAdjusting()) { deleteButton.setEnabled(versionsList.getSelectedValue() != null); } }); // Bouton supprimer deleteButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { deleteSelectedVersion(); } }); // Bouton actualiser refreshButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { loadInstalledVersions(); } }); } private void loadInstalledVersions() { listModel.clear(); List installedVersions = getInstalledVersions(); if (installedVersions.isEmpty()) { sizeLabel.setText("Aucune version installée"); } else { for (String version : installedVersions) { listModel.addElement(version); } // Calculer la taille totale long totalSize = calculateTotalSize(installedVersions); String sizeText = formatSize(totalSize); sizeLabel.setText(installedVersions.size() + " version(s) - " + sizeText); } } private List getInstalledVersions() { List versions = new ArrayList<>(); Path versionsDir = Paths.get(MINECRAFT_DIR, "versions"); try { if (Files.exists(versionsDir) && Files.isDirectory(versionsDir)) { Files.list(versionsDir) .filter(Files::isDirectory) .forEach(versionDir -> { String versionName = versionDir.getFileName().toString(); Path jarFile = versionDir.resolve(versionName + ".jar"); Path jsonFile = versionDir.resolve(versionName + ".json"); // Vérifier que les fichiers essentiels existent if (Files.exists(jarFile) && Files.exists(jsonFile)) { versions.add(versionName); } }); } } catch (Exception e) { System.err.println("Erreur lors de la lecture des versions: " + e.getMessage()); } versions.sort(String::compareTo); return versions; } private long calculateTotalSize(List versions) { long totalSize = 0; for (String version : versions) { Path versionDir = Paths.get(MINECRAFT_DIR, "versions", version); try { totalSize += Files.walk(versionDir) .filter(Files::isRegularFile) .mapToLong(path -> { try { return Files.size(path); } catch (Exception e) { return 0; } }) .sum(); } catch (Exception e) { // Ignorer les erreurs pour cette version } } return totalSize; } private String formatSize(long bytes) { if (bytes < 1024) return bytes + " B"; if (bytes < 1024 * 1024) return String.format("%.1f KB", bytes / 1024.0); if (bytes < 1024 * 1024 * 1024) return String.format("%.1f MB", bytes / (1024.0 * 1024.0)); return String.format("%.1f GB", bytes / (1024.0 * 1024.0 * 1024.0)); } private void deleteSelectedVersion() { String selectedVersion = versionsList.getSelectedValue(); if (selectedVersion == null) return; int result = JOptionPane.showConfirmDialog( this, "Voulez-vous vraiment supprimer la version " + selectedVersion + " ?\n\n" + "Cette action est irréversible.", "Confirmer la suppression", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE ); if (result == JOptionPane.YES_OPTION) { if (deleteVersion(selectedVersion)) { JOptionPane.showMessageDialog( this, "Version " + selectedVersion + " Supprimée avec succès.", "Suppression réussie", JOptionPane.INFORMATION_MESSAGE ); loadInstalledVersions(); // Actualiser la liste } else { JOptionPane.showMessageDialog( this, "Erreur lors de la suppression de la version " + selectedVersion + ".\n" + "Vérifiez que les fichiers ne sont pas en cours d'utilisation.", "Erreur de suppression", JOptionPane.ERROR_MESSAGE ); } } } private boolean deleteVersion(String version) { Path versionDir = Paths.get(MINECRAFT_DIR, "versions", version); try { // Supprimer récursivement le dossier de la version Files.walk(versionDir) .sorted((a, b) -> b.compareTo(a)) // Ordre inverse pour supprimer les fichiers avant les dossiers .forEach(path -> { try { Files.delete(path); } catch (Exception e) { System.err.println("Impossible de supprimer: " + path); } }); return !Files.exists(versionDir); } catch (Exception e) { System.err.println("[ERROR] Erreur lors de la suppression: " + e.getMessage()); return false; } } }