diff --git a/.gitignore b/.gitignore
index 2c6eb3893..d76946210 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,35 @@
-/.metadata
-/robots/.settings
-/robots/bin
-eclipse.bat
\ No newline at end of file
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 000000000..26d33521a
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 000000000..aa00ffab7
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 000000000..ecfa09c0d
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 000000000..2b63946d5
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 000000000..35eb1ddfb
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 000000000..007462f84
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,17 @@
+
+
+ 4.0.0
+
+ org.robots
+ Robots
+ 1.0-SNAPSHOT
+
+
+ 21
+ 21
+ UTF-8
+
+
+
\ No newline at end of file
diff --git a/robots/.classpath b/robots/.classpath
deleted file mode 100644
index fceb4801b..000000000
--- a/robots/.classpath
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/robots/.gitignore b/robots/.gitignore
deleted file mode 100644
index 2757ffa76..000000000
--- a/robots/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/bin/
-/.settings/
diff --git a/robots/.project b/robots/.project
deleted file mode 100644
index 78e165663..000000000
--- a/robots/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
- Robots
-
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
-
- org.eclipse.jdt.core.javanature
-
-
diff --git a/robots/src/gui/MainApplicationFrame.java b/robots/src/gui/MainApplicationFrame.java
deleted file mode 100644
index 62e943ee1..000000000
--- a/robots/src/gui/MainApplicationFrame.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package gui;
-
-import java.awt.Dimension;
-import java.awt.Toolkit;
-import java.awt.event.KeyEvent;
-
-import javax.swing.JDesktopPane;
-import javax.swing.JFrame;
-import javax.swing.JInternalFrame;
-import javax.swing.JMenu;
-import javax.swing.JMenuBar;
-import javax.swing.JMenuItem;
-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();
-
- public MainApplicationFrame() {
- //Make the big window be indented 50 pixels from each edge
- //of the screen.
- 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);
-
- GameWindow gameWindow = new GameWindow();
- gameWindow.setSize(400, 400);
- addWindow(gameWindow);
-
- setJMenuBar(generateMenuBar());
- setDefaultCloseOperation(EXIT_ON_CLOSE);
- }
-
- protected LogWindow createLogWindow()
- {
- LogWindow logWindow = new LogWindow(Logger.getDefaultLogSource());
- 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()
- {
- 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);
- }
-
- {
- JMenuItem crossplatformLookAndFeel = new JMenuItem("Универсальная схема", KeyEvent.VK_S);
- crossplatformLookAndFeel.addActionListener((event) -> {
- setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
- this.invalidate();
- });
- lookAndFeelMenu.add(crossplatformLookAndFeel);
- }
-
- 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;
- }
-
- private void setLookAndFeel(String className)
- {
- try
- {
- UIManager.setLookAndFeel(className);
- SwingUtilities.updateComponentTreeUI(this);
- }
- catch (ClassNotFoundException | InstantiationException
- | IllegalAccessException | UnsupportedLookAndFeelException e)
- {
- // just ignore
- }
- }
-}
diff --git a/robots/src/log/LogEntry.java b/robots/src/log/LogEntry.java
deleted file mode 100644
index 3d9147107..000000000
--- a/robots/src/log/LogEntry.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package log;
-
-public class LogEntry
-{
- private LogLevel m_logLevel;
- private String m_strMessage;
-
- public LogEntry(LogLevel logLevel, String strMessage)
- {
- m_strMessage = strMessage;
- m_logLevel = logLevel;
- }
-
- public String getMessage()
- {
- return m_strMessage;
- }
-
- public LogLevel getLevel()
- {
- return m_logLevel;
- }
-}
-
diff --git a/robots/src/log/LogWindowSource.java b/robots/src/log/LogWindowSource.java
deleted file mode 100644
index ca0ce4426..000000000
--- a/robots/src/log/LogWindowSource.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package log;
-
-import java.util.ArrayList;
-import java.util.Collections;
-
-/**
- * Что починить:
- * 1. Этот класс порождает утечку ресурсов (связанные слушатели оказываются
- * удерживаемыми в памяти)
- * 2. Этот класс хранит активные сообщения лога, но в такой реализации он
- * их лишь накапливает. Надо же, чтобы количество сообщений в логе было ограничено
- * величиной m_iQueueLength (т.е. реально нужна очередь сообщений
- * ограниченного размера)
- */
-public class LogWindowSource
-{
- private int m_iQueueLength;
-
- private ArrayList m_messages;
- private final ArrayList m_listeners;
- private volatile LogChangeListener[] m_activeListeners;
-
- public LogWindowSource(int iQueueLength)
- {
- m_iQueueLength = iQueueLength;
- m_messages = new ArrayList(iQueueLength);
- m_listeners = new ArrayList();
- }
-
- public void registerListener(LogChangeListener listener)
- {
- synchronized(m_listeners)
- {
- m_listeners.add(listener);
- m_activeListeners = null;
- }
- }
-
- public void unregisterListener(LogChangeListener listener)
- {
- synchronized(m_listeners)
- {
- m_listeners.remove(listener);
- m_activeListeners = null;
- }
- }
-
- public void append(LogLevel logLevel, String strMessage)
- {
- LogEntry entry = new LogEntry(logLevel, strMessage);
- m_messages.add(entry);
- LogChangeListener [] activeListeners = m_activeListeners;
- if (activeListeners == null)
- {
- synchronized (m_listeners)
- {
- if (m_activeListeners == null)
- {
- activeListeners = m_listeners.toArray(new LogChangeListener [0]);
- m_activeListeners = activeListeners;
- }
- }
- }
- for (LogChangeListener listener : activeListeners)
- {
- listener.onLogChanged();
- }
- }
-
- public int size()
- {
- return m_messages.size();
- }
-
- public Iterable range(int startFrom, int count)
- {
- if (startFrom < 0 || startFrom >= m_messages.size())
- {
- return Collections.emptyList();
- }
- int indexTo = Math.min(startFrom + count, m_messages.size());
- return m_messages.subList(startFrom, indexTo);
- }
-
- public Iterable all()
- {
- return m_messages;
- }
-}
diff --git a/robots/src/gui/RobotsProgram.java b/src/main/java/org/robots/Main.java
similarity index 71%
rename from robots/src/gui/RobotsProgram.java
rename to src/main/java/org/robots/Main.java
index ae0930a8b..e6d5595ce 100644
--- a/robots/src/gui/RobotsProgram.java
+++ b/src/main/java/org/robots/Main.java
@@ -1,21 +1,26 @@
-package gui;
+package org.robots;
+
+import org.robots.gui.MainApplicationFrame;
import java.awt.Frame;
-import javax.swing.SwingUtilities;
-import javax.swing.UIManager;
+import javax.swing.*;
-public class RobotsProgram
+public class Main
{
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
+ UIManager.put("OptionPane.yesButtonText", "Да" );
+ UIManager.put("OptionPane.noButtonText", "Нет" );
// UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
- } catch (Exception e) {
+ }
+ catch (Exception e) {
e.printStackTrace();
}
+
SwingUtilities.invokeLater(() -> {
MainApplicationFrame frame = new MainApplicationFrame();
frame.pack();
diff --git a/robots/src/gui/GameVisualizer.java b/src/main/java/org/robots/gui/GameVisualizer.java
similarity index 58%
rename from robots/src/gui/GameVisualizer.java
rename to src/main/java/org/robots/gui/GameVisualizer.java
index f82cfd8f8..d3c2b69bb 100644
--- a/robots/src/gui/GameVisualizer.java
+++ b/src/main/java/org/robots/gui/GameVisualizer.java
@@ -1,4 +1,4 @@
-package gui;
+package org.robots.gui;
import java.awt.Color;
import java.awt.EventQueue;
@@ -13,29 +13,26 @@
import javax.swing.JPanel;
-public class GameVisualizer extends JPanel
-{
- private final Timer m_timer = initTimer();
+public class GameVisualizer extends JPanel {
+ private final Timer timer = initTimer();
- private static Timer initTimer()
- {
+ private static Timer initTimer() {
Timer timer = new Timer("events generator", true);
return timer;
}
- private volatile double m_robotPositionX = 100;
- private volatile double m_robotPositionY = 100;
- private volatile double m_robotDirection = 0;
+ private volatile double robotPositionX = 100;
+ private volatile double robotPositionY = 100;
+ private volatile double robotDirection = 0;
- private volatile int m_targetPositionX = 150;
- private volatile int m_targetPositionY = 100;
+ private volatile int targetPositionX = 150;
+ private volatile int targetPositionY = 100;
private static final double maxVelocity = 0.1;
private static final double maxAngularVelocity = 0.001;
- public GameVisualizer()
- {
- m_timer.schedule(new TimerTask()
+ public GameVisualizer() {
+ timer.schedule(new TimerTask()
{
@Override
public void run()
@@ -43,7 +40,7 @@ public void run()
onRedrawEvent();
}
}, 0, 50);
- m_timer.schedule(new TimerTask()
+ timer.schedule(new TimerTask()
{
@Override
public void run()
@@ -51,6 +48,7 @@ public void run()
onModelUpdateEvent();
}
}, 0, 10);
+
addMouseListener(new MouseAdapter()
{
@Override
@@ -60,13 +58,13 @@ public void mouseClicked(MouseEvent e)
repaint();
}
});
+
setDoubleBuffered(true);
}
- protected void setTargetPosition(Point p)
- {
- m_targetPositionX = p.x;
- m_targetPositionY = p.y;
+ protected void setTargetPosition(Point p) {
+ targetPositionX = p.x;
+ targetPositionY = p.y;
}
protected void onRedrawEvent()
@@ -74,87 +72,86 @@ protected void onRedrawEvent()
EventQueue.invokeLater(this::repaint);
}
- private static double distance(double x1, double y1, double x2, double y2)
- {
+ private static double distance(double x1, double y1, double x2, double y2) {
double diffX = x1 - x2;
double diffY = y1 - y2;
return Math.sqrt(diffX * diffX + diffY * diffY);
}
- private static double angleTo(double fromX, double fromY, double toX, double toY)
- {
+ private static double angleTo(double fromX, double fromY, double toX, double toY) {
double diffX = toX - fromX;
double diffY = toY - fromY;
return asNormalizedRadians(Math.atan2(diffY, diffX));
}
- protected void onModelUpdateEvent()
- {
- double distance = distance(m_targetPositionX, m_targetPositionY,
- m_robotPositionX, m_robotPositionY);
- if (distance < 0.5)
- {
+ protected void onModelUpdateEvent() {
+ double distance = distance(targetPositionX, targetPositionY,
+ robotPositionX, robotPositionY);
+ if (distance < 0.5) {
return;
}
+
double velocity = maxVelocity;
- double angleToTarget = angleTo(m_robotPositionX, m_robotPositionY, m_targetPositionX, m_targetPositionY);
+ double angleToTarget = angleTo(robotPositionX, robotPositionY, targetPositionX, targetPositionY);
double angularVelocity = 0;
- if (angleToTarget > m_robotDirection)
- {
+
+ if (angleToTarget > robotDirection) {
angularVelocity = maxAngularVelocity;
}
- if (angleToTarget < m_robotDirection)
- {
+
+ if (angleToTarget < robotDirection) {
angularVelocity = -maxAngularVelocity;
}
moveRobot(velocity, angularVelocity, 10);
}
- private static double applyLimits(double value, double min, double max)
- {
+ private static double applyLimits(double value, double min, double max) {
if (value < min)
return min;
+
if (value > max)
return max;
+
return value;
}
- private void moveRobot(double velocity, double angularVelocity, double duration)
- {
+ private void moveRobot(double velocity, double angularVelocity, double duration) {
velocity = applyLimits(velocity, 0, maxVelocity);
angularVelocity = applyLimits(angularVelocity, -maxAngularVelocity, maxAngularVelocity);
- double newX = m_robotPositionX + velocity / angularVelocity *
- (Math.sin(m_robotDirection + angularVelocity * duration) -
- Math.sin(m_robotDirection));
- if (!Double.isFinite(newX))
- {
- newX = m_robotPositionX + velocity * duration * Math.cos(m_robotDirection);
+
+ double newX = robotPositionX + velocity / angularVelocity *
+ (Math.sin(robotDirection + angularVelocity * duration) -
+ Math.sin(robotDirection));
+
+ if (!Double.isFinite(newX)) {
+ newX = robotPositionX + velocity * duration * Math.cos(robotDirection);
}
- double newY = m_robotPositionY - velocity / angularVelocity *
- (Math.cos(m_robotDirection + angularVelocity * duration) -
- Math.cos(m_robotDirection));
- if (!Double.isFinite(newY))
- {
- newY = m_robotPositionY + velocity * duration * Math.sin(m_robotDirection);
+
+ double newY = robotPositionY - velocity / angularVelocity *
+ (Math.cos(robotDirection + angularVelocity * duration) -
+ Math.cos(robotDirection));
+
+ if (!Double.isFinite(newY)) {
+ newY = robotPositionY + velocity * duration * Math.sin(robotDirection);
}
- m_robotPositionX = newX;
- m_robotPositionY = newY;
- double newDirection = asNormalizedRadians(m_robotDirection + angularVelocity * duration);
- m_robotDirection = newDirection;
+
+ robotPositionX = newX;
+ robotPositionY = newY;
+ double newDirection = asNormalizedRadians(robotDirection + angularVelocity * duration);
+ robotDirection = newDirection;
}
- private static double asNormalizedRadians(double angle)
- {
- while (angle < 0)
- {
+ private static double asNormalizedRadians(double angle) {
+ while (angle < 0) {
angle += 2*Math.PI;
}
- while (angle >= 2*Math.PI)
- {
+
+ while (angle >= 2*Math.PI) {
angle -= 2*Math.PI;
}
+
return angle;
}
@@ -164,46 +161,49 @@ private static int round(double value)
}
@Override
- public void paint(Graphics g)
- {
+ public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
- drawRobot(g2d, round(m_robotPositionX), round(m_robotPositionY), m_robotDirection);
- drawTarget(g2d, m_targetPositionX, m_targetPositionY);
+
+ drawRobot(g2d, round(robotPositionX), round(robotPositionY), robotDirection);
+ drawTarget(g2d, targetPositionX, targetPositionY);
}
- private static void fillOval(Graphics g, int centerX, int centerY, int diam1, int diam2)
- {
+ private static void fillOval(Graphics g, int centerX, int centerY, int diam1, int diam2) {
g.fillOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2);
}
- private static void drawOval(Graphics g, int centerX, int centerY, int diam1, int diam2)
- {
+ private static void drawOval(Graphics g, int centerX, int centerY, int diam1, int diam2) {
g.drawOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2);
}
- private void drawRobot(Graphics2D g, int x, int y, double direction)
- {
- int robotCenterX = round(m_robotPositionX);
- int robotCenterY = round(m_robotPositionY);
- AffineTransform t = AffineTransform.getRotateInstance(direction, robotCenterX, robotCenterY);
+ private void drawRobot(Graphics2D g, int x, int y, double direction) {
+ int robotCenterX = round(robotPositionX);
+ int robotCenterY = round(robotPositionY);
+
+ AffineTransform t = AffineTransform.getRotateInstance(direction, robotCenterX, robotCenterY);
+
g.setTransform(t);
g.setColor(Color.MAGENTA);
fillOval(g, robotCenterX, robotCenterY, 30, 10);
+
g.setColor(Color.BLACK);
drawOval(g, robotCenterX, robotCenterY, 30, 10);
+
g.setColor(Color.WHITE);
fillOval(g, robotCenterX + 10, robotCenterY, 5, 5);
+
g.setColor(Color.BLACK);
drawOval(g, robotCenterX + 10, robotCenterY, 5, 5);
}
- private void drawTarget(Graphics2D g, int x, int y)
- {
+ private void drawTarget(Graphics2D g, int x, int y) {
AffineTransform t = AffineTransform.getRotateInstance(0, 0, 0);
+
g.setTransform(t);
g.setColor(Color.GREEN);
fillOval(g, x, y, 5, 5);
+
g.setColor(Color.BLACK);
drawOval(g, x, y, 5, 5);
}
diff --git a/robots/src/gui/GameWindow.java b/src/main/java/org/robots/gui/GameWindow.java
similarity index 53%
rename from robots/src/gui/GameWindow.java
rename to src/main/java/org/robots/gui/GameWindow.java
index ecb63c00f..0277d3508 100644
--- a/robots/src/gui/GameWindow.java
+++ b/src/main/java/org/robots/gui/GameWindow.java
@@ -1,19 +1,18 @@
-package gui;
+package org.robots.gui;
import java.awt.BorderLayout;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
-public class GameWindow extends JInternalFrame
-{
- private final GameVisualizer m_visualizer;
- public GameWindow()
- {
+public class GameWindow extends JInternalFrame {
+ private final GameVisualizer visualizer;
+ public GameWindow() {
super("Игровое поле", true, true, true, true);
- m_visualizer = new GameVisualizer();
+ visualizer = new GameVisualizer();
JPanel panel = new JPanel(new BorderLayout());
- panel.add(m_visualizer, BorderLayout.CENTER);
+
+ panel.add(visualizer, BorderLayout.CENTER);
getContentPane().add(panel);
pack();
}
diff --git a/robots/src/gui/LogWindow.java b/src/main/java/org/robots/gui/LogWindow.java
similarity index 50%
rename from robots/src/gui/LogWindow.java
rename to src/main/java/org/robots/gui/LogWindow.java
index 723d3e2fc..c0061db96 100644
--- a/robots/src/gui/LogWindow.java
+++ b/src/main/java/org/robots/gui/LogWindow.java
@@ -1,4 +1,4 @@
-package gui;
+package org.robots.gui;
import java.awt.BorderLayout;
import java.awt.EventQueue;
@@ -7,39 +7,38 @@
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
-import log.LogChangeListener;
-import log.LogEntry;
-import log.LogWindowSource;
+import org.robots.log.LogChangeListener;
+import org.robots.log.LogEntry;
+import org.robots.log.LogWindowSource;
-public class LogWindow extends JInternalFrame implements LogChangeListener
-{
- private LogWindowSource m_logSource;
- private TextArea m_logContent;
+public class LogWindow extends JInternalFrame implements LogChangeListener {
+ private LogWindowSource logSource;
+ private TextArea logContent;
- public LogWindow(LogWindowSource logSource)
- {
+ public LogWindow(LogWindowSource logSource) {
super("Протокол работы", true, true, true, true);
- m_logSource = logSource;
- m_logSource.registerListener(this);
- m_logContent = new TextArea("");
- m_logContent.setSize(200, 500);
+
+ this.logSource = logSource;
+ this.logSource.registerListener(this);
+ this.logContent = new TextArea("");
+ this.logContent.setSize(200, 500);
JPanel panel = new JPanel(new BorderLayout());
- panel.add(m_logContent, BorderLayout.CENTER);
+ panel.add(logContent, BorderLayout.CENTER);
getContentPane().add(panel);
pack();
updateLogContent();
}
- private void updateLogContent()
- {
+ private void updateLogContent() {
StringBuilder content = new StringBuilder();
- for (LogEntry entry : m_logSource.all())
- {
+
+ for (LogEntry entry : logSource.all()) {
content.append(entry.getMessage()).append("\n");
}
- m_logContent.setText(content.toString());
- m_logContent.invalidate();
+
+ logContent.setText(content.toString());
+ logContent.invalidate();
}
@Override
diff --git a/src/main/java/org/robots/gui/MainApplicationFrame.java b/src/main/java/org/robots/gui/MainApplicationFrame.java
new file mode 100644
index 000000000..a90a447b3
--- /dev/null
+++ b/src/main/java/org/robots/gui/MainApplicationFrame.java
@@ -0,0 +1,102 @@
+package org.robots.gui;
+
+import java.awt.Dimension;
+import java.awt.Toolkit;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.*;
+
+import org.robots.log.Logger;
+
+/**
+ * Что требуется сделать:
+ * 1. Метод создания меню перегружен функционалом и трудно читается.
+ * Следует разделить его на серию более простых методов (или вообще выделить отдельный класс).
+ *
+ */
+public class MainApplicationFrame extends JFrame {
+ private final JDesktopPane desktopPane = new JDesktopPane();
+
+ 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;
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+
+ setBounds(inset, inset,
+ screenSize.width - inset * 2,
+ screenSize.height - inset * 2);
+
+ setContentPane(desktopPane);
+
+ logWindow = createLogWindow();
+ gameWindow = createGameWindow();
+ addWindow(logWindow, 10, 10, 300, 800);
+ addWindow(gameWindow, 300, 10, 400, 400);
+
+ setJMenuBar(new MenuBar(this));
+
+ addWindowListener(new WindowAdapter(){
+ @Override
+ public void windowClosing(WindowEvent event){
+ MainApplicationFrame.this.confirmWindowClose();
+ }
+ });
+
+ setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+ }
+
+ public void confirmWindowClose(){
+ if (JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите закрыть приложение?",
+ "Закрыть?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION){
+
+ logWindow.dispose();
+ gameWindow.dispose();
+ this.dispose();
+ }
+ }
+
+ protected GameWindow createGameWindow(){
+ GameWindow gameWindow = new GameWindow();
+
+ return gameWindow;
+ }
+
+ protected LogWindow createLogWindow() {
+
+ LogWindow logWindow = new LogWindow(Logger.getDefaultLogSource());
+
+
+ setMinimumSize(logWindow.getSize());
+ logWindow.pack();
+ Logger.debug("Протокол работает");
+
+ return logWindow;
+ }
+
+ protected void addWindow(JInternalFrame frame) {
+
+ desktopPane.add(frame);
+ frame.setVisible(true);
+ }
+
+ protected void addWindow(JInternalFrame frame, int xLocation, int yLocation, int width, int height){
+ frame.setSize(width, height);
+ frame.setLocation(xLocation, yLocation);
+ addWindow(frame);
+ }
+
+ public GameWindow getGameWindow(){
+ return gameWindow;
+ }
+
+ public LogWindow getLogWindow(){
+ return logWindow;
+ }
+
+}
diff --git a/src/main/java/org/robots/gui/MenuBar.java b/src/main/java/org/robots/gui/MenuBar.java
new file mode 100644
index 000000000..63462b4ef
--- /dev/null
+++ b/src/main/java/org/robots/gui/MenuBar.java
@@ -0,0 +1,89 @@
+package org.robots.gui;
+
+import javax.swing.*;
+
+import org.robots.log.Logger;
+
+import java.awt.event.*;
+
+public class MenuBar extends JMenuBar{
+ private final MainApplicationFrame parent;
+
+ public MenuBar(MainApplicationFrame parent) {
+ this.parent = parent;
+ this.add(initTestMenu());
+ this.add(initLookAndFeelMenu());
+ this.add(initExitMenu());
+ }
+
+ private JMenu createJMenu(String label, int mnemonic, String accessDescription){
+ JMenu menu = new JMenu(label);
+ menu.setMnemonic(mnemonic);
+ menu.getAccessibleContext().setAccessibleDescription(accessDescription);
+
+ return menu;
+ }
+
+ private JMenu initExitMenu(){
+ JMenu menu = createJMenu("Выход", KeyEvent.VK_E,
+ "Выход из приложения");
+
+ menu.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent event) {
+ parent.confirmWindowClose();
+ }
+ });
+
+ return menu;
+ }
+ private JMenuItem createJMenuItem(String label, KeyStroke key, ActionListener listener){
+ JMenuItem menuItem = new JMenuItem(label);
+ menuItem.setAccelerator(key);
+ menuItem.addActionListener(listener);
+
+ return menuItem;
+ }
+
+ private void setLookAndFeel(String className){
+ try{
+ UIManager.setLookAndFeel(className);
+ SwingUtilities.updateComponentTreeUI(parent);
+ }
+
+ catch (ClassNotFoundException | InstantiationException
+ | IllegalAccessException | UnsupportedLookAndFeelException exception) {
+ //ignore
+ }
+
+ finally{
+ parent.invalidate();
+ }
+
+ }
+
+ private JMenu initLookAndFeelMenu(){
+ JMenu menu = createJMenu("Режим отображения", KeyEvent.VK_V,
+ "Управление режимом отображения приложения");
+
+ menu.add(createJMenuItem("Системная схема", KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.ALT_MASK),
+ event -> setLookAndFeel(UIManager.getSystemLookAndFeelClassName())));
+
+ menu.add(createJMenuItem("Универсальная схема", KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.ALT_MASK),
+ event -> setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName())));
+
+ return menu;
+ }
+ private JMenu initTestMenu(){
+ JMenu menu = createJMenu("Тесты", KeyEvent.VK_T,
+ "Тестовые команды");
+
+ menu.add(createJMenuItem("Сообщение в лог", KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.ALT_MASK),
+ event -> Logger.debug("Новая строка")));
+
+ return menu;
+ }
+
+
+
+}
diff --git a/robots/src/log/LogChangeListener.java b/src/main/java/org/robots/log/LogChangeListener.java
similarity index 75%
rename from robots/src/log/LogChangeListener.java
rename to src/main/java/org/robots/log/LogChangeListener.java
index 0b0fb85dd..950a70cd5 100644
--- a/robots/src/log/LogChangeListener.java
+++ b/src/main/java/org/robots/log/LogChangeListener.java
@@ -1,4 +1,4 @@
-package log;
+package org.robots.log;
public interface LogChangeListener
{
diff --git a/src/main/java/org/robots/log/LogEntry.java b/src/main/java/org/robots/log/LogEntry.java
new file mode 100644
index 000000000..f5cfbb8ab
--- /dev/null
+++ b/src/main/java/org/robots/log/LogEntry.java
@@ -0,0 +1,22 @@
+package org.robots.log;
+
+public class LogEntry {
+ private LogLevel logLevel;
+ private String strMessage;
+
+ public LogEntry(LogLevel logLevel, String strMessage) {
+ this.strMessage = strMessage;
+ this.logLevel = logLevel;
+ }
+
+ public String getMessage()
+ {
+ return strMessage;
+ }
+
+ public LogLevel getLevel()
+ {
+ return logLevel;
+ }
+}
+
diff --git a/robots/src/log/LogLevel.java b/src/main/java/org/robots/log/LogLevel.java
similarity index 59%
rename from robots/src/log/LogLevel.java
rename to src/main/java/org/robots/log/LogLevel.java
index 582d010cc..1f175f594 100644
--- a/robots/src/log/LogLevel.java
+++ b/src/main/java/org/robots/log/LogLevel.java
@@ -1,7 +1,6 @@
-package log;
+package org.robots.log;
-public enum LogLevel
-{
+public enum LogLevel {
Trace(0),
Debug(1),
Info(2),
@@ -9,16 +8,16 @@ public enum LogLevel
Error(4),
Fatal(5);
- private int m_iLevel;
+ private int iLevel;
private LogLevel(int iLevel)
{
- m_iLevel = iLevel;
+ this.iLevel = iLevel;
}
public int level()
{
- return m_iLevel;
+ return iLevel;
}
}
diff --git a/src/main/java/org/robots/log/LogWindowSource.java b/src/main/java/org/robots/log/LogWindowSource.java
new file mode 100644
index 000000000..b08da4f11
--- /dev/null
+++ b/src/main/java/org/robots/log/LogWindowSource.java
@@ -0,0 +1,82 @@
+package org.robots.log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Что починить:
+ * 1. Этот класс порождает утечку ресурсов (связанные слушатели оказываются
+ * удерживаемыми в памяти)
+ * 2. Этот класс хранит активные сообщения лога, но в такой реализации он
+ * их лишь накапливает. Надо же, чтобы количество сообщений в логе было ограничено
+ * величиной m_iQueueLength (т.е. реально нужна очередь сообщений
+ * ограниченного размера)
+ */
+public class LogWindowSource {
+ private int iQueueLength;
+
+ private ArrayList messages;
+ private final ArrayList listeners;
+ private volatile LogChangeListener[] activeListeners;
+
+ public LogWindowSource(int iQueueLength){
+ this.iQueueLength = iQueueLength;
+ messages = new ArrayList(iQueueLength);
+ listeners = new ArrayList();
+ }
+
+ public void registerListener(LogChangeListener listener) {
+
+ synchronized(listeners) {
+ listeners.add(listener);
+ activeListeners = null;
+ }
+ }
+
+ public void unregisterListener(LogChangeListener listener) {
+
+ synchronized(listeners) {
+ listeners.remove(listener);
+ activeListeners = null;
+ }
+ }
+
+ public void append(LogLevel logLevel, String strMessage) {
+ LogEntry entry = new LogEntry(logLevel, strMessage);
+ messages.add(entry);
+ LogChangeListener [] activeListeners = this.activeListeners;
+ if (activeListeners == null) {
+
+ synchronized (listeners) {
+
+ if (this.activeListeners == null)
+ {
+ activeListeners = listeners.toArray(new LogChangeListener [0]);
+ this.activeListeners = activeListeners;
+ }
+ }
+ }
+ for (LogChangeListener listener : activeListeners) {
+ listener.onLogChanged();
+ }
+ }
+
+ public int size()
+ {
+ return messages.size();
+ }
+
+ public Iterable range(int startFrom, int count) {
+ if (startFrom < 0 || startFrom >= messages.size())
+ {
+ return Collections.emptyList();
+ }
+ int indexTo = Math.min(startFrom + count, messages.size());
+ return messages.subList(startFrom, indexTo);
+ }
+
+ public Iterable all()
+ {
+ return messages;
+ }
+}
diff --git a/robots/src/log/Logger.java b/src/main/java/org/robots/log/Logger.java
similarity index 86%
rename from robots/src/log/Logger.java
rename to src/main/java/org/robots/log/Logger.java
index b008a5d01..5294bf8d6 100644
--- a/robots/src/log/Logger.java
+++ b/src/main/java/org/robots/log/Logger.java
@@ -1,14 +1,12 @@
-package log;
+package org.robots.log;
-public final class Logger
-{
+public final class Logger {
private static final LogWindowSource defaultLogSource;
static {
defaultLogSource = new LogWindowSource(100);
}
- private Logger()
- {
+ private Logger() {
}
public static void debug(String strMessage)