diff --git a/robots/src/gui/MainApplicationFrame.java b/robots/src/gui/MainApplicationFrame.java index 62e943e..c472886 100644 --- a/robots/src/gui/MainApplicationFrame.java +++ b/robots/src/gui/MainApplicationFrame.java @@ -3,6 +3,8 @@ import java.awt.Dimension; import java.awt.Toolkit; import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import javax.swing.JDesktopPane; import javax.swing.JFrame; @@ -10,136 +12,150 @@ import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; +import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import log.Logger; -/** - * Что требуется сделать: - * 1. Метод создания меню перегружен функционалом и трудно читается. - * Следует разделить его на серию более простых методов (или вообще выделить отдельный класс). - * - */ public class MainApplicationFrame extends JFrame { private final JDesktopPane desktopPane = new JDesktopPane(); - + private WindowStateManager stateManager; + private LogWindow logWindow; + private GameWindow gameWindow; + public MainApplicationFrame() { - //Make the big window be indented 50 pixels from each edge - //of the screen. - int inset = 50; + stateManager = new WindowStateManager(); + + stateManager.loadFromFile(); + + int inset = 50; Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); setBounds(inset, inset, - screenSize.width - inset*2, - screenSize.height - inset*2); + screenSize.width - inset*2, + screenSize.height - inset*2); setContentPane(desktopPane); - - - LogWindow logWindow = createLogWindow(); - addWindow(logWindow); - GameWindow gameWindow = new GameWindow(); - gameWindow.setSize(400, 400); + logWindow = createLogWindow(); + gameWindow = new GameWindow(); + gameWindow.setSize(400, 400); + + stateManager.applyWindowState(logWindow, "logWindow"); + stateManager.applyWindowState(gameWindow, "gameWindow"); + + addWindow(logWindow); addWindow(gameWindow); - setJMenuBar(generateMenuBar()); - setDefaultCloseOperation(EXIT_ON_CLOSE); + setJMenuBar(createMenuBar()); + + // Обработчик закрытия окна + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + exitApplication(); + } + }); } - + protected LogWindow createLogWindow() { LogWindow logWindow = new LogWindow(Logger.getDefaultLogSource()); - logWindow.setLocation(10,10); + logWindow.setLocation(10, 10); logWindow.setSize(300, 800); setMinimumSize(logWindow.getSize()); logWindow.pack(); Logger.debug("Протокол работает"); return logWindow; } - + protected void addWindow(JInternalFrame frame) { desktopPane.add(frame); frame.setVisible(true); } - -// protected JMenuBar createMenuBar() { -// JMenuBar menuBar = new JMenuBar(); -// -// //Set up the lone menu. -// JMenu menu = new JMenu("Document"); -// menu.setMnemonic(KeyEvent.VK_D); -// menuBar.add(menu); -// -// //Set up the first menu item. -// JMenuItem menuItem = new JMenuItem("New"); -// menuItem.setMnemonic(KeyEvent.VK_N); -// menuItem.setAccelerator(KeyStroke.getKeyStroke( -// KeyEvent.VK_N, ActionEvent.ALT_MASK)); -// menuItem.setActionCommand("new"); -//// menuItem.addActionListener(this); -// menu.add(menuItem); -// -// //Set up the second menu item. -// menuItem = new JMenuItem("Quit"); -// menuItem.setMnemonic(KeyEvent.VK_Q); -// menuItem.setAccelerator(KeyStroke.getKeyStroke( -// KeyEvent.VK_Q, ActionEvent.ALT_MASK)); -// menuItem.setActionCommand("quit"); -//// menuItem.addActionListener(this); -// menu.add(menuItem); -// -// return menuBar; -// } - - private JMenuBar generateMenuBar() + + private JMenuBar createMenuBar() { JMenuBar menuBar = new JMenuBar(); - + menuBar.add(createFileMenu()); + menuBar.add(createLookAndFeelMenu()); + menuBar.add(createTestMenu()); + return menuBar; + } + + private JMenu createFileMenu() + { + JMenu fileMenu = new JMenu("Файл"); + fileMenu.setMnemonic(KeyEvent.VK_F); + fileMenu.add(createExitMenuItem()); + return fileMenu; + } + + private JMenuItem createExitMenuItem() + { + JMenuItem exitMenuItem = new JMenuItem("Выход", KeyEvent.VK_X); + exitMenuItem.addActionListener((event) -> exitApplication()); + return exitMenuItem; + } + + private JMenu createLookAndFeelMenu() + { JMenu lookAndFeelMenu = new JMenu("Режим отображения"); lookAndFeelMenu.setMnemonic(KeyEvent.VK_V); lookAndFeelMenu.getAccessibleContext().setAccessibleDescription( "Управление режимом отображения приложения"); - - { - JMenuItem systemLookAndFeel = new JMenuItem("Системная схема", KeyEvent.VK_S); - systemLookAndFeel.addActionListener((event) -> { - setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - this.invalidate(); - }); - lookAndFeelMenu.add(systemLookAndFeel); - } - { - JMenuItem crossplatformLookAndFeel = new JMenuItem("Универсальная схема", KeyEvent.VK_S); - crossplatformLookAndFeel.addActionListener((event) -> { - setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); - this.invalidate(); - }); - lookAndFeelMenu.add(crossplatformLookAndFeel); - } + lookAndFeelMenu.add(createSystemLookAndFeelMenuItem()); + lookAndFeelMenu.add(createCrossplatformLookAndFeelMenuItem()); + + return lookAndFeelMenu; + } + private JMenuItem createSystemLookAndFeelMenuItem() + { + JMenuItem systemLookAndFeel = new JMenuItem("Системная схема", KeyEvent.VK_S); + systemLookAndFeel.addActionListener((event) -> { + setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + this.invalidate(); + }); + return systemLookAndFeel; + } + + private JMenuItem createCrossplatformLookAndFeelMenuItem() + { + JMenuItem crossplatformLookAndFeel = new JMenuItem("Универсальная схема", KeyEvent.VK_S); + crossplatformLookAndFeel.addActionListener((event) -> { + setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); + this.invalidate(); + }); + return crossplatformLookAndFeel; + } + + private JMenu createTestMenu() + { JMenu testMenu = new JMenu("Тесты"); testMenu.setMnemonic(KeyEvent.VK_T); testMenu.getAccessibleContext().setAccessibleDescription( "Тестовые команды"); - - { - JMenuItem addLogMessageItem = new JMenuItem("Сообщение в лог", KeyEvent.VK_S); - addLogMessageItem.addActionListener((event) -> { - Logger.debug("Новая строка"); - }); - testMenu.add(addLogMessageItem); - } - menuBar.add(lookAndFeelMenu); - menuBar.add(testMenu); - return menuBar; + testMenu.add(createAddLogMessageMenuItem()); + + return testMenu; + } + + private JMenuItem createAddLogMessageMenuItem() + { + JMenuItem addLogMessageItem = new JMenuItem("Сообщение в лог", KeyEvent.VK_S); + addLogMessageItem.addActionListener((event) -> { + Logger.debug("Новая строка"); + }); + return addLogMessageItem; } - + private void setLookAndFeel(String className) { try @@ -148,9 +164,42 @@ private void setLookAndFeel(String className) SwingUtilities.updateComponentTreeUI(this); } catch (ClassNotFoundException | InstantiationException - | IllegalAccessException | UnsupportedLookAndFeelException e) + | IllegalAccessException | UnsupportedLookAndFeelException e) { // just ignore } } -} + + private void exitApplication() + { + Object[] options = {"Да", "Нет"}; + + int result = JOptionPane.showOptionDialog( + this, + "Вы действительно хотите выйти из приложения?", + "Подтверждение выхода", + JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE, + null, + options, + options[1]); + + if (result == JOptionPane.YES_OPTION) { + saveWindowStates(); + + Logger.debug("Приложение завершает работу"); + System.exit(0); + } + } + + private void saveWindowStates() + { + if (logWindow != null) { + stateManager.saveWindowState(logWindow, "logWindow"); + } + if (gameWindow != null) { + stateManager.saveWindowState(gameWindow, "gameWindow"); + } + stateManager.saveToFile(); + } +} \ No newline at end of file diff --git a/robots/src/gui/WindowStateLoader.java b/robots/src/gui/WindowStateLoader.java new file mode 100644 index 0000000..0862366 --- /dev/null +++ b/robots/src/gui/WindowStateLoader.java @@ -0,0 +1,65 @@ +package gui; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; +import javax.swing.JInternalFrame; + +public class WindowStateLoader { + + private static final String CONFIG_FILE = System.getProperty("user.home") + + File.separator + + ".robot_game_config.properties"; + + public Properties loadFromFile() { + Properties properties = new Properties(); + File configFile = new File(CONFIG_FILE); + + if (!configFile.exists()) { + return properties; + } + + try (FileInputStream in = new FileInputStream(configFile)) { + properties.load(in); + } catch (IOException e) { + System.err.println("Ошибка загрузки конфигурации: " + e.getMessage()); + } + + return properties; + } + + public void applyWindowState(Properties properties, JInternalFrame frame, String windowKey) { + try { + String xStr = properties.getProperty(windowKey + ".x"); + String yStr = properties.getProperty(windowKey + ".y"); + if (xStr != null && yStr != null) { + frame.setLocation(Integer.parseInt(xStr), Integer.parseInt(yStr)); + } + + String widthStr = properties.getProperty(windowKey + ".width"); + String heightStr = properties.getProperty(windowKey + ".height"); + if (widthStr != null && heightStr != null) { + frame.setSize(Integer.parseInt(widthStr), Integer.parseInt(heightStr)); + } + + String state = properties.getProperty(windowKey + ".state"); + if (state != null) { + switch (state) { + case "ICONIFIED": + frame.setIcon(true); + break; + case "MAXIMIZED": + try { + frame.setMaximum(true); + } catch (Exception e) { + } + break; + } + } + + } catch (Exception e) { + System.err.println("Ошибка восстановления окна " + windowKey + ": " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/robots/src/gui/WindowStateManager.java b/robots/src/gui/WindowStateManager.java new file mode 100644 index 0000000..2a49bf1 --- /dev/null +++ b/robots/src/gui/WindowStateManager.java @@ -0,0 +1,33 @@ +package gui; + +import java.util.Properties; +import javax.swing.JInternalFrame; + +public class WindowStateManager { + + private Properties properties; + private WindowStateSaver saver; + private WindowStateLoader loader; + + public WindowStateManager() { + this.properties = new Properties(); + this.saver = new WindowStateSaver(); + this.loader = new WindowStateLoader(); + } + + public void loadFromFile() { + this.properties = loader.loadFromFile(); + } + + public void saveToFile() { + saver.saveToFile(properties); + } + + public void saveWindowState(JInternalFrame frame, String windowKey) { + saver.saveWindowState(properties, frame, windowKey); + } + + public void applyWindowState(JInternalFrame frame, String windowKey) { + loader.applyWindowState(properties, frame, windowKey); + } +} \ No newline at end of file diff --git a/robots/src/gui/WindowStateSaver.java b/robots/src/gui/WindowStateSaver.java new file mode 100644 index 0000000..5db619c --- /dev/null +++ b/robots/src/gui/WindowStateSaver.java @@ -0,0 +1,44 @@ +package gui; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; +import javax.swing.JInternalFrame; + +public class WindowStateSaver { + + private static final String CONFIG_FILE = System.getProperty("user.home") + + File.separator + + ".robot_game_config.properties"; + + public void saveWindowState(Properties properties, JInternalFrame frame, String windowKey) { + try { + java.awt.Point location = frame.getLocation(); + properties.setProperty(windowKey + ".x", String.valueOf(location.x)); + properties.setProperty(windowKey + ".y", String.valueOf(location.y)); + + properties.setProperty(windowKey + ".width", String.valueOf(frame.getWidth())); + properties.setProperty(windowKey + ".height", String.valueOf(frame.getHeight())); + + if (frame.isIcon()) { + properties.setProperty(windowKey + ".state", "ICONIFIED"); + } else if (frame.isMaximum()) { + properties.setProperty(windowKey + ".state", "MAXIMIZED"); + } else { + properties.setProperty(windowKey + ".state", "NORMAL"); + } + + } catch (Exception e) { + System.err.println("Ошибка сохранения состояния окна " + windowKey + ": " + e.getMessage()); + } + } + + public void saveToFile(Properties properties) { + try (FileOutputStream out = new FileOutputStream(CONFIG_FILE)) { + properties.store(out, "Robot Game Configuration"); + } catch (IOException e) { + System.err.println("Ошибка сохранения конфигурации: " + e.getMessage()); + } + } +} \ No newline at end of file