Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions robots/src/config/ConfigManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package config;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

/**
* Универсальный менеджер конфигурации.
* Отвечает только за сохранение и загрузку пар "ключ-значение" в файл.
* Никак не связан с GUI.
*/
public class ConfigManager {
// Имя файла настроек, который будет создаваться в корне проекта
private static final String CONFIG_FILE_NAME = "window_settings.properties";
private final Properties properties;
private final File configFile;

public ConfigManager() {
this.properties = new Properties();
// Находим домашнюю директорию пользователя, чтобы сохранять конфиг туда
String userHome = System.getProperty("user.home");
this.configFile = new File(userHome, CONFIG_FILE_NAME);
load();
}

/**
* Возвращает значение по ключу. Если ключа нет, вернет defaultValue.
*/
public String getValue(String key, String defaultValue) {
return properties.getProperty(key, defaultValue);
}

/**
* Устанавливает значение для ключа.
*/
public void setValue(String key, String value) {
properties.setProperty(key, value);
}

/**
* Загружает настройки из файла.
*/
private void load() {
if (configFile.exists()) {
try (FileInputStream in = new FileInputStream(configFile)) {
properties.load(in);
} catch (IOException e) {
System.err.println("Ошибка при загрузке файла конфигурации: " + e.getMessage());
}
}
}

/**
* Сохраняет текущие настройки в файл на диск.
*/
public void save() {
try (FileOutputStream out = new FileOutputStream(configFile)) {
properties.store(out, "Application Window Settings");
} catch (IOException e) {
System.err.println("Ошибка при сохранении файла конфигурации: " + e.getMessage());
}
}
}
5 changes: 5 additions & 0 deletions robots/src/gui/GameVisualizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ private static Timer initTimer()
Timer timer = new Timer("events generator", true);
return timer;
}

public void stopTimer() {
m_timer.cancel();
m_timer.purge();
}

private volatile double m_robotPositionX = 100;
private volatile double m_robotPositionY = 100;
Expand Down
9 changes: 8 additions & 1 deletion robots/src/gui/GameWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@
public class GameWindow extends JInternalFrame
{
private final GameVisualizer m_visualizer;
public GameWindow()

@Override
public void dispose() {
m_visualizer.stopTimer();
super.dispose();
}

public GameWindow()
{
super("Игровое поле", true, true, true, true);
m_visualizer = new GameVisualizer();
Expand Down
201 changes: 122 additions & 79 deletions robots/src/gui/MainApplicationFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,28 @@
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.JOptionPane;

import config.ConfigManager;
import log.Logger;

/**
* Что требуется сделать:
* 1. Метод создания меню перегружен функционалом и трудно читается.
* Следует разделить его на серию более простых методов (или вообще выделить отдельный класс).
*
*/
import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;

public class MainApplicationFrame extends JFrame
{
private final JDesktopPane desktopPane = new JDesktopPane();

public MainApplicationFrame() {
//Make the big window be indented 50 pixels from each edge
//of the screen.
int inset = 50;
int inset = 50;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds(inset, inset,
screenSize.width - inset*2,
screenSize.height - inset*2);

setContentPane(desktopPane);


LogWindow logWindow = createLogWindow();
addWindow(logWindow);

Expand All @@ -46,9 +43,16 @@ public MainApplicationFrame() {
addWindow(gameWindow);

setJMenuBar(generateMenuBar());
setDefaultCloseOperation(EXIT_ON_CLOSE);
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);

addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
exitApplication();
}
});
}

protected LogWindow createLogWindow()
{
LogWindow logWindow = new LogWindow(Logger.getDefaultLogSource());
Expand All @@ -59,87 +63,73 @@ protected LogWindow createLogWindow()
Logger.debug("Протокол работает");
return logWindow;
}

protected void addWindow(JInternalFrame frame)
{
desktopPane.add(frame);
frame.setVisible(true);
restoreWindowState(frame);
}

// 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()
{
JMenuBar menuBar = new JMenuBar();


menuBar.add(createLookAndFeelMenu());
menuBar.add(createTestMenu());
menuBar.add(createActionMenu());

return menuBar;
}

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);
}
JMenuItem systemLookAndFeel = new JMenuItem("Системная схема", KeyEvent.VK_S);
systemLookAndFeel.addActionListener((event) -> {
setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
this.invalidate();
});
lookAndFeelMenu.add(systemLookAndFeel);

JMenuItem crossplatformLookAndFeel = new JMenuItem("Универсальная схема", KeyEvent.VK_U);
crossplatformLookAndFeel.addActionListener((event) -> {
setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
this.invalidate();
});
lookAndFeelMenu.add(crossplatformLookAndFeel);

return lookAndFeelMenu;
}

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;
JMenuItem addLogMessageItem = new JMenuItem("Сообщение в лог", KeyEvent.VK_S);
addLogMessageItem.addActionListener((event) -> {
Logger.debug("Новая строка");
});
testMenu.add(addLogMessageItem);

return testMenu;
}


private JMenu createActionMenu() {
JMenu actionMenu = new JMenu("Управление");
actionMenu.setMnemonic(KeyEvent.VK_A);

JMenuItem exitItem = new JMenuItem("Выход", KeyEvent.VK_X);
exitItem.addActionListener((event) -> {
// Вызываем нашу готовую логику из Шага №2
exitApplication();
});
actionMenu.add(exitItem);

return actionMenu;
}

private void setLookAndFeel(String className)
{
try
Expand All @@ -153,4 +143,57 @@ private void setLookAndFeel(String className)
// just ignore
}
}

private final ConfigManager configManager = new ConfigManager();
private final WindowStateManager windowStateManager = new WindowStateManager(configManager);

private void saveWindowStates() {
for (JInternalFrame frame : desktopPane.getAllFrames()) {
String windowId = frame.getName();

if (windowId != null && !windowId.isEmpty()) {
windowStateManager.saveInternalFrameState(windowId, frame);
}
}
configManager.save();
}


private void exitApplication() {
int n = JOptionPane.showConfirmDialog(
this,
"Вы действительно хотите выйти?",
"Подтверждение выхода",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE
);

if (n == JOptionPane.YES_OPTION) {
saveWindowStates();

for (JInternalFrame frame : desktopPane.getAllFrames()) {
frame.dispose();
}

this.dispose(); // Закрываем главное окно
}
}

private void restoreWindowState(JInternalFrame frame) {
String windowId = frame.getName();

if (windowId == null || windowId.isEmpty()) {
return;
}

int defaultX = 10, defaultY = 10, defaultWidth = 400, defaultHeight = 400;

if ("log_window".equals(windowId)) {
defaultX = 10; defaultY = 10; defaultWidth = 300; defaultHeight = 800;
} else if ("game_window".equals(windowId)) {
defaultX = 320; defaultY = 10; defaultWidth = 400; defaultHeight = 400;
}

windowStateManager.restoreInternalFrameState(windowId, frame, defaultX, defaultY, defaultWidth, defaultHeight);
}
}
12 changes: 9 additions & 3 deletions robots/src/gui/RobotsProgram.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@ public class RobotsProgram
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
// UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());

// --- ШАГ 5: Глобальная русификация ---
UIManager.put("OptionPane.yesButtonText", "Да");
UIManager.put("OptionPane.noButtonText", "Нет");
UIManager.put("OptionPane.cancelButtonText", "Отмена");
UIManager.put("OptionPane.okButtonText", "Готово");
// -------------------------------------

} catch (Exception e) {
e.printStackTrace();
}

SwingUtilities.invokeLater(() -> {
MainApplicationFrame frame = new MainApplicationFrame();
frame.pack();
Expand Down
Loading