diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/Robots.iml b/.idea/Robots.iml new file mode 100644 index 0000000..8df936b --- /dev/null +++ b/.idea/Robots.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..8b92ee8 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..650a132 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/out/production/Robots/gui/GameVisualizer$1.class b/out/production/Robots/gui/GameVisualizer$1.class new file mode 100644 index 0000000..4fb9850 Binary files /dev/null and b/out/production/Robots/gui/GameVisualizer$1.class differ diff --git a/out/production/Robots/gui/GameVisualizer$2.class b/out/production/Robots/gui/GameVisualizer$2.class new file mode 100644 index 0000000..ba3bd49 Binary files /dev/null and b/out/production/Robots/gui/GameVisualizer$2.class differ diff --git a/out/production/Robots/gui/GameVisualizer$3.class b/out/production/Robots/gui/GameVisualizer$3.class new file mode 100644 index 0000000..9eca837 Binary files /dev/null and b/out/production/Robots/gui/GameVisualizer$3.class differ diff --git a/out/production/Robots/gui/GameVisualizer.class b/out/production/Robots/gui/GameVisualizer.class new file mode 100644 index 0000000..99297d8 Binary files /dev/null and b/out/production/Robots/gui/GameVisualizer.class differ diff --git a/out/production/Robots/gui/GameWindow.class b/out/production/Robots/gui/GameWindow.class new file mode 100644 index 0000000..dcdd943 Binary files /dev/null and b/out/production/Robots/gui/GameWindow.class differ diff --git a/out/production/Robots/gui/Listener.class b/out/production/Robots/gui/Listener.class new file mode 100644 index 0000000..223493f Binary files /dev/null and b/out/production/Robots/gui/Listener.class differ diff --git a/out/production/Robots/gui/LogWindow.class b/out/production/Robots/gui/LogWindow.class new file mode 100644 index 0000000..d6304ed Binary files /dev/null and b/out/production/Robots/gui/LogWindow.class differ diff --git a/out/production/Robots/gui/MainApplicationFrame$1.class b/out/production/Robots/gui/MainApplicationFrame$1.class new file mode 100644 index 0000000..27fe8e2 Binary files /dev/null and b/out/production/Robots/gui/MainApplicationFrame$1.class differ diff --git a/out/production/Robots/gui/MainApplicationFrame.class b/out/production/Robots/gui/MainApplicationFrame.class new file mode 100644 index 0000000..b597b5d Binary files /dev/null and b/out/production/Robots/gui/MainApplicationFrame.class differ diff --git a/out/production/Robots/gui/RobotsProgram.class b/out/production/Robots/gui/RobotsProgram.class new file mode 100644 index 0000000..bcac843 Binary files /dev/null and b/out/production/Robots/gui/RobotsProgram.class differ diff --git a/out/production/Robots/log/LogChangeListener.class b/out/production/Robots/log/LogChangeListener.class new file mode 100644 index 0000000..565fd48 Binary files /dev/null and b/out/production/Robots/log/LogChangeListener.class differ diff --git a/out/production/Robots/log/LogEntry.class b/out/production/Robots/log/LogEntry.class new file mode 100644 index 0000000..59e3960 Binary files /dev/null and b/out/production/Robots/log/LogEntry.class differ diff --git a/out/production/Robots/log/LogLevel.class b/out/production/Robots/log/LogLevel.class new file mode 100644 index 0000000..15d09c0 Binary files /dev/null and b/out/production/Robots/log/LogLevel.class differ diff --git a/out/production/Robots/log/LogWindowSource.class b/out/production/Robots/log/LogWindowSource.class new file mode 100644 index 0000000..4c8d31d Binary files /dev/null and b/out/production/Robots/log/LogWindowSource.class differ diff --git a/out/production/Robots/log/Logger.class b/out/production/Robots/log/Logger.class new file mode 100644 index 0000000..0386159 Binary files /dev/null and b/out/production/Robots/log/Logger.class differ diff --git a/robots/src/gui/Listener.java b/robots/src/gui/Listener.java new file mode 100644 index 0000000..647cd84 --- /dev/null +++ b/robots/src/gui/Listener.java @@ -0,0 +1,8 @@ +package gui; + +import java.awt.event.WindowAdapter; +import java.awt.event.WindowListener; + +public class Listener extends WindowAdapter { + +} diff --git a/robots/src/gui/MainApplicationFrame.java b/robots/src/gui/MainApplicationFrame.java index 62e943e..2756f06 100644 --- a/robots/src/gui/MainApplicationFrame.java +++ b/robots/src/gui/MainApplicationFrame.java @@ -3,6 +3,13 @@ import java.awt.Dimension; import java.awt.Toolkit; import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.beans.PropertyVetoException; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; import javax.swing.JDesktopPane; import javax.swing.JFrame; @@ -13,6 +20,7 @@ import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.JOptionPane; import log.Logger; @@ -25,7 +33,23 @@ public class MainApplicationFrame extends JFrame { private final JDesktopPane desktopPane = new JDesktopPane(); - + + private final LogWindow logWindowGlobal; + private final GameWindow gameWindowGlobal; + private static final String WINDOW_STATE_FILE = System.getProperty("user.home") + "\\window_state.properties"; + + private void confirmExit() { + int result = JOptionPane.showConfirmDialog(this, + "Вы действительно хотите выйти?", + "Подтверждение выхода", + JOptionPane.YES_NO_OPTION); + if (result == JOptionPane.YES_OPTION) { + saveWindowStates(); + dispose(); + System.exit(0); + } + } + public MainApplicationFrame() { //Make the big window be indented 50 pixels from each edge //of the screen. @@ -39,14 +63,24 @@ public MainApplicationFrame() { LogWindow logWindow = createLogWindow(); + logWindowGlobal = logWindow; addWindow(logWindow); GameWindow gameWindow = new GameWindow(); + gameWindowGlobal = gameWindow; gameWindow.setSize(400, 400); addWindow(gameWindow); + loadWindowStates(); + setJMenuBar(generateMenuBar()); - setDefaultCloseOperation(EXIT_ON_CLOSE); + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e){ + confirmExit(); + } + }); } protected LogWindow createLogWindow() @@ -65,15 +99,85 @@ protected void addWindow(JInternalFrame frame) desktopPane.add(frame); frame.setVisible(true); } - + + private void saveWindowStates() { + Properties props = new Properties(); + + props.setProperty("frame.x", String.valueOf(getX())); + props.setProperty("frame.y", String.valueOf(getY())); + props.setProperty("frame.width", String.valueOf(getWidth())); + props.setProperty("frame.height", String.valueOf(getHeight())); + props.setProperty("frame.extendedState", String.valueOf(getExtendedState())); + + saveInternalFrameState(props, logWindowGlobal, "LogWindow"); + saveInternalFrameState(props, gameWindowGlobal, "GameWindow"); + + try (FileOutputStream out = new FileOutputStream(WINDOW_STATE_FILE)) { + props.store(out, "Window states"); + } catch (IOException e) { + System.err.println("Не удалось сохранить состояние окон: " + e.getMessage()); + } + } + + private void saveInternalFrameState(Properties props, JInternalFrame frame, String prefix) { + props.setProperty(prefix + ".x", String.valueOf(frame.getX())); + props.setProperty(prefix + ".y", String.valueOf(frame.getY())); + props.setProperty(prefix + ".width", String.valueOf(frame.getWidth())); + props.setProperty(prefix + ".height", String.valueOf(frame.getHeight())); + props.setProperty(prefix + ".isIcon", String.valueOf(frame.isIcon())); + props.setProperty(prefix + ".isMaximum", String.valueOf(frame.isMaximum())); + } + + private void loadWindowStates() { + Properties props = new Properties(); + try (FileInputStream in = new FileInputStream(WINDOW_STATE_FILE)) { + props.load(in); + } catch (IOException e) { + return; + } + + try { + int x = Integer.parseInt(props.getProperty("frame.x")); + int y = Integer.parseInt(props.getProperty("frame.y")); + int width = Integer.parseInt(props.getProperty("frame.width")); + int height = Integer.parseInt(props.getProperty("frame.height")); + setBounds(x, y, width, height); + int extendedState = Integer.parseInt(props.getProperty("frame.extendedState")); + setExtendedState(extendedState); + } catch (NumberFormatException e) {} + + loadInternalFrameState(props, logWindowGlobal, "LogWindow"); + loadInternalFrameState(props, gameWindowGlobal, "GameWindow"); + } + + + private void loadInternalFrameState(Properties props, JInternalFrame frame, String prefix) { + try { + int x = Integer.parseInt(props.getProperty(prefix + ".x")); + int y = Integer.parseInt(props.getProperty(prefix + ".y")); + int width = Integer.parseInt(props.getProperty(prefix + ".width")); + int height = Integer.parseInt(props.getProperty(prefix + ".height")); + boolean isIcon = Boolean.parseBoolean(props.getProperty(prefix + ".isIcon")); + boolean isMaximum = Boolean.parseBoolean(props.getProperty(prefix + ".isMaximum")); + + // Сначала устанавливаем границы, потом развёрнутость/свёрнутость + frame.setBounds(x, y, width, height); + if (isMaximum) { + frame.setMaximum(true); + } else { + frame.setIcon(isIcon); + } + } catch (NumberFormatException | PropertyVetoException e) {} + } + // 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); @@ -82,7 +186,7 @@ protected void addWindow(JInternalFrame frame) // menuItem.setActionCommand("new"); //// menuItem.addActionListener(this); // menu.add(menuItem); -// +// // //Set up the second menu item. // menuItem = new JMenuItem("Quit"); // menuItem.setMnemonic(KeyEvent.VK_Q); @@ -91,52 +195,78 @@ protected void addWindow(JInternalFrame frame) // menuItem.setActionCommand("quit"); //// menuItem.addActionListener(this); // menu.add(menuItem); -// +// // return menuBar; // } - - private JMenuBar generateMenuBar() + + private void addSystemLookAndFeel(JMenu lookAndFeelMenu) { - JMenuBar menuBar = new JMenuBar(); - - 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); - } + } - { + private void addCrossplatformLookAndFeel(JMenu lookAndFeelMenu) + { JMenuItem crossplatformLookAndFeel = new JMenuItem("Универсальная схема", KeyEvent.VK_S); crossplatformLookAndFeel.addActionListener((event) -> { setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); this.invalidate(); }); lookAndFeelMenu.add(crossplatformLookAndFeel); - } + } + + private void addLogMessageItem(JMenu testMenu) + { + JMenuItem addLogMessageItem = new JMenuItem("Сообщение в лог", KeyEvent.VK_S); + addLogMessageItem.addActionListener((event) -> { + Logger.debug("Новая строка"); + }); + testMenu.add(addLogMessageItem); + } + + private void addExitLookAndFeel(JMenu exitMenu) + { + JMenuItem addLogMessageItem = new JMenuItem("Завершение работы программы", KeyEvent.VK_S); + addLogMessageItem.addActionListener((event) -> { + confirmExit(); + }); + exitMenu.add(addLogMessageItem); + } + + private JMenuBar generateMenuBar() + { + JMenuBar menuBar = new JMenuBar(); + + JMenu lookAndFeelMenu = new JMenu("Режим отображения"); + lookAndFeelMenu.setMnemonic(KeyEvent.VK_V); + lookAndFeelMenu.getAccessibleContext().setAccessibleDescription( + "Управление режимом отображения приложения"); + + addSystemLookAndFeel(lookAndFeelMenu); + + addCrossplatformLookAndFeel(lookAndFeelMenu); 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); - } + + addLogMessageItem(testMenu); + + JMenu exitMenu = new JMenu("Выход"); + exitMenu.setMnemonic(KeyEvent.VK_T); + exitMenu.getAccessibleContext().setAccessibleDescription( + "Меню выхода"); + + addExitLookAndFeel(exitMenu); menuBar.add(lookAndFeelMenu); menuBar.add(testMenu); + menuBar.add(exitMenu); return menuBar; } diff --git a/robots/src/gui/RobotsProgram.java b/robots/src/gui/RobotsProgram.java index ae0930a..a8800b1 100644 --- a/robots/src/gui/RobotsProgram.java +++ b/robots/src/gui/RobotsProgram.java @@ -1,6 +1,7 @@ package gui; import java.awt.Frame; +import java.util.Locale; import javax.swing.SwingUtilities; import javax.swing.UIManager; @@ -8,6 +9,11 @@ public class RobotsProgram { public static void main(String[] args) { + UIManager.put("OptionPane.yesButtonText", "Да"); + UIManager.put("OptionPane.noButtonText", "Нет"); + UIManager.put("OptionPane.okButtonText", "OK"); + UIManager.put("OptionPane.cancelButtonText", "Отмена"); + UIManager.put("OptionPane.titleText", "Подтверждение"); try { UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); // UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); diff --git a/robots/src/log/LogWindowSource.java b/robots/src/log/LogWindowSource.java index ca0ce44..5e3a4ac 100644 --- a/robots/src/log/LogWindowSource.java +++ b/robots/src/log/LogWindowSource.java @@ -49,19 +49,16 @@ public void append(LogLevel logLevel, String strMessage) { LogEntry entry = new LogEntry(logLevel, strMessage); m_messages.add(entry); - LogChangeListener [] activeListeners = m_activeListeners; - if (activeListeners == null) + if(m_messages.size() > m_iQueueLength) + m_messages.removeFirst(); + if (m_activeListeners == null) { synchronized (m_listeners) { - if (m_activeListeners == null) - { - activeListeners = m_listeners.toArray(new LogChangeListener [0]); - m_activeListeners = activeListeners; - } + m_activeListeners = m_listeners.toArray(new LogChangeListener [0]); } } - for (LogChangeListener listener : activeListeners) + for (LogChangeListener listener : m_activeListeners) { listener.onLogChanged(); } diff --git a/robots/src/log/Logger.java b/robots/src/log/Logger.java index b008a5d..91c71b6 100644 --- a/robots/src/log/Logger.java +++ b/robots/src/log/Logger.java @@ -4,7 +4,7 @@ public final class Logger { private static final LogWindowSource defaultLogSource; static { - defaultLogSource = new LogWindowSource(100); + defaultLogSource = new LogWindowSource(5); } private Logger()