m_commands;
-
- private final MessageDialogs m_messageDialogs;
-
- private final Listener m_listener;
-
- private String m_lastUpdateOptionsCommand;
-
- private void clearCommand()
- {
- m_listener.actionClearAnalyzeCommand();
- m_autoRun.setSelected(false);
- }
-
- private void comboBoxChanged()
- {
- Object item = m_comboBoxHistory.getSelectedItem();
- if (item == null)
- {
- m_list.clearSelection();
- return;
- }
- String label = item.toString();
- updateOptions(label);
- String selectedValue = (String)m_list.getSelectedValue();
- if (selectedValue != null && ! selectedValue.equals(label))
- m_list.clearSelection();
- }
-
- private JPanel createButtons()
- {
- JPanel innerPanel = new JPanel(new GridLayout(1, 0, 5, 0));
- m_runButton = new JButton("Run");
- m_runButton.setToolTipText("Run Command");
- m_runButton.setActionCommand("run");
- m_runButton.addActionListener(this);
- m_runButton.setMnemonic(KeyEvent.VK_R);
- m_runButton.setEnabled(false);
- GuiUtil.setMacBevelButton(m_runButton);
- innerPanel.add(m_runButton);
- m_clearButton = new JButton("Clear");
- m_clearButton.setToolTipText(("Clear command"));
- m_clearButton.setActionCommand("clear");
- m_clearButton.addActionListener(this);
- m_clearButton.setMnemonic(KeyEvent.VK_C);
- GuiUtil.setMacBevelButton(m_clearButton);
- innerPanel.add(m_clearButton);
- JPanel outerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
- outerPanel.add(innerPanel);
- return outerPanel;
- }
-
- private JComponent createColorPanel()
- {
- m_colorBox = Box.createVerticalBox();
- ButtonGroup group = new ButtonGroup();
- m_black = new JRadioButton("Black");
- m_black.setToolTipText("Black");
- m_black.setEnabled(false);
- group.add(m_black);
- m_colorBox.add(m_black);
- m_white = new JRadioButton("White");
- m_white.setToolTipText("White");
- m_white.setEnabled(false);
- group.add(m_white);
- m_colorBox.add(m_white);
- return m_colorBox;
- }
-
- private JPanel createCommandPanel()
- {
- JPanel panel = new JPanel(new BorderLayout());
- m_list = new JList();
- m_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- m_list.setVisibleRowCount(25);
- m_list.addMouseListener(new MouseAdapter() {
- public void mouseClicked(MouseEvent e) {
- int modifiers = e.getModifiers();
- int mask = ActionEvent.ALT_MASK;
- if (e.getClickCount() == 2
- || ((modifiers & mask) != 0))
- {
- //int index =
- // m_list.locationToIndex(event.getPoint());
- runCommand();
- }
- }
- });
- m_list.addFocusListener(new FocusAdapter() {
- public void focusGained(FocusEvent e) {
- int index = getSelectedCommand();
- if (index >= 0)
- m_list.setSelectedIndex(index);
- }
- });
- m_list.addListSelectionListener(this);
- JScrollPane scrollPane = new JScrollPane(m_list);
- if (Platform.isMac())
- // Default Apple L&F uses no border, but Quaqua 3.7.4 does
- scrollPane.setBorder(null);
- panel.add(scrollPane, BorderLayout.CENTER);
- panel.add(createLowerPanel(), BorderLayout.SOUTH);
- String[] labels = new String[m_commands.size()];
- for (int i = 0; i < m_commands.size(); ++i)
- labels[i] = m_commands.get(i).getLabel();
- m_list.setListData(labels);
- comboBoxChanged();
- loadRecent();
- return panel;
- }
-
- private JComponent createLowerPanel()
- {
- Box panel = Box.createVerticalBox();
- panel.add(GuiUtil.createFiller());
- m_comboBoxHistory = new JComboBox();
- panel.add(m_comboBoxHistory);
- Box lowerPanel = Box.createVerticalBox();
- lowerPanel.setBorder(GuiUtil.createEmptyBorder());
- panel.add(lowerPanel);
- Box optionsPanel = Box.createHorizontalBox();
- lowerPanel.add(optionsPanel);
- JPanel leftPanel = new JPanel();
- optionsPanel.add(leftPanel);
- Box leftBox = Box.createVerticalBox();
- leftPanel.add(leftBox);
- m_autoRun = new JCheckBox("Autorun");
- m_autoRun.addItemListener(new ItemListener() {
- public void itemStateChanged(ItemEvent e) {
- if (! m_autoRun.isSelected())
- m_listener.actionClearAnalyzeCommand();
- }
- });
- m_autoRun.setToolTipText("Autorun");
- m_autoRun.setEnabled(false);
- leftBox.add(m_autoRun);
- m_clearBoard = new JCheckBox("Clearboard");
- m_clearBoard.setToolTipText("Clearboard");
- m_clearBoard.setEnabled(false);
- leftBox.add(m_clearBoard);
- m_clearBoard.setSelected(true);
- m_reuseWindow = new JCheckBox("Reuse Text");
- m_reuseWindow.setToolTipText("Reuse text window");
- leftBox.add(m_reuseWindow);
- JPanel rightPanel = new JPanel();
- rightPanel.add(createColorPanel());
- optionsPanel.add(rightPanel);
-
- // TODO: The following horizontal glue does not really work as expected
- // (tested on Linux/Sun Java 1.6.0_14) and the left two components in
- // the box are not aligned to the left.
- optionsPanel.add(Box.createHorizontalGlue());
-
- // TODO: If GTK Looks L&F is used on Linux/Sun Java 1.6.0_14 or OpenJDK
- // 6b14-1.4.1-0ubuntu11, then the text of the checkbox items can be
- // truncated a bit on the left (wrong minimum size calculation?). The
- // two fillers are a workaround for this.
- optionsPanel.add(GuiUtil.createFiller());
- optionsPanel.add(GuiUtil.createFiller());
-
- lowerPanel.add(createButtons());
- m_comboBoxHistory.addActionListener(this);
- return panel;
- }
-
- private String getComboBoxItem(int i)
- {
- return m_comboBoxHistory.getItemAt(i).toString();
- }
-
- private int getComboBoxItemCount()
- {
- return m_comboBoxHistory.getItemCount();
- }
-
- private int getCommandIndex(String label)
- {
- for (int i = 0; i < m_commands.size(); ++i)
- if (m_commands.get(i).getLabel().equals(label))
- return i;
- return -1;
- }
-
- private int getSelectedCommand()
- {
- Object item = m_comboBoxHistory.getSelectedItem();
- if (item == null)
- return -1;
- return getCommandIndex(item.toString());
- }
-
- private void insertComboBoxItem(String label, int index)
- {
- m_comboBoxHistory.insertItemAt(GuiUtil.createComboBoxItem(label),
- index);
- }
-
- private void loadRecent()
- {
- m_comboBoxHistory.removeAllItems();
- m_fullRecentList =
- PrefUtil.getList("net/sf/hexgui/gui/analyzedialog/recentcommands");
- for (int i = 0; i < m_fullRecentList.size(); ++i)
- {
- String name = m_fullRecentList.get(i);
- if (getCommandIndex(name) >= 0)
- m_comboBoxHistory.addItem(GuiUtil.createComboBoxItem(name));
- if (m_comboBoxHistory.getItemCount() > 20)
- break;
- }
- int index = getSelectedCommand();
- if (index >= 0)
- selectCommand(index);
- m_firstIsTemp = false;
- }
-
- private void runCommand()
- {
- // if (m_gtp.isCommandInProgress())
- // {
- // showError("MSG_ANALYZE_CANNOT_EXECUTE",
- // "MSG_ANALYZE_CANNOT_EXECUTE_2",
- // false);
- // return;
- // }
- int index = getSelectedCommand();
- if (index < 0)
- {
- // String name = m_gtp.getName();
- // if (name == null)
- // showError("MSG_ANALYZE_NOT_SUPPORTED",
- // "MSG_ANALYZE_NOT_SUPPORTED_2", false);
- // else
- // showError("MSG_ANALYZE_NOT_SUPPORTED",
- // "MSG_ANALYZE_NOT_SUPPORTED_3", false, name);
- return;
- }
- updateRecent(index);
- AnalyzeCommand command = new AnalyzeCommand(m_commands.get(index));
- if (command.needsColorArg())
- command.setColorArg(getSelectedColor());
- String label = command.getResultTitle();
- if (command.needsStringArg())
- {
- String stringArg =
- JOptionPane.showInputDialog(this, label,
- "TIT_INPUT",
- JOptionPane.PLAIN_MESSAGE);
- if (stringArg == null)
- return;
- command.setStringArg(stringArg);
- }
- if (command.needsOptStringArg())
- {
- }
- if (command.getType() == AnalyzeType.EPLIST)
- {
- }
- if (command.needsFileArg())
- {
- File fileArg = FileDialogs.showSelectFile(this, label);
- if (fileArg == null)
- return;
- command.setFileArg(fileArg);
- }
- if (command.needsFileOpenArg())
- {
- File fileArg = FileDialogs.showOpen(this, label);
- if (fileArg == null)
- return;
- command.setFileOpenArg(fileArg);
- }
- if (command.needsFileSaveArg())
- {
- File fileArg = FileDialogs.showSave(this, label, m_messageDialogs);
- if (fileArg == null)
- return;
- command.setFileSaveArg(fileArg);
- }
- if (command.needsColorArg())
- command.setColorArg(getSelectedColor());
- boolean autoRun = m_autoRun.isEnabled() && m_autoRun.isSelected();
- boolean clearBoard =
- ! m_clearBoard.isEnabled() || m_clearBoard.isSelected();
- boolean reuseWindow =
- m_reuseWindow.isEnabled() && m_reuseWindow.isSelected();
- m_listener.actionSetAnalyzeCommand(command, autoRun, clearBoard,
- false, reuseWindow);
- }
-
- private void selectCommand(int index)
- {
- String label = m_commands.get(index).getLabel();
- updateOptions(label);
- m_comboBoxHistory.removeActionListener(this);
- if (m_firstIsTemp && getComboBoxItemCount() > 0)
- m_comboBoxHistory.removeItemAt(0);
- if (getComboBoxItemCount() == 0 || ! getComboBoxItem(0).equals(label))
- {
- insertComboBoxItem(label, 0);
- m_firstIsTemp = true;
- m_comboBoxHistory.setSelectedIndex(0);
- }
- m_comboBoxHistory.addActionListener(this);
- }
-
- private void selectColor()
- {
- if (m_selectedColor == BLACK)
- m_black.setSelected(true);
- else if (m_selectedColor == WHITE)
- m_white.setSelected(true);
- }
-
- private void showError(String mainMessage, String optionalMessage,
- boolean isCritical)
- {
- ShowError.msg(this, mainMessage);
- }
-
- private void showError(String mainMessage, String optionalMessage,
- boolean isCritical, Object... args)
- {
- ShowError.msg(this, mainMessage);
- }
-
- private void updateOptions(String label)
- {
- if (label.equals(m_lastUpdateOptionsCommand))
- return;
- m_lastUpdateOptionsCommand = label;
- int index = getCommandIndex(label);
- if (index < 0)
- return;
- AnalyzeCommand command =
- new AnalyzeCommand(m_commands.get(index));
- boolean needsColorArg = command.needsColorArg();
- m_black.setEnabled(needsColorArg);
- m_white.setEnabled(needsColorArg);
- m_autoRun.setEnabled(command.getType() != AnalyzeType.PARAM);
- m_autoRun.setSelected(false);
- m_clearBoard.setEnabled(command.getType() != AnalyzeType.PARAM);
- m_runButton.setEnabled(true);
- }
-
- private void updateRecent(int index)
- {
- String label = m_commands.get(index).getLabel();
- insertComboBoxItem(label, 0);
- m_comboBoxHistory.setSelectedIndex(0);
- for (int i = 1; i < getComboBoxItemCount(); ++i)
- if (getComboBoxItem(i).equals(label))
- m_comboBoxHistory.removeItemAt(i);
- m_firstIsTemp = false;
- }
-}
diff --git a/src/hexgui/gui/BoardDrawerBase.java b/src/hexgui/gui/BoardDrawerBase.java
deleted file mode 100644
index f40f823..0000000
--- a/src/hexgui/gui/BoardDrawerBase.java
+++ /dev/null
@@ -1,376 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.gui;
-
-import hexgui.util.Pair;
-import hexgui.util.RadialGradientPaint;
-import hexgui.hex.HexColor;
-import hexgui.hex.HexPoint;
-
-import java.util.Vector;
-import javax.swing.*;
-
-import java.awt.Point;
-import java.awt.Polygon;
-import java.awt.Color;
-import java.awt.Graphics2D;
-import java.awt.AlphaComposite;
-import java.awt.Image;
-import java.awt.FontMetrics;
-import java.awt.Font;
-import java.awt.RenderingHints;
-import java.awt.Graphics;
-
-import java.awt.event.*;
-import java.net.URL;
-
-//----------------------------------------------------------------------------
-
-/** Base class for board drawing.
-
- Board drawers are responsible for drawing the background,
- labels, field outlines, and stone shadows. In addition, they
- are also responsible for determining the actual position of each
- field in the window. Field contents (i.e. stones, markers,
- numerical values, etc) are not drawn, they are drawn with the
- GuiField class.
-
-
Board sizes supported are m x n where
- m and n range from 1 to 26. By
- default, black connects top and bottom and should be labeled with
- letters. White connects left and right and should be labeled with
- numbers.
-*/
-public abstract class BoardDrawerBase
-{
- public BoardDrawerBase()
- {
- m_background = null;
- m_aspect_ratio = 1.0;
- }
-
- /** Loads the image in filename and sets it as the
- background. If filename does not exist no
- background image is displayed. Image will be scaled to fit
- the window.
- @param filename filename of the image to use as a background.
- */
- public void loadBackground(String filename)
- {
- ClassLoader classLoader = getClass().getClassLoader();
- URL url = classLoader.getResource(filename);
- if (url == null) {
- System.out.println("loadBackground: could not load '" +
- filename + "'!");
- m_background = null;
- } else {
- m_background = new ImageIcon(url).getImage();
- }
- }
-
- /** Gets the field containing the specified point.
- NOTE: uses the position of fields from the last call to draw().
- Also assumes the set of fields given are the same as those in the
- last call to draw().
- @param p the point
- @param field the set of fields to search through.
- @return the field in the set that p is in or null if
- p is not in any field.
- */
- public GuiField getFieldContaining(Point p, GuiField field[])
- {
- if (m_outline == null)
- return null;
- for (int x=0; x> arrows)
- {
- m_width = w;
- m_height = h;
-
- m_bwidth = bw;
- m_bheight = bh;
-
- m_alphaontop = alphaontop;
-
- computeFieldPlacement();
- m_outline = calcCellOutlines(field);
-
- setAntiAliasing(g);
- drawBackground(g);
- drawCells(g, field);
- drawLabels(g, alphaontop);
- drawShadows(g, field);
- drawFields(g, field);
- drawAlpha(g, field);
-
- drawArrows(g, arrows);
- }
-
- //------------------------------------------------------------
-
- protected abstract Point getLocation(HexPoint p);
-
- /** Calculates the width of a field given the dimensions of the
- window and board.
- @param w width of window
- @param h height of window
- @param bw width of board
- @param bh height of board
- */
- protected abstract int calcFieldWidth(int w, int h, int bw, int bh);
-
- /** Calculates the height of a field given the dimensions of the
- window and board.
- @see calcFieldWidth
- */
- protected abstract int calcFieldHeight(int w, int h, int bw, int bh);
-
-
- protected abstract int calcStepSize();
-
- /** Calculates the width of the board in pixels.
- @requires calcFieldWidth and calcFieldHeight to have been called.
- */
- protected abstract int calcBoardWidth();
-
- /** Calculates the height of the board in pixels.
- @requires calcFieldWidth and calcFieldHeight to have been called.
- */
- protected abstract int calcBoardHeight();
-
- /** Performs any necessary initializations for drawing the
- outlines of the fields.
- @param the fields it will need to draw
- */
- protected abstract Polygon[] calcCellOutlines(GuiField field[]);
-
- /** Draws the outlines of the given fields.
- @param g graphics context to draw to.
- @param field the list of fields to draw.
- */
- protected void drawCells(Graphics g, GuiField field[])
- {
- g.setColor(Color.black);
- for (int i=0; i= (int)(m_fieldWidth/m_aspect_ratio)) {
- m_fieldHeight = (int)(m_fieldWidth/m_aspect_ratio);
- } else {
- m_fieldWidth = (int)(m_fieldHeight*m_aspect_ratio);
- }
-
- // If field dimensions are not even then the inner cell lines
- // on the board can be doubled up.
- // FIXME: lines still get doubled up...why?
- if ((m_fieldWidth & 1) != 0) m_fieldWidth--;
- if ((m_fieldHeight & 1) != 0) m_fieldHeight--;
-
- m_fieldRadius = (m_fieldWidth < m_fieldHeight) ?
- m_fieldWidth : m_fieldHeight;
-
- m_step = calcStepSize();
-
- int bw = calcBoardWidth();
- int bh = calcBoardHeight();
-
- // add a half cell's worth of empty space
- int extra = (m_width - (bw + 3*m_fieldWidth));
- m_marginX = extra/2 + 3*m_fieldWidth/2;
-
- m_marginY = (m_height - bh)/2 + m_fieldHeight/2;
- }
-
- //------------------------------------------------------------
-
- protected int getShadowOffset()
- {
- return (m_fieldRadius - 2*GuiField.getStoneMargin(m_fieldRadius)) / 12;
- }
-
- protected void drawBackground(Graphics g)
- {
- if (m_background != null)
- g.drawImage(m_background, 0, 0, m_width, m_height, null);
- }
-
- protected void drawLabel(Graphics g, Point p, String string, int xoff)
- {
- double size = Math.min(m_fieldWidth, m_fieldHeight) * 0.4;
- Font f = g.getFont();
- Font f2 = f.deriveFont((float)size);
-
- FontMetrics fm = g.getFontMetrics(f2);
- int width = fm.stringWidth(string);
- int height = fm.getAscent();
-
- g.setFont(f2);
- int x = width/2;
- int y = height/2;
- g.drawString(string, p.x + xoff - x, p.y + y);
- g.setFont(f);
- }
-
- protected abstract void drawLabels(Graphics g, boolean alphatop);
-
- protected void drawShadows(Graphics graphics, GuiField[] field)
- {
- if (m_fieldRadius <= 5)
- return;
- Graphics2D graphics2D =
- graphics instanceof Graphics2D ? (Graphics2D)graphics : null;
- if (graphics2D == null)
- return;
- graphics2D.setComposite(COMPOSITE_3);
- int size = m_fieldRadius - 2 * GuiField.getStoneMargin(m_fieldRadius);
- int offset = getShadowOffset();
- for (int pos = 0; pos < field.length; pos++) {
- if (field[pos].getColor() == HexColor.EMPTY)
- continue;
- Point location = getLocation(field[pos].getPoint());
- graphics.setColor(Color.black);
- graphics.fillOval(location.x - size / 2 + offset,
- location.y - size / 2 + offset,
- size, size);
- }
- graphics.setPaintMode();
- }
-
- protected void drawFields(Graphics g, GuiField field[])
- {
- for (int x=0; x> arrows)
- {
- if (g instanceof Graphics2D) {
- Graphics2D g2d = (Graphics2D)g;
- g2d.setColor(Color.BLUE);
- for (int i=0; i(x,y). Coordinates increase to the
- right and down, with the top left of the board having
- coordinates (0,0). Negative values are acceptable.
- @param x the x coordinate of the field.
- @param y the y coordinate of the field.
- @return the center of the field at (x,y).
- */
- protected Point getLocation(int x, int y)
- {
- // yoffset will be positive when bwidth > bheight (to push the
- // board down) and negative when bwidth < bheight (to lift it
- // up) because the a1 square (0,0) will not be
- // in the center of the vertical space occupied by the board.
- int yoffset = (m_bwidth - m_bheight)*m_fieldHeight/2;
-
- Point ret = new Point();
- ret.x = m_marginX + (y + x)*m_step;
- ret.y = m_marginY + yoffset + (m_bheight/2)*m_fieldHeight
- + (y - x)*m_fieldHeight/2;
- return ret;
- }
-
- /** Returns the location of the field with HexPoint pos. */
- protected Point getLocation(HexPoint pos)
- {
- if (pos == HexPoint.EAST) {
- return getLocation(m_bwidth+1, m_bheight/2-1);
- } else if (pos == HexPoint.WEST) {
- return getLocation(-2, m_bheight/2+1);
- } else if (pos == HexPoint.SOUTH) {
- return getLocation(m_bwidth/2-1, m_bheight+1);
- } else if (pos == HexPoint.NORTH) {
- return getLocation(m_bwidth/2+1, -2);
- }
- return getLocation(pos.x, pos.y);
- }
-
- protected int calcFieldWidth(int w, int h, int bw, int bh)
- {
- return w / (bw + (bh-1)/2 + 2);
- }
-
- protected int calcFieldHeight(int w, int h, int bw, int bh)
- {
- return h / (bh + 2);
- }
-
- protected int calcStepSize()
- {
- return m_fieldWidth/4 + m_fieldWidth/2;
- }
- protected int calcBoardWidth()
- {
- return (m_bwidth+m_bheight-1)*m_step;
- }
-
- protected int calcBoardHeight()
- {
- return m_bheight*m_fieldHeight
- + (m_bwidth - m_bheight)*m_fieldHeight/2;
- }
-
- protected Polygon[] calcCellOutlines(GuiField field[])
- {
- Polygon outline[] = new Polygon[field.length];
- for (int x = 0; x < outline.length; x++) {
- Point p = getLocation(field[x].getPoint());
- outline[x] = Hexagon.createHorizontalHexagon(p,
- m_fieldWidth,
- m_fieldHeight);
-// System.out.println("-----");
-// System.out.println(field[x].getPoint().toString());
-// Polygon poly = outline[x];
-// for (int j=0; j<6; j++) {
-// System.out.print("(" + poly.xpoints[j] +
-// "," + poly.ypoints[j] +
-// ") ");
-// }
-// System.out.println("");
- }
- return outline;
- }
-
- protected void drawLabels(Graphics g, boolean alphatop)
- {
- int xoffset;
- String string;
- g.setColor(Color.black);
-
- xoffset = 0;
- for (int x=0; x(x,y). Coordinates increase to the
- right and down, with the top left of the board having
- coordinates (0,0). Negative values are acceptable.
- @param x the x coordinate of the field.
- @param y the y coordinate of the field.
- @return the center of the field at (x,y).
- */
- protected Point getLocation(int x, int y)
- {
- Point ret = new Point();
- ret.x = m_marginX + y*m_fieldWidth/2 + x*m_fieldWidth;
- ret.y = m_marginY + y*m_step;
- return ret;
- }
-
- /** Returns the location of the field with HexPoint pos. */
- protected Point getLocation(HexPoint pos)
- {
- if (pos == HexPoint.EAST) {
- return getLocation(m_bwidth+1, m_bheight/2-1);
- } else if (pos == HexPoint.WEST) {
- return getLocation(-2, m_bheight/2+1);
- } else if (pos == HexPoint.SOUTH) {
- return getLocation(m_bwidth/2-1, m_bheight+1);
- } else if (pos == HexPoint.NORTH) {
- return getLocation(m_bwidth/2+1, -2);
- }
- return getLocation(pos.x, pos.y);
- }
-
- protected int calcFieldWidth(int w, int h, int bw, int bh)
- {
- return w / (bw + (bh-1)/2 + 2);
- }
-
- protected int calcFieldHeight(int w, int h, int bw, int bh)
- {
- return h / ((bh+1)/2 + (bh/4) + 4);
- }
-
- protected int calcStepSize()
- {
- return m_fieldHeight/4 + m_fieldHeight/2;
-
- }
- protected int calcBoardWidth()
- {
- return m_bwidth*m_fieldWidth + (m_bheight-1)*m_fieldWidth/2;
- }
-
- protected int calcBoardHeight()
- {
- return m_fieldHeight*(m_bheight+1)/2
- + m_fieldHeight*m_bheight/4;
- }
-
- protected Polygon[] calcCellOutlines(GuiField field[])
- {
- Polygon outline[] = new Polygon[field.length];
- for (int x = 0; x < outline.length; x++) {
- Point p = getLocation(field[x].getPoint());
- outline[x] = Hexagon.createVerticalHexagon(p,
- m_fieldWidth,
- m_fieldHeight);
- }
- return outline;
- }
-
- protected void drawLabels(Graphics g, boolean alphatop)
- {
- String string;
- int xoffset,yoffset;
- g.setColor(Color.black);
-
- xoffset = m_fieldWidth/2;
- yoffset = 1;
- for (int x=0; x(x,y). Coordinates increase to the
- right and down, with the top left of the board having
- coordinates (0,0). Negative values are acceptable.
- @param x the x coordinate of the field.
- @param y the y coordinate of the field.
- @return the center of the field at (x,y).
- */
- protected Point getLocation(int x, int y)
- {
- Point ret = new Point();
- ret.x = m_marginX + y*m_fieldWidth/2 + x*m_fieldWidth;
- ret.y = m_marginY + (m_bheight-1-y)*m_step;
- return ret;
- }
-
- /** Returns the location of the field with HexPoint pos. */
- protected Point getLocation(HexPoint pos)
- {
- if (pos == HexPoint.EAST) {
- return getLocation(m_bwidth+1, m_bheight/2-1);
- } else if (pos == HexPoint.WEST) {
- return getLocation(-2, m_bheight/2+1);
- } else if (pos == HexPoint.SOUTH) {
- return getLocation(m_bwidth/2-1, m_bheight+1);
- } else if (pos == HexPoint.NORTH) {
- return getLocation(m_bwidth/2+1, -2);
- }
- return getLocation(pos.x, pos.y);
- }
-
- protected int calcFieldWidth(int w, int h, int bw, int bh)
- {
- return w / (bw + (bh-1)/2 + 2);
- }
-
- protected int calcFieldHeight(int w, int h, int bw, int bh)
- {
- return h / ((bh+1)/2 + (bh/4) + 4);
- }
-
- protected int calcStepSize()
- {
- return m_fieldHeight/4 + m_fieldHeight/2;
-
- }
- protected int calcBoardWidth()
- {
- return m_bwidth*m_fieldWidth + (m_bheight-1)*m_fieldWidth/2;
- }
-
- protected int calcBoardHeight()
- {
- return m_fieldHeight*(m_bheight+1)/2
- + m_fieldHeight*m_bheight/4;
- }
-
- protected Polygon[] calcCellOutlines(GuiField field[])
- {
- Polygon outline[] = new Polygon[field.length];
- for (int x = 0; x < outline.length; x++) {
- Point p = getLocation(field[x].getPoint());
- outline[x] = Hexagon.createVerticalHexagon(p,
- m_fieldWidth,
- m_fieldHeight);
- }
- return outline;
- }
-
- protected void drawLabels(Graphics g, boolean alphatop)
- {
- String string;
- int xoffset,yoffset;
- g.setColor(Color.black);
-
- xoffset = m_fieldWidth/2;
- yoffset = 1;
- for (int x=0; x(x,y). Coordinates increase to the
- right and down, with the top left of the board having
- coordinates (0,0). Negative values are acceptable.
- @param x the x coordinate of the field.
- @param y the y coordinate of the field.
- @return the center of the field at (x,y).
- */
- protected Point getLocation(int x, int y)
- {
- Point ret = new Point();
- int center = m_marginX + m_bwidth*m_fieldWidth / 2;
- ret.x = center - y*m_fieldWidth/2 + x*m_fieldWidth;
- ret.y = m_marginY + y*m_step;
- return ret;
- }
-
- /** Returns the location of the field with HexPoint pos. */
- protected Point getLocation(HexPoint pos)
- {
- if (pos == HexPoint.EAST) {
- return getLocation(m_bheight/2+2, m_bheight/2);
- } else if (pos == HexPoint.WEST) {
- return getLocation(-2, m_bheight/2);
- } else if (pos == HexPoint.SOUTH) {
- return getLocation(m_bwidth/2+1, m_bheight+1);
- }
- return getLocation(pos.x, pos.y);
- }
-
- protected int calcFieldWidth(int w, int h, int bw, int bh)
- {
- return w / (bw + 3); // width + 2 cells for labels + 1 for spacing
- }
-
- protected int calcFieldHeight(int w, int h, int bw, int bh)
- {
- // each row takes 3/4 of the height of hex
- // need 2 extra rows for labels + 1 row of spacing
- return h / ( 3*bh/4 + 3);
- }
-
- protected int calcStepSize()
- {
- return m_fieldHeight/4 + m_fieldHeight/2;
-
- }
- protected int calcBoardWidth()
- {
- return m_bwidth*m_fieldWidth;
- }
-
- protected int calcBoardHeight()
- {
- // return m_fieldHeight*(m_bheight+1)/2
- // + m_fieldHeight*m_bheight/4;
- return 3*m_fieldHeight/4*(m_bheight+2);
- }
-
- protected Polygon[] calcCellOutlines(GuiField field[])
- {
- Polygon outline[] = new Polygon[field.length];
- for (int x = 0; x < outline.length; x++) {
- Point p = getLocation(field[x].getPoint());
- outline[x] = Hexagon.createVerticalHexagon(p,
- m_fieldWidth,
- m_fieldHeight);
- }
- return outline;
- }
-
- protected void drawLabels(Graphics g, boolean alphatop)
- {
- String string;
- int xoffset,yoffset;
- g.setColor(Color.black);
-
- xoffset = m_fieldWidth/2;
- yoffset = 1;
- for (int x=0; x programs)
- {
- super(owner, true);
- setTitle(title);
-
- m_programs = programs;
-
- // create gui
- JEditorPane info = new JEditorPane();
- info.setEditable(false);
- info.setEditorKit(new HTMLEditorKit());
- info.setText("Select program from list below.");
- add(info, BorderLayout.NORTH);
- add(createProgramPanel(), BorderLayout.CENTER);
- add(createButtonPanel(), BorderLayout.SOUTH);
-
- pack();
-
- setResizable(false);
- }
-
- public void actionPerformed(ActionEvent e)
- {
- String cmd = e.getActionCommand();
- if (cmd.equals("OK")) {
-
- m_program = m_programs.get(m_list.getSelectedIndex());
-
- // set the program
- setVisible(false);
-
- } else if (cmd.equals("Cancel")) {
- setVisible(false);
- }
- }
-
- public Program getProgram()
- {
- return m_program;
- }
-
- private JPanel createProgramPanel()
- {
- JPanel panel = new JPanel();
-
- m_list = new JList(m_programs);
- m_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- m_list.setVisibleRowCount(10);
- m_list.setSelectedIndex(0);
- m_list.setPreferredSize(new Dimension(200, 250));
-
- JScrollPane sc = new JScrollPane(m_list);
- sc.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
-
- panel.add(sc);
-
- return panel;
- }
-
- private JPanel createButtonPanel()
- {
- JPanel panel = new JPanel();
-
- JButton button = new JButton(" OK ");
- button.addActionListener(this);
- button.setActionCommand("OK");
- panel.add(button);
-
- button = new JButton("Cancel");
- button.addActionListener(this);
- button.setActionCommand("Cancel");
- panel.add(button);
-
- return panel;
- }
-
- JList m_list;
-
- Vector m_programs;
- Program m_program;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/gui/Comment.java b/src/hexgui/gui/Comment.java
deleted file mode 100644
index 3d37449..0000000
--- a/src/hexgui/gui/Comment.java
+++ /dev/null
@@ -1,73 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.gui;
-
-import java.io.*;
-import java.util.*;
-import javax.swing.*;
-import javax.swing.event.DocumentListener;
-import javax.swing.event.DocumentEvent;
-import javax.swing.border.EtchedBorder;
-import java.awt.*;
-import java.awt.event.*;
-
-/** Displays comment for current node. */
-public class Comment
- extends JScrollPane
- implements DocumentListener
-{
-
- public interface Listener
- {
- public void commentChanged(String msg);
- }
-
- public Comment(Listener listener)
- {
- m_listener = listener;
- m_textPane = new JTextArea();
- m_textPane.setFont(MONOSPACED_FONT);
- m_textPane.setLineWrap(true);
- m_textPane.setWrapStyleWord(true);
- setViewportView(m_textPane);
- setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
- m_textPane.getDocument().addDocumentListener(this);
- //setPreferredSize(new Dimension(200, 400));
- }
-
- public void setText(String text)
- {
- m_textPane.setText(text);
- m_textPane.getCaret().setDot(0);
- }
-
- public void changedUpdate(DocumentEvent e)
- {
- notifyChanged();
- }
-
- public void removeUpdate(DocumentEvent e)
- {
- notifyChanged();
- }
-
- public void insertUpdate(DocumentEvent e)
- {
- notifyChanged();
- }
-
- private void notifyChanged()
- {
- m_listener.commentChanged(m_textPane.getText());
- }
-
- JTextArea m_textPane;
-
- Listener m_listener;
-
- private static final Font MONOSPACED_FONT = Font.decode("Monospaced");
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/gui/EditProgramDialog.java b/src/hexgui/gui/EditProgramDialog.java
deleted file mode 100644
index 8445969..0000000
--- a/src/hexgui/gui/EditProgramDialog.java
+++ /dev/null
@@ -1,140 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.gui;
-
-import hexgui.util.SpringUtilities;
-import hexgui.gui.ShowError;
-import hexgui.gui.Program;
-
-import java.util.Vector;
-import javax.swing.*;
-import javax.swing.text.html.HTMLEditorKit;
-import java.awt.*;
-import java.awt.event.*;
-
-/** Dialog for adding/editing new programs. */
-public final class EditProgramDialog
- extends JDialog implements ActionListener
-{
-
- public EditProgramDialog(Frame owner, Program program,
- String title, boolean is_new)
- {
- super(owner, true);
- m_program = program;
-
- setTitle(title);
- init(is_new);
- }
-
- private void init(boolean is_new)
- {
- JEditorPane info = new JEditorPane();
- info.setEditable(false);
- info.setEditorKit(new HTMLEditorKit());
-
- if (!is_new) {
- info.setText("Edit the program's fields.");
- } else {
- info.setText("Enter command for new Hex program
"+
- "The command can be simply the name of the " +
- "executable file, or the name plus any options " +
- "you wish to set. The working directory can be left " +
- "blank if the program does not need a special " +
- "working directory. Enter a simple descriptive name " +
- "to refer to this program.");
- }
- add(info, BorderLayout.NORTH);
- add(createProgramPanel(m_program), BorderLayout.CENTER);
- add(createButtonPanel(), BorderLayout.SOUTH);
-
- if (!is_new) {
- setPreferredSize(new Dimension(500, 180));
- } else {
- setPreferredSize(new Dimension(500, 280));
- }
- pack();
-
- setResizable(false);
-
- setVisible(true);
- }
-
- public void actionPerformed(ActionEvent e)
- {
- String cmd = e.getActionCommand();
- if (cmd.equals("OK")) {
-
- m_program.m_name = m_name.getText();
- m_program.m_command = m_command.getText();
- m_program.m_working = m_working.getText();
-
- dispose();
-
- } else if (cmd.equals("Cancel")) {
- dispose();
- }
- }
-
- private JPanel createProgramPanel(Program program)
- {
- JPanel panel = new JPanel(new SpringLayout());
- JLabel l;
-
- l = new JLabel("Name:", JLabel.TRAILING);
- panel.add(l);
-
- m_name = new JTextField(40);
- if (program != null) m_name.setText(program.m_name);
- l.setLabelFor(m_name);
- panel.add(m_name);
-
- l = new JLabel("Command:", JLabel.TRAILING);
- panel.add(l);
- m_command = new JTextField(40);
- if (program != null) m_command.setText(program.m_command);
- l.setLabelFor(m_command);
- panel.add(m_command);
-
- l = new JLabel("Working Directory:", JLabel.TRAILING);
- panel.add(l);
- m_working = new JTextField(40);
- if (program != null) m_working.setText(program.m_working);
- l.setLabelFor(m_working);
- panel.add(m_working);
-
- SpringUtilities.makeCompactGrid(panel,
- 3, 2, // rows, cols
- 6, 6, // initX, initY
- 6, 6); // xPad, yPad
-
- return panel;
- }
-
- private JPanel createButtonPanel()
- {
- JPanel panel = new JPanel();
-
- JButton button = new JButton(" OK ");
- button.addActionListener(this);
- button.setActionCommand("OK");
- panel.add(button);
-
- button = new JButton("Cancel");
- button.addActionListener(this);
- button.setActionCommand("Cancel");
- panel.add(button);
-
- return panel;
- }
-
- JTextField m_name;
- JTextField m_command;
- JTextField m_working;
-
- Program m_program;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/gui/FileDialogs.java b/src/hexgui/gui/FileDialogs.java
deleted file mode 100644
index f6534e9..0000000
--- a/src/hexgui/gui/FileDialogs.java
+++ /dev/null
@@ -1,262 +0,0 @@
-// FileDialogs.java
-
-package hexgui.gui;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Container;
-import java.awt.Dimension;
-import java.awt.FileDialog;
-import java.awt.Frame;
-import java.awt.Graphics;
-import java.awt.Image;
-import java.awt.MediaTracker;
-import java.awt.Toolkit;
-import java.awt.event.ActionListener;
-import java.awt.event.ActionEvent;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.io.File;
-import java.net.URL;
-import java.net.MalformedURLException;
-import java.text.MessageFormat;
-import java.util.Locale;
-import java.util.prefs.Preferences;
-import javax.swing.Box;
-import javax.swing.BoxLayout;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JFileChooser;
-import javax.swing.JPanel;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import hexgui.sgf.GameFileFilter;
-import hexgui.util.ErrorMessage;
-import hexgui.util.Platform;
-import hexgui.util.StringUtils;
-
-/** File dialogs. */
-public final class FileDialogs
-{
- public static File showOpen(Component parent, String title)
- {
- return showFileChooser(parent, Type.FILE_OPEN, null, false, title);
- }
-
- public static File showOpenSgf(Component parent)
- {
- return showFileChooser(parent, Type.FILE_OPEN, null, true, null);
- }
-
- public static File showSave(Component parent, String title,
- MessageDialogs messageDialogs)
- {
- return showFileChooserSave(parent, null, false, title,
- messageDialogs);
- }
-
- public static File showSaveSgf(Frame parent,
- MessageDialogs messageDialogs)
- {
- return showFileChooserSave(parent, s_lastFile, true, null,
- messageDialogs);
- }
-
- /** File selection, unknown whether for load or save. */
- public static File showSelectFile(Component parent, String title)
- {
- return showFileChooser(parent, Type.FILE_SELECT, s_lastFile, false,
- title);
- }
-
- public static void setLastFile(File file)
- {
- s_lastFile = file;
- }
-
- private enum Type
- {
- /** Dialog type for opening a file. */
- FILE_OPEN,
-
- /** Dialog type for saving to a file. */
- FILE_SAVE,
-
- /** Dialog type for selecting a file.
- Use this type, if a file name should be selected, but it is not
- known what the file name is used for and if the file already
- exists.
- @deprecated Not supported by native AWT FileDialog */
- FILE_SELECT
- }
-
- /** Use native AWT-dialogs.
- They are used on Mac OS X because JFileChooser looks too different
- from the native dialogs (Java 1.5), and on Windows because
- JFileChooser is too slow on Windows XP (startup and directory changing
- takes up to 10 sec; Java 1.6) */
- private static final boolean NATIVE_DIALOGS =
- (Platform.isMac() || Platform.isWindows());
-
- private static File s_lastFile;
-
- /** Make constructor unavailable; class is for namespace only. */
- private FileDialogs()
- {
- }
-
- /** Find first parent that is a Frame.
- @return null If no such parent. */
- private static Frame findParentFrame(Component component)
- {
- while (component != null)
- if (component instanceof Frame)
- return (Frame)component;
- else
- component = component.getParent();
- return null;
- }
-
- private static File showFileChooser(Component parent, Type type,
- File lastFile, boolean setSgfFilter,
- String title)
- {
- // Use native dialogs for some platforms. but not for type select
- // There is no native dialog for select
- if (NATIVE_DIALOGS && type != Type.FILE_SELECT)
- {
- Frame frame = findParentFrame(parent);
- return showFileChooserAWT(frame, type, title);
- }
- return showFileChooserSwing(parent, type, lastFile, setSgfFilter,
- title);
- }
-
- private static File showFileChooserSave(Component parent,
- File lastFile,
- boolean setSgfFilter,
- String title,
- MessageDialogs messageDialogs)
- {
- File file = showFileChooser(parent, Type.FILE_SAVE, lastFile,
- setSgfFilter, title);
- if (NATIVE_DIALOGS)
- // Overwrite warning is already part of FileDialog
- return file;
- while (file != null)
- {
- if (file.exists())
- {
- String mainMessage =
- MessageFormat.format("Replace file \"{0}\"",
- file.getName());
- String optionalMessage = "If you overwrite the file, the previous version will be lost.";
- if (! messageDialogs.showQuestion(parent, mainMessage,
- optionalMessage,
- "Replace", true))
- {
- file = showFileChooser(parent, Type.FILE_SAVE, lastFile,
- setSgfFilter, title);
- continue;
- }
- }
- break;
- }
- return file;
- }
-
- private static File showFileChooserAWT(Frame parent, Type type,
- String title)
- {
- FileDialog dialog = new FileDialog(parent);
- if (title == null)
- {
- switch (type)
- {
- case FILE_OPEN:
- title = "Open";
- break;
- case FILE_SAVE:
- title = "Save";
- break;
- default:
- assert false;
- }
- }
- dialog.setTitle(title);
- int mode = FileDialog.LOAD;
- if (type == Type.FILE_SAVE)
- mode = FileDialog.SAVE;
- dialog.setMode(mode);
- /* Commented out, because there is no way to change the filter by the
- user (at least not on Linux)
- if (setSgfFilter)
- dialog.setFilenameFilter(new FilenameFilter() {
- public boolean accept(File dir, String name)
- {
- return name.toLowerCase().endsWith("sgf");
- }
- });
- */
- //dialog.setLocationRelativeTo(parent); // Java <= 1.4
- dialog.setLocationByPlatform(true);
- dialog.setVisible(true);
- if (dialog.getFile() == null)
- return null;
- return new File(dialog.getDirectory(), dialog.getFile());
- }
-
- private static File showFileChooserSwing(Component parent, Type type,
- File lastFile,
- boolean setSgfFilter,
- String title)
- {
- JFileChooser chooser;
- if (s_lastFile == null)
- {
- if (Platform.isMac())
- // user.dir is application directory on Mac, which is bad
- // I have not found a way to set it to user home in Info.plist
- // so I use null here, which sets is to the user home
- chooser = new JFileChooser((String)null);
- else
- chooser = new JFileChooser(System.getProperty("user.dir"));
- }
- else
- chooser = new JFileChooser(s_lastFile);
- chooser.setMultiSelectionEnabled(false);
- javax.swing.filechooser.FileFilter filter = new GameFileFilter();
- chooser.addChoosableFileFilter(filter);
- if (setSgfFilter)
- {
- chooser.setFileFilter(filter);
- }
- else
- chooser.setFileFilter(chooser.getAcceptAllFileFilter());
- if (type == Type.FILE_SAVE)
- {
- if (lastFile != null && lastFile.isFile() && lastFile.exists())
- chooser.setSelectedFile(lastFile);
- }
- if (title != null)
- chooser.setDialogTitle(title);
- int ret;
- switch (type)
- {
- case FILE_SAVE:
- ret = chooser.showSaveDialog(parent);
- break;
- case FILE_OPEN:
- ret = chooser.showOpenDialog(parent);
- break;
- default:
- ret = chooser.showDialog(parent, "Select");
- break;
- }
- if (ret != JFileChooser.APPROVE_OPTION)
- return null;
- File file = chooser.getSelectedFile();
- s_lastFile = file;
- return file;
- }
-}
diff --git a/src/hexgui/gui/GameInfoPanel.java b/src/hexgui/gui/GameInfoPanel.java
deleted file mode 100644
index 994bfdc..0000000
--- a/src/hexgui/gui/GameInfoPanel.java
+++ /dev/null
@@ -1,120 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.gui;
-
-import hexgui.hex.HexColor;
-import hexgui.game.Clock;
-
-import java.io.*;
-import java.util.*;
-import javax.swing.*;
-import javax.swing.event.DocumentListener;
-import javax.swing.border.EtchedBorder;
-import java.awt.*;
-import java.awt.event.*;
-import java.net.URL;
-
-/** Displays info about the current game. */
-public class GameInfoPanel
- extends JPanel
-{
- public GameInfoPanel(Clock blackClock, Clock whiteClock)
- {
- JPanel panel = new JPanel();
- add(panel, BorderLayout.CENTER);
-
- JPanel bpanel = new JPanel();
- bpanel.setLayout(new BoxLayout(bpanel, BoxLayout.Y_AXIS));
- URL bURL = getURL("hexgui/images/black-24x24.png");
- JLabel blab = new JLabel(new ImageIcon(bURL));
- blab.setAlignmentX(Component.CENTER_ALIGNMENT);
- bpanel.add(blab);
- bpanel.add(new GuiClock(HexColor.BLACK, blackClock));
-
- JPanel wpanel = new JPanel();
- wpanel.setLayout(new BoxLayout(wpanel, BoxLayout.Y_AXIS));
- URL wURL = getURL("hexgui/images/white-24x24.png");
- JLabel wlab = new JLabel(new ImageIcon(wURL));
- wlab.setAlignmentX(Component.CENTER_ALIGNMENT);
- wpanel.add(wlab);
- wpanel.add(new GuiClock(HexColor.WHITE, whiteClock));
-
- panel.add(bpanel);
- panel.add(wpanel);
-
- //setPreferredSize(new Dimension(200, 150));
- }
-
- private URL getURL(String filename)
- {
- URL url = null;
- if (filename != null) {
- ClassLoader classLoader = getClass().getClassLoader();
- url = classLoader.getResource(filename);
- }
- return url;
- }
-
-};
-
-class GuiClock
- extends JTextField
- implements Clock.Listener
-{
- public GuiClock(HexColor color, Clock clock)
- {
- super(COLUMNS);
-
- m_clock = clock;
- m_clock.addListener(this);
-
- //Monspace font doesn't center correctly on the Mac
- //GuiUtil.setMonospacedFont(this);
- setEditable(false);
- setFocusable(false);
- setHorizontalAlignment(SwingConstants.CENTER);
- //setMinimumSize(getPreferredSize());
- m_color = color;
- setText("00:00");
- }
-
- public final void setText(String text)
- {
- super.setText(text);
- String toolTip;
- if (m_color == HexColor.BLACK)
- toolTip = "Time for Black";
- else
- toolTip = "Time for White";
- if (text.length() > COLUMNS)
- toolTip = toolTip + " (" + text + ")";
- setToolTipText(toolTip);
- }
-
- public void clockChanged()
- {
- int elapsed = m_clock.elapsed();
- int minutes = elapsed / 60000;
- int seconds = (elapsed % 60000) / 1000;
- String min, sec;
-
- min = (minutes < 10) ? "0"+minutes : "" + minutes;
- sec = (seconds < 10) ? "0"+seconds : "" + seconds;
- setText(min+":"+sec);
- }
-
- /** Serial version to suppress compiler warning.
- Contains a marker comment for serialver.sf.net
- */
- private static final long serialVersionUID = 0L; // SUID
-
- private static final int COLUMNS = 5;
-
- private final HexColor m_color;
-
- private Clock m_clock;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/gui/GuiBoard.java b/src/hexgui/gui/GuiBoard.java
deleted file mode 100644
index e549822..0000000
--- a/src/hexgui/gui/GuiBoard.java
+++ /dev/null
@@ -1,774 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.gui;
-
-import hexgui.hex.*;
-import hexgui.util.*;
-import hexgui.game.Node;
-
-import java.util.Vector;
-import java.util.Map;
-import java.util.TreeMap;
-import java.math.BigInteger;
-import javax.swing.*;
-import javax.swing.border.EtchedBorder;
-import java.awt.print.Printable;
-import java.awt.print.PageFormat;
-import java.awt.print.PrinterException;
-import java.awt.*;
-import java.awt.event.*;
-import java.net.URL;
-
-//----------------------------------------------------------------------------
-
-/** Gui Board. */
-public final class GuiBoard
- extends JPanel implements Printable
-{
- /** Callback for clicks on a field. */
- public interface Listener
- {
- void panelClicked();
- void fieldClicked(HexPoint point, boolean ctrl, boolean shift);
- void fieldDoubleClicked(HexPoint point, boolean ctrl, boolean shift);
- }
-
- private static final boolean DEFAULT_FLIPPED = true;
-
- public static final int HEXBOARD = 0;
- public static final int YBOARD = 1;
-
- /** Constructor. */
- public GuiBoard(Listener listener, GuiPreferences preferences)
- {
- m_image = null;
- m_listener = listener;
- m_preferences = preferences;
- m_arrows = new Vector>();
-
- initSize(HEXBOARD,
- m_preferences.getInt("gui-board-width"),
- m_preferences.getInt("gui-board-height"));
-
- setDrawType(m_preferences.get("gui-board-type"));
-
- setPreferredSize(new Dimension
- (m_preferences.getInt("gui-board-pixel-width"),
- m_preferences.getInt("gui-board-pixel-height")));
-
- setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
- setLayout(new BoardLayout());
- m_boardPanel = new BoardPanel();
- add(m_boardPanel);
-
- MouseAdapter mouseAdapter = new MouseAdapter()
- {
- public void mouseClicked(MouseEvent e)
- {
- // First inform the parent that we were clicked, to
- // handle things like keyboard focus.
- m_listener.panelClicked();
- GuiField f = m_drawer.getFieldContaining(e.getPoint(), m_field);
- if (f == null) return;
-
- int modifiers = e.getModifiers();
- boolean ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0;
- boolean shift = (modifiers & ActionEvent.SHIFT_MASK) != 0;
- if (e.getClickCount() >= 2)
- m_listener.fieldDoubleClicked(f.getPoint(), ctrl, shift);
- else
- m_listener.fieldClicked(f.getPoint(), ctrl, shift);
- }
- };
- m_boardPanel.addMouseListener(mouseAdapter);
- setCursorType("default");
- setVisible(true);
- }
-
- // Set the cursor to one of: "default", "black", "white",
- // "black-setup", "white-setup".
- public void setCursorType(String name)
- {
- String path;
-
- if (name.equals("white")) {
- path = "hexgui/images/cursor-white.png";
- } else if (name.equals("black")) {
- path = "hexgui/images/cursor-black.png";
- } else if (name.equals("white-setup")) {
- path = "hexgui/images/cursor-white-setup.png";
- } else if (name.equals("black-setup")) {
- path = "hexgui/images/cursor-black-setup.png";
- } else {
- path = null;
- }
-
- if (path == null) {
- setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
- return;
- }
-
- ClassLoader classLoader = getClass().getClassLoader();
- URL url = classLoader.getResource(path);
- if (url == null) {
- System.out.println("setCursorType: could not load '" +
- "hexgui/images/cursor-white.png" + "'!");
- return;
- }
- Image img = new ImageIcon(url).getImage();
- Point hot = new Point(8, 8);
- Toolkit t = getToolkit();
- Cursor c = t.createCustomCursor(img, hot, name);
- setCursor(c);
- }
-
- /** Sets the type of board drawer to use. If name is
- not one of the known values, "Diamond" is used.
- @param name one of ("Diamond", "Flat", "Flat2", "Go").
- */
- public void setDrawType(String name)
- {
- if (name.equals("Y")) {
- m_drawer = new BoardDrawerY();
- initSize(YBOARD, m_width, m_height);
- } else if (name.equals("Go")) {
- if (m_mode != HEXBOARD)
- initSize(HEXBOARD, m_width, m_height);
- m_drawer = new BoardDrawerGo();
- m_preferences.put("gui-board-type", "Go");
- } else if (name.equals("Diamond")) {
- if (m_mode != HEXBOARD)
- initSize(HEXBOARD, m_width, m_height);
- m_drawer = new BoardDrawerDiamond();
- m_preferences.put("gui-board-type", "Diamond");
- } else if (name.equals("Flat")) {
- if (m_mode != HEXBOARD)
- initSize(HEXBOARD, m_width, m_height);
- m_drawer = new BoardDrawerFlat();
- m_preferences.put("gui-board-type", "Flat");
- } else if (name.equals("Flat2")) {
- if (m_mode != HEXBOARD)
- initSize(HEXBOARD, m_width, m_height);
- m_drawer = new BoardDrawerFlat2();
- m_preferences.put("gui-board-type", "Flat2");
- } else {
- System.out.println("GuiBoard: unknown draw type '" + name + "'.");
- m_drawer = new BoardDrawerDiamond();
- }
- repaint();
- }
-
- /** Sets whether black and letters is on top or if white and
- numbers is on top. If string is invalid defaults to positive.
- @param orient either "Positive" or "Negative".
- */
- public void setOrientation(String orient)
- {
- if (orient.equals("Positive"))
- m_preferences.put("gui-board-orientation", "positive");
- else if (orient.equals("Negative"))
- m_preferences.put("gui-board-orientation", "negative");
- else {
- System.out.println("GuiBoard: unknown orientation '" +
- orient + "'.");
- }
- repaint();
- }
-
- public void initSize(int w, int h)
- {
- initSize(m_mode, w, h);
- }
-
- /** Creates a board of the given dimensions.
- Dirty flag is set to false.
- @param m type of board to create (HEX or Y)
- @param w width of the board in cells
- @param h height of the board in cells
- */
- private void initSize(int m, int w, int h)
- {
- System.out.println("GuiBoard.initSize: "
- + (m == HEXBOARD ? "(HEX) " : "(Y) ")
- + w + " " + h);
-
- m_mode = m;
- m_width = w;
- m_height = h;
- m_size = new Dimension(m_width, m_height);
-
- m_dirty_stones = false;
- clearArrows();
-
- if (m_mode == HEXBOARD)
- {
- m_field = new GuiField[w*h+4];
- for (int x=0; x(from, to));
- repaint();
- }
-
- public void clearArrows()
- {
- m_arrows.clear();
- repaint();
- }
-
- /** Clears dynamic marks, leaving stones intact. If the dirty flag is set,
- revert the fields to the saved fields saved in markStonesDirty().
- Dirty stones flag is set to false. See aboutToDirtyStones().
- Empties the list of arrows.
- */
- public void clearMarks()
- {
- if (m_dirty_stones) {
- for (int i=0; ipoint
- */
- public HexColor getColor(HexPoint point)
- {
- GuiField f = getField(point);
- return f.getColor();
- }
-
- /** Gets the field at the specified point.
- Special points are ignored (SWAP_SIDES, etc).
- */
- public GuiField getField(HexPoint point)
- {
- if (point == HexPoint.SWAP_SIDES
- || point == HexPoint.SWAP_PIECES
- || point == HexPoint.PASS
- || point == HexPoint.RESIGN
- || point == HexPoint.FORFEIT) {
- return null;
- }
-
- for (int x=0; xpoint is null. */
-
- public void markLastPlayed(HexPoint point)
- {
- assert(point != HexPoint.SWAP_SIDES && point != HexPoint.SWAP_PIECES);
-
- if (m_last_played != null) {
- m_last_played.clearAttributes(GuiField.LAST_PLAYED);
- m_last_played = null;
- }
- if (point != null) {
- m_last_played = getField(point);
- if (m_last_played != null) {
- m_last_played.setAttributes(GuiField.LAST_PLAYED);
- }
- }
- repaint();
- }
-
- /** Clear swap marks */
- public void clearSwapPlayed()
- {
- for (int x=0; x colors = new TreeMap();
- for (int x=0; x carrier = vc.getCarrier();
- for (int i=0; i stones = vc.getStones();
- for (int i=0; i key = vc.getKey();
- for (int i=0; i= 1)
- {
- return Printable.NO_SUCH_PAGE;
- }
- double width = getWidth();
- double height = getHeight();
- double pageWidth = format.getImageableWidth();
- double pageHeight = format.getImageableHeight();
- double scale = 1;
- if (width >= pageWidth)
- scale = pageWidth / width;
- double xSpace = (pageWidth - width * scale) / 2;
- double ySpace = (pageHeight - height * scale) / 2;
- Graphics2D g2d = (Graphics2D)g;
- g2d.translate(format.getImageableX() + xSpace,
- format.getImageableY() + ySpace);
- g2d.scale(scale, scale);
- print(g2d);
- return Printable.PAGE_EXISTS;
- }
-
- //------------------------------------------------------------
-
- /** Converts a hex string representing a bitset into a vector of
- HexPoints. This relies on m_field being ordered in a particular
- fashion.
-
- NOTE: THIS IS BROKEN SINCE HexPoint was changed in wolve, r182.
- USE BASE 64 INSTEAD!
-
- FIXME: switch carriers to be printed as a list of HexPoints instead of
- as hex strings?
- */
- private Vector convertHexString(String str)
- {
- Vector ret = new Vector();
-
- for (int i=0; i convertBase64String(String str)
- {
-
- Vector ret = new Vector();
- for (int i=0; i> arrows = m_arrows;
-
- boolean positive = true;
- if (m_preferences.get("gui-board-orientation").equals("negative")) {
- positive = false;
- }
- boolean flip;
- if (m_preferences.get("gui-board-type").equals("Flat2")) {
- flip = positive;
- } else {
- flip = !positive;
- }
-
- if (flip) {
- bw = m_height;
- bh = m_width;
- alphaontop = false;
- ff = flipFields(m_field);
-
- arrows = new Vector>();
- for (int i=0; i
- (HexPoint.get(p1.y, p1.x),
- HexPoint.get(p2.y, p2.x)));
- }
- }
-
- m_drawer.draw(m_image.getGraphics(),
- w, h, bw, bh, alphaontop,
- ff, arrows);
- graphics.drawImage(m_image, 0, 0, null);
- }
-
- public void setBounds(int x, int y, int w, int h)
- {
- super.setBounds(x, y, w, h);
- m_image = null;
- }
- }
-
- public void mousePressed(MouseEvent e) {}
- public void mouseReleased(MouseEvent e) {}
- public void mouseEntered(MouseEvent e) {}
- public void mouseExited(MouseEvent e) {}
-
- private int m_width, m_height;
- private Dimension m_size;
- private int m_mode;
-
- private Image m_image;
- private GuiField m_field[];
- private Vector> m_arrows;
-
- private boolean m_dirty_stones;
- private GuiField m_backup_field[];
-
- private GuiField m_last_played;
-
- private BoardDrawerBase m_drawer;
- private BoardPanel m_boardPanel;
-
- private Listener m_listener;
- private GuiPreferences m_preferences;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/gui/GuiField.java b/src/hexgui/gui/GuiField.java
deleted file mode 100644
index f673994..0000000
--- a/src/hexgui/gui/GuiField.java
+++ /dev/null
@@ -1,327 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.gui;
-
-import javax.swing.*;
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.AlphaComposite;
-import java.awt.FontMetrics;
-import java.awt.Font;
-
-import java.awt.event.*;
-import java.awt.geom.*;
-
-import hexgui.hex.*;
-import hexgui.util.*;
-
-//----------------------------------------------------------------------------
-
-public class GuiField
-{
- public static final int DRAW_CELL_OUTLINE = 1;
- public static final int LAST_PLAYED = 2;
- public static final int SWAP_PLAYED = 4;
- public static final int DRAW_TEXT = 8;
- public static final int DRAW_ALPHA = 16;
- public static final int SELECTED = 32;
-
- private static final Color COLOR_STONE_BLACK = Color.decode("#030303");
- private static final Color COLOR_STONE_BLACK_BRIGHT = Color.decode("#666666");
- private static final Color COLOR_STONE_WHITE = Color.decode("#d7d0c9");
- private static final Color COLOR_STONE_WHITE_BRIGHT = Color.decode("#ffffff");
-
-
- public GuiField(HexPoint p)
- {
- this(p, HexColor.EMPTY, 0, null, null, 0);
- }
-
- public GuiField(HexPoint p, HexColor c, int attributes,
- String text, Color alpha, float blend)
- {
- m_point = p;
- m_color = c;
- m_text = text;
- m_alpha_color = alpha;
- m_attributes = attributes;
- m_alpha_blend = blend;
- }
-
- /** Creates a copy of the given field. */
- public GuiField(GuiField f)
- {
- this(f.getPoint(), f.getColor(), f.getAttributes(),
- f.getText(), f.getAlphaColor(), f.getAlphaBlend());
- }
-
- public static int getStoneMargin(int width)
- {
- return width / 17 + 1;
- }
-
- public void clearAttributes()
- {
- m_attributes = 0;
- }
-
- public void clearAttributes(int f)
- {
- m_attributes &= ~f;
- }
-
- public void setAttributes(int f)
- {
- m_attributes |= f;
- }
-
- public int getAttributes()
- {
- return m_attributes;
- }
-
- public void setColor(HexColor c)
- {
- m_color = c;
- }
-
- public HexColor getColor()
- {
- return m_color;
- }
-
- public void setText(String str)
- {
- m_text = str;
- if (str == null)
- clearAttributes(DRAW_TEXT);
- else
- setAttributes(DRAW_TEXT);
- }
-
- public String getText() {
- return m_text;
- }
-
- public void setAlphaColor(Color c)
- {
- m_alpha_color = c;
- m_alpha_blend = 0.3f;
- if (c == null)
- clearAttributes(DRAW_ALPHA);
- else
- setAttributes(DRAW_ALPHA);
- }
-
- public void setAlphaColor(Color c, float blend)
- {
- m_alpha_color = c;
- m_alpha_blend = blend;
- if (c == null)
- clearAttributes(DRAW_ALPHA);
- else
- setAttributes(DRAW_ALPHA);
- }
-
- public Color getAlphaColor() {
- return m_alpha_color;
- }
-
- public float getAlphaBlend() {
- return m_alpha_blend;
- }
-
- public void setSelected(boolean f)
- {
- if (f) {
- setAttributes(SELECTED);
- } else {
- clearAttributes(SELECTED);
- }
- }
-
- public void setPoint(HexPoint p) {
- m_point = p;
- }
- public HexPoint getPoint() {
- return m_point;
- }
-
- public void clear()
- {
- setColor(HexColor.EMPTY);
- }
-
- private RadialGradientPaint getPaint(int width,
- int height,
- Color colorNormal,
- Color colorBright)
- {
- RadialGradientPaint paint;
- int paintSize;
- int size = (width < height) ? width : height;
- int radius = Math.max(size / 3, 1);
- Point2D.Double centerPoint =
- new Point2D.Double(width/2 - size/6, height/2 - size/6);
- Point2D.Double radiusPoint =
- new Point2D.Double(radius, radius);
- paint = new RadialGradientPaint(centerPoint, colorBright,
- radiusPoint, colorNormal);
- return paint;
- }
-
- public void draw(Graphics g, int x, int y, int w, int h)
- {
- if (!g.hitClip(x, y, w, h))
- return;
-
- m_width = w;
- m_height = h;
-
- m_radius = (h < w) ? h/2 : w/2;
- m_margin = getStoneMargin(m_radius*2);
-
- m_graphics = g.create(x-w/2,y-h/2,w,h);
- if (m_graphics instanceof Graphics2D) {
- m_graphics2D = (Graphics2D)m_graphics;
- } else {
- m_graphics2D = null;
- }
-
- if (m_color == HexColor.WHITE) {
- drawStone(COLOR_STONE_WHITE, COLOR_STONE_WHITE_BRIGHT);
- } else if (m_color == HexColor.BLACK) {
- drawStone(COLOR_STONE_BLACK, COLOR_STONE_BLACK_BRIGHT);
- }
-
- if ((m_attributes & LAST_PLAYED) != 0) {
- drawLastPlayed();
- }
-
- if ((m_attributes & SWAP_PLAYED) != 0) {
- drawSwapPlayed();
- }
-
- // FIXME: this is done in BoardDrawer since we don't know
- // anything about our shape and size and we want to cover the
- // entire field. Should all drawing be done in board drawer?
- // if ((m_attributes & DRAW_ALPHA) != 0) drawAlpha();
-
- if ((m_attributes & DRAW_TEXT) != 0)
- drawText();
-
- }
-
- private void drawStone(Color normal, Color bright)
- {
- if (m_graphics2D != null) {
- RadialGradientPaint paint = getPaint(m_width, m_height,
- normal, bright);
- m_graphics2D.setPaint(paint);
- } else {
- m_graphics.setColor(normal);
- }
-
- int size = m_radius - m_margin;
- m_graphics.fillOval(m_width/2 - size, m_height/2 - size,
- size*2, size*2);
-
- m_graphics.setPaintMode();
- }
-
- private void drawLastPlayed()
- {
- m_graphics.setColor(Color.gray);
- int size = (m_radius - m_margin) / 6;
- m_graphics.fillOval(m_width/2 - size, m_height/2 - size, 2*size, 2*size);
- }
-
- /** Draw the given string centered at the coordinates (x,y) in the
- current font, with the given relative size. */
- private void drawString(String str, double x, double y, double size)
- {
- double abssize = (m_radius - m_margin) * size;
- Font f = m_graphics.getFont();
- Font f2 = f.deriveFont((float)abssize);
- FontMetrics m = m_graphics.getFontMetrics(f2);
- double width = m.stringWidth(str);
- double height = m.getAscent();
-
- m_graphics.setFont(f2);
- m_graphics.drawString(str, (int)(x - width/2), (int)(y + 0.8*height/2));
- m_graphics.setFont(f);
- }
-
- private void drawSwapPlayed()
- {
- if (m_color == HexColor.BLACK) {
- m_graphics.setColor(Color.white);
- } else {
- m_graphics.setColor(Color.black);
- }
- this.drawString("S", m_width/2.0, m_height/2.0, 1);
- }
-
- private void drawAlpha()
- {
- if (m_alpha_color == null)
- return;
- if (m_graphics2D == null)
- return;
-
- m_graphics2D.setComposite(AlphaComposite.
- getInstance(AlphaComposite.SRC_OVER,
- 0.3f));
- m_graphics.setColor(m_alpha_color);
- m_graphics.fillRect(m_width/2 - m_width/4, m_height/2 - m_height/4,
- m_width/2, m_height/2);
-
- }
-
- private void drawText()
- {
- String[] lines = m_text.split("@");
- int nlines = lines.length;
-
- double size = m_radius - m_margin;
- double relheight = nlines > 1 ? 2.0/nlines : 1.0;
- double height = size * relheight;
-
- double y = m_height/2 + ((nlines-1)*height)/2;
-
- for (int i=lines.length-1; i>=0; --i) {
- String str = lines[i].trim();
-
- Color color = Color.black;
- if (getColor() == HexColor.BLACK)
- color = Color.white;
-
- m_graphics.setColor(color);
- this.drawString(str, m_width/2, y, relheight);
-
- y -= height;
- }
- }
-
- private HexPoint m_point;
- private HexColor m_color;
- private int m_attributes;
-
- private Color m_alpha_color;
- private float m_alpha_blend;
-
- private String m_text;
-
- private int m_width;
- private int m_height;
- private int m_radius;
- private int m_margin;
-
- private Graphics m_graphics;
- private Graphics2D m_graphics2D;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/gui/GuiMenuBar.java b/src/hexgui/gui/GuiMenuBar.java
deleted file mode 100644
index 8b2ff16..0000000
--- a/src/hexgui/gui/GuiMenuBar.java
+++ /dev/null
@@ -1,633 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.gui;
-
-import hexgui.game.Node;
-
-import java.util.*;
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.*;
-
-//----------------------------------------------------------------------------
-
-/** Menu bar. */
-public final class GuiMenuBar
-{
- public GuiMenuBar(ActionListener listener, GuiPreferences preferences)
- {
- m_preferences = preferences;
-
- m_menuBar = new JMenuBar();
-
- m_listener = listener;
- m_menuBar.add(createFileMenu());
- m_menuBar.add(createProgramMenu());
- m_menuBar.add(createGameMenu());
- m_menuBar.add(createEditMenu());
- m_menuBar.add(createViewMenu());
- m_menuBar.add(createHelpMenu());
-
- setProgramConnected(false);
- }
-
- public JMenuBar getJMenuBar()
- {
- return m_menuBar;
- }
-
- public void setProgramConnected(boolean f)
- {
- //m_connect_remote.setEnabled(!f);
- m_connect_local.setEnabled(!f);
- m_disconnect.setEnabled(f);
- m_reconnect.setEnabled(f);
- m_genmove.setEnabled(f);
-
- if (f == false) {
- setShellVisible(false);
- m_shell_visible.setEnabled(false);
- setAnalyzeVisible(false);
- m_analyze_visible.setEnabled(false);
- } else {
- m_shell_visible.setEnabled(true);
- m_analyze_visible.setEnabled(true);
-
- setShellVisible(m_preferences.
- getBoolean("shell-show-on-connect"));
- setAnalyzeVisible(m_preferences.
- getBoolean("analyze-show-on-connect"));
- }
- }
-
- public void updateMenuStates(HexGui current)
- {
- m_swap_pieces.setEnabled(current.isSwapAllowed());
- m_swap_sides.setEnabled(current.isSwapAllowed());
- }
-
- //----------------------------------------------------------------------
-
- private JMenu createFileMenu()
- {
- JMenu menu = new JMenu("File");
- menu.setMnemonic(KeyEvent.VK_F);
-
- JMenuItem item;
- item = new JMenuItem("Open...");
- item.setMnemonic(KeyEvent.VK_O);
- item.addActionListener(m_listener);
- item.setActionCommand("loadgame");
- menu.add(item);
-
- menu.addSeparator();
-
- item = new JMenuItem("Save Game");
- item.setMnemonic(KeyEvent.VK_S);
- item.addActionListener(m_listener);
- item.setActionCommand("savegame");
- menu.add(item);
-
- item = new JMenuItem("Save Game As...");
- item.setMnemonic(KeyEvent.VK_A);
- item.addActionListener(m_listener);
- item.setActionCommand("savegameas");
- menu.add(item);
-
- item = new JMenuItem("Save Position As...");
- item.addActionListener(m_listener);
- item.setActionCommand("save-position-as");
- menu.add(item);
-
- menu.addSeparator();
-
- item = new JMenuItem("Print Preview");
- item.addActionListener(m_listener);
- item.setActionCommand("print-preview");
- menu.add(item);
-
- item = new JMenuItem("Print...");
- item.addActionListener(m_listener);
- item.setActionCommand("print");
- menu.add(item);
-
- menu.addSeparator();
-
- item = new JMenuItem("Exit");
- item.setMnemonic(KeyEvent.VK_X);
- item.addActionListener(m_listener);
- item.setActionCommand("shutdown");
- menu.add(item);
-
- return menu;
- }
-
- //----------------------------------------------------------------------
- private JMenu createProgramMenu()
- {
- JMenu menu = new JMenu("Program");
- menu.setMnemonic(KeyEvent.VK_P);
-
- JMenuItem item;
-
- item = new JMenuItem("New Program...");
- item.addActionListener(m_listener);
- item.setActionCommand("new-program");
- menu.add(item);
-
- item = new JMenuItem("Edit Program...");
- item.addActionListener(m_listener);
- item.setActionCommand("edit-program");
- menu.add(item);
-
- item = new JMenuItem("Delete Program...");
- item.addActionListener(m_listener);
- item.setActionCommand("delete-program");
- menu.add(item);
-
- menu.addSeparator();
-
- item = new JMenuItem("Connect Local Program...");
- item.addActionListener(m_listener);
- item.setActionCommand("connect-local-program");
- m_connect_local = item;
- menu.add(item);
-
- // item = new JMenuItem("Connect Remote Program...");
- // item.addActionListener(m_listener);
- // item.setActionCommand("connect-program");
- // item.setEnabled(false);
- // m_connect_remote = item;
- // menu.add(item);
-
- menu.addSeparator();
-
- item = new JMenuItem("Reconnect Program");
- item.addActionListener(m_listener);
- item.setActionCommand("reconnect-program");
- m_reconnect = item;
- menu.add(item);
-
- item = new JMenuItem("Disconnect Program");
- item.addActionListener(m_listener);
- item.setActionCommand("disconnect-program");
- m_disconnect = item;
- menu.add(item);
-
- return menu;
- }
-
- //----------------------------------------------------------------------
-
- private JMenu createGameMenu()
- {
- JMenu menu = new JMenu("Game");
- menu.setMnemonic(KeyEvent.VK_G);
-
- JMenuItem item;
- item = new JMenuItem("New");
- item.setMnemonic(KeyEvent.VK_N);
- item.addActionListener(m_listener);
- item.setActionCommand("newgame");
- menu.add(item);
-
- JMenu submenu;
-
- menu.addSeparator();
-
- submenu = createClockMenu();
- menu.add(submenu);
-
- menu.addSeparator();
-
- submenu = createToMoveMenu();
- menu.add(submenu);
-
- menu.addSeparator();
-
- m_swap_pieces = new JMenuItem("Swap pieces");
- m_swap_pieces.addActionListener(m_listener);
- m_swap_pieces.setActionCommand("game_swap_pieces");
- menu.add(m_swap_pieces);
-
- m_swap_sides = new JMenuItem("Swap sides");
- m_swap_sides.addActionListener(m_listener);
- m_swap_sides.setActionCommand("game_swap_sides");
- menu.add(m_swap_sides);
-
- m_pass = new JMenuItem("Pass");
- m_pass.addActionListener(m_listener);
- m_pass.setActionCommand("game_pass");
- menu.add(m_pass);
-
- m_resign = new JMenuItem("Resign");
- m_resign.addActionListener(m_listener);
- m_resign.setActionCommand("game_resign");
- menu.add(m_resign);
-
- m_forfeit = new JMenuItem("Forfeit");
- m_forfeit.addActionListener(m_listener);
- m_forfeit.setActionCommand("game_forfeit");
- menu.add(m_forfeit);
-
- m_addsetup = new JMenuItem("Add setup node");
- m_addsetup.addActionListener(m_listener);
- m_addsetup.setActionCommand("game_addsetup");
- menu.add(m_addsetup);
-
- m_genmove = new JMenuItem("Generate Computer Move");
- m_genmove.addActionListener(m_listener);
- m_genmove.setActionCommand("genmove");
- menu.add(m_genmove);
-
- menu.addSeparator();
-
- item = new JMenuItem("Delete Current Branch");
- item.addActionListener(m_listener);
- item.setActionCommand("game_delete_branch");
- menu.add(item);
-
- item = new JMenuItem("Make Main Branch");
- item.addActionListener(m_listener);
- item.setActionCommand("game_make_main_branch");
- menu.add(item);
-
- return menu;
- }
-
- private JMenu createClockMenu()
- {
- JMenu menu = new JMenu("Clock");
- JMenuItem item;
-
- item = new JMenuItem("Start");
- item.addActionListener(m_listener);
- item.setActionCommand("game_start_clock");
- menu.add(item);
-
- item = new JMenuItem("Stop");
- item.addActionListener(m_listener);
- item.setActionCommand("game_stop_clock");
- menu.add(item);
-
- return menu;
- }
-
- private JMenu createToMoveMenu()
- {
- JMenu menu = new JMenu("Color To Move");
-
- m_colorGroup = new ButtonGroup();
- String pref = m_preferences.get("first-move-color");
-
- JRadioButtonMenuItem item;
- item = new JRadioButtonMenuItem("black");
- item.addActionListener(m_listener);
- item.setActionCommand("set_to_move");
- if (pref.equals("black")) item.setSelected(true);
- m_colorGroup.add(item);
- menu.add(item);
-
- item = new JRadioButtonMenuItem("white");
- item.addActionListener(m_listener);
- item.setActionCommand("set_to_move");
- if (pref.equals("white")) item.setSelected(true);
- m_colorGroup.add(item);
- menu.add(item);
-
- return menu;
- }
-
- public String getToMove()
- {
- Enumeration e = m_colorGroup.getElements();
- AbstractButton b = (AbstractButton)e.nextElement();
- while (!b.isSelected() && e.hasMoreElements()) {
- b = (AbstractButton)e.nextElement();
- }
- return b.getText();
- }
-
- public void setToMove(String color)
- {
- Enumeration e = m_colorGroup.getElements();
- AbstractButton b = (AbstractButton)e.nextElement();
- while (true) {
- if (color.equalsIgnoreCase(b.getText())) {
- b.setSelected(true);
- } else {
- b.setSelected(false);
- }
- if (!e.hasMoreElements())
- break;
- b = (AbstractButton)e.nextElement();
- }
- }
-
- //----------------------------------------------------------------------
-
- private JMenu createEditMenu()
- {
- JMenu menu = new JMenu("Edit");
- menu.setMnemonic(KeyEvent.VK_E);
-
- JMenu size = createBoardSizeMenu();
- menu.add(size);
-
- menu.addSeparator();
-
- JMenuItem item;
- item = new JMenuItem("Preferences...");
- item.addActionListener(m_listener);
- item.setActionCommand("show-preferences");
-
- menu.add(item);
-
- return menu;
- }
-
- private JMenu createBoardSizeMenu()
- {
- JMenu menu = new JMenu("Board Size");
- m_bsGroup = new ButtonGroup();
-
- String sizes[] = new String[]
- {
- "19 x 19",
- "15 x 15",
- "14 x 14",
- "13 x 13",
- "11 x 11",
- "10 x 10",
- "9 x 9",
- "8 x 8",
- "7 x 7",
- "6 x 6",
- "5 x 5",
- "4 x 4",
- "3 x 3"
- };
-
- String preferred = m_preferences.get("gui-board-width") + " x "
- + m_preferences.get("gui-board-height");
-
- boolean found = false;
- JRadioButtonMenuItem item;
- for (int i=0; i";
- else
- return
- "";
- }
-
- /** Get size of default monspaced font.
- Can be used for setting the initial size of some GUI elements. */
- public static int getDefaultMonoFontSize()
- {
- return MONOSPACED_FONT.getSize();
- }
-
- public static ImageIcon getIcon(String icon, String name)
- {
- String resource = "hexgui/images/" + icon + ".png";
- URL url = GuiUtil.class.getClassLoader().getResource(resource);
- return new ImageIcon(url, name);
- }
-
- /** Manually break message into multiple lines for multi-line labels.
- Needed for multi-line messages in option panes, because pack() on
- JOptionPane does not compute the option pane size correctly, if a
- maximum width is set and the label text is automatically broken into
- multiple lines. The workaround with calling invalidate() and pack() a
- second time does not work either in this case. See also Sun Bug ID
- 4545951 (still in Linux JDK 1.5.0_04-b05 or Mac 1.4.2_12) */
- public static String insertLineBreaks(String message)
- {
- final int MAX_CHAR_PER_LINE = 72;
- int length = message.length();
- if (length < MAX_CHAR_PER_LINE)
- return message;
- StringBuilder buffer = new StringBuilder();
- int startLine = 0;
- int lastWhiteSpace = -1;
- for (int pos = 0; pos < length; ++pos)
- {
- char c = message.charAt(pos);
- if (pos - startLine > 72)
- {
- int endLine =
- (lastWhiteSpace > startLine ? lastWhiteSpace : pos);
- if (buffer.length() > 0)
- buffer.append("
");
- buffer.append(message.substring(startLine, endLine));
- startLine = endLine;
- }
- if (Character.isWhitespace(c))
- lastWhiteSpace = pos;
- }
- if (buffer.length() > 0)
- buffer.append("
");
- buffer.append(message.substring(startLine));
- return buffer.toString();
- }
-
- /** Call SwingUtilities.invokeAndWait.
- Ignores possible exceptions (apart from printing a warning to
- System.err */
- public static void invokeAndWait(Runnable runnable)
- {
- try
- {
- SwingUtilities.invokeAndWait(runnable);
- }
- catch (InterruptedException e)
- {
- System.err.println("Thread interrupted");
- }
- catch (java.lang.reflect.InvocationTargetException e)
- {
- System.err.println("InvocationTargetException");
- }
- }
-
- public static boolean isActiveWindow(Window window)
- {
- KeyboardFocusManager manager =
- KeyboardFocusManager.getCurrentKeyboardFocusManager();
- return (manager.getActiveWindow() == window);
- }
-
- /** Check window for normal state.
- Checks if window is not maximized (in either or both directions) and
- not iconified. */
- public static boolean isNormalSizeMode(JFrame window)
- {
- int state = window.getExtendedState();
- int mask = Frame.MAXIMIZED_BOTH | Frame.MAXIMIZED_VERT
- | Frame.MAXIMIZED_HORIZ | Frame.ICONIFIED;
- return ((state & mask) == 0);
- }
-
- public static void paintImmediately(JComponent component)
- {
- component.paintImmediately(component.getVisibleRect());
- }
-
- public static void removeKeyBinding(JComponent component, String key)
- {
- int condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
- InputMap inputMap = component.getInputMap(condition);
- // According to the docs, null should remove the action, but it does
- // not seem to work with Sun Java 1.4.2, new Object() works
- inputMap.put(KeyStroke.getKeyStroke(key), new Object());
- }
-
- /** Set antialias rendering hint if graphics is instance of Graphics2D. */
- public static void setAntiAlias(Graphics graphics)
- {
- if (graphics instanceof Graphics2D)
- {
- Graphics2D graphics2D = (Graphics2D)graphics;
- graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
- RenderingHints.VALUE_ANTIALIAS_ON);
- }
- }
-
- /** Set text field non-editable.
- Also sets it non-focusable. */
- public static void setEditableFalse(JTextField field)
- {
- field.setEditable(false);
- field.setFocusable(false);
- }
-
- /** Set Go icon on frame. */
- public static void setGoIcon(Frame frame)
- {
- URL url = s_iconURL;
- if (url != null)
- frame.setIconImage(new ImageIcon(url).getImage());
- }
-
- /** Set property to render button in bevel style on the Mac.
- Only has an effect if Quaqua Look and Feel is used. */
- public static void setMacBevelButton(JButton button)
- {
- button.putClientProperty("Quaqua.Button.style", "bevel");
- }
-
- public static void setMonospacedFont(JComponent component)
- {
- if (MONOSPACED_FONT != null)
- component.setFont(MONOSPACED_FONT);
- }
-
- public static void addStyle(JTextPane textPane, String name,
- Color foreground)
- {
- addStyle(textPane, name, foreground, null, false);
- }
-
- public static void addStyle(JTextPane textPane, String name,
- Color foreground, Color background,
- boolean bold)
- {
- StyledDocument doc = textPane.getStyledDocument();
- StyleContext context = StyleContext.getDefaultStyleContext();
- Style def = context.getStyle(StyleContext.DEFAULT_STYLE);
- Style style = doc.addStyle(name, def);
- if (foreground != null)
- StyleConstants.setForeground(style, foreground);
- if (background != null)
- StyleConstants.setBackground(style, background);
- StyleConstants.setBold(style, bold);
- }
-
- public static void setStyle(JTextPane textPane, int start, int length,
- String name)
- {
- StyledDocument doc = textPane.getStyledDocument();
- Style style;
- if (name == null)
- {
- StyleContext context = StyleContext.getDefaultStyleContext();
- style = context.getStyle(StyleContext.DEFAULT_STYLE);
- }
- else
- style = doc.getStyle(name);
- doc.setCharacterAttributes(start, length, style, true);
- }
-
- public static void setUnlimitedSize(JComponent component)
- {
- Dimension size = new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
- component.setMaximumSize(size);
- }
-
- static
- {
- ClassLoader loader = ClassLoader.getSystemClassLoader();
- // There are problems on some platforms with transparency (e.g. Linux
- // Sun Java 1.5.0). Best solution for now is to take an icon without
- // transparency
- s_iconURL =
- loader.getResource("hexgui/images/hexgui-48x48-notrans.png");
- }
-
- private static final Font MONOSPACED_FONT = Font.decode("Monospaced");
-
- private static final Border EMPTY_BORDER =
- BorderFactory.createEmptyBorder(PAD, PAD, PAD, PAD);
-
- private static final Border SMALL_EMPTY_BORDER =
- BorderFactory.createEmptyBorder(SMALL_PAD, SMALL_PAD,
- SMALL_PAD, SMALL_PAD);
-
- private static final Dimension FILLER_DIMENSION =
- new Dimension(PAD, PAD);
-
- private static final Dimension SMALL_FILLER_DIMENSION =
- new Dimension(SMALL_PAD, SMALL_PAD);
-
- private static URL s_iconURL;
-}
diff --git a/src/hexgui/gui/HexGui.java b/src/hexgui/gui/HexGui.java
deleted file mode 100644
index b090f85..0000000
--- a/src/hexgui/gui/HexGui.java
+++ /dev/null
@@ -1,2706 +0,0 @@
-package hexgui.gui;
-
-import hexgui.hex.*;
-import hexgui.util.Pair;
-import hexgui.util.StringUtils;
-import hexgui.game.Node;
-import hexgui.game.GameInfo;
-import hexgui.game.Clock;
-import hexgui.sgf.SgfWriter;
-import hexgui.sgf.SgfReader;
-import hexgui.htp.HtpController;
-import hexgui.htp.HtpError;
-import hexgui.util.StreamCopy;
-import hexgui.version.Version;
-import hexgui.gui.ParameterDialog;
-import hexgui.htp.AnalyzeDefinition;
-import hexgui.htp.AnalyzeCommand;
-import hexgui.htp.AnalyzeType;
-import hexgui.util.ErrorMessage;
-import hexgui.gui.ShowAnalyzeText;
-
-import java.io.*;
-import static java.text.MessageFormat.format;
-import java.util.*;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.Semaphore;
-import javax.swing.*;
-import java.awt.*;
-import java.awt.image.BufferedImage;
-import java.awt.event.*;
-import java.net.*;
-
-//----------------------------------------------------------------------------
-
-/** HexGui. */
-public final class HexGui
- extends JFrame
- implements ActionListener, GuiBoard.Listener,
- HtpShell.Callback, HtpController.GuiFxCallback,
- AnalyzeDialog.Listener, Comment.Listener
-{
- public HexGui(final File file, final String command)
- {
- super("HexGui");
- setIcon();
-
- System.out.println("HexGui v" + Version.id + "; " + Version.date
- + "\n");
-
- // Catch the close action and shutdown nicely
- setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
- addWindowListener(new java.awt.event.WindowAdapter()
- {
- public void windowClosing(WindowEvent winEvt) {
- cmdShutdown();
- }
- });
-
- m_selected_cells = new Vector();
-
- m_about = new AboutDialog(this);
-
- m_preferences = new GuiPreferences(getClass());
-
- m_menubar = new GuiMenuBar(this, m_preferences);
- setJMenuBar(m_menubar.getJMenuBar());
-
- m_toolbar = new GuiToolBar(this, m_preferences);
- getContentPane().add(m_toolbar.getJToolBar(), BorderLayout.NORTH);
-
- m_statusbar = new StatusBar();
- getContentPane().add(m_statusbar, BorderLayout.SOUTH);
-
- m_guiboard = new GuiBoard(this, m_preferences);
- getContentPane().add(m_guiboard, BorderLayout.CENTER);
-
- m_showAnalyzeText = new ShowAnalyzeText(this, m_guiboard);
-
- JPanel panel = new JPanel(new BorderLayout());
- getContentPane().add(panel, BorderLayout.EAST);
-
- m_blackClock = new Clock();
- m_whiteClock = new Clock();
- m_gameinfopanel = new GameInfoPanel(m_blackClock, m_whiteClock);
- m_comment = new Comment(this);
- panel.add(m_gameinfopanel, BorderLayout.NORTH);
- panel.add(m_comment, BorderLayout.CENTER);
-
- cmdNewGame();
-
- pack();
-
- m_locked = false;
-
- m_semaphore = new Semaphore(1);
- m_htp_queue = new ArrayBlockingQueue(256);
- new Thread(new CommandHandler(this, m_htp_queue)).start();
-
- setVisible(true);
- // After frame is visible, further code using Swing functions must
- // be run in the Swing event dispatch thread.
- SwingUtilities.invokeLater(new Runnable() {
- public void run() {
- initialize(file, command);
- } });
- setCursorType();
- }
-
- //-------------------------------------------------------------------
-
- public void actionPerformed(ActionEvent e)
- {
- String cmd = e.getActionCommand();
-
- unFocus();
-
- //
- // system commands
- //
- if (cmd.equals("shutdown")) {
- cmdShutdown();
- } else if (cmd.equals("new-program")) {
- cmdNewProgram();
- } else if (cmd.equals("edit-program")) {
- cmdEditProgram();
- } else if (cmd.equals("delete-program")) {
- cmdDeleteProgram();
- } else if (cmd.equals("connect-program")) {
- cmdConnectRemoteProgram();
- } else if (cmd.equals("connect-local-program")) {
- cmdConnectLocalProgram();
- } else if (cmd.equals("disconnect-program")) {
- cmdDisconnectProgram();
- } else if (cmd.equals("reconnect-program")) {
- cmdReconnectProgram();
- //
- // file/help commands
- //
- } else if (cmd.equals("newgame")) {
- end_setup();
- cmdNewGame();
- } else if (cmd.equals("savegame")) {
- // We previously only saved when gameChanged() == true,
- // but this is dangerous because saving would fail
- // silently otherwise. It's better to simply save the game
- // when the user asks for it. An alternative use for
- // gameChanged() would be to disable the save button when
- // we think the game hasn't changed. But we shouldn't just
- // offer a button and then do nothing.
- cmdSaveGame();
- } else if (cmd.equals("savegameas")) {
- cmdSaveGameAs();
- } else if (cmd.equals("loadgame")) {
- cmdLoadGame();
- } else if (cmd.equals("save-position-as")) {
- cmdSavePositionAs();
- } else if (cmd.equals("print-preview")) {
- cmdPrintPreview();
- } else if (cmd.equals("print")) {
- cmdPrint();
- } else if (cmd.equals("about")) {
- cmdAbout();
- //
- // gui commands
- //
- } else if (cmd.equals("gui_toolbar_visible")) {
- cmdGuiToolbarVisible();
- } else if (cmd.equals("gui_shell_visible")) {
- cmdGuiShellVisible();
- } else if (cmd.equals("gui_analyze_visible")) {
- cmdGuiAnalyzeVisible();
- } else if (cmd.equals("gui_board_draw_type")) {
- cmdGuiBoardDrawType();
- } else if (cmd.equals("gui_board_orientation")) {
- cmdGuiBoardOrientation();
- } else if (cmd.equals("show-preferences")) {
- cmdShowPreferences();
- } else if (cmd.equals("gui-clear-marks")) {
- cmdClearMarks();
- //
- // game navigation commands
- //
- } else if (cmd.equals("game_beginning")) {
- end_setup();
- backward(-1);
- } else if (cmd.equals("game_backward10")) {
- end_setup();
- backward(10);
- } else if (cmd.equals("game_back")) {
- end_setup();
- backward(1);
- } else if (cmd.equals("game_forward")) {
- end_setup();
- forward(1);
- } else if (cmd.equals("game_forward10")) {
- end_setup();
- forward(10);
- } else if (cmd.equals("game_end")) {
- end_setup();
- forward(-1);
- } else if (cmd.equals("game_up")) {
- end_setup();
- up();
- } else if (cmd.equals("game_down")) {
- end_setup();
- down();
- } else if (cmd.equals("game_swap_sides")) {
- end_setup();
- humanMove(new Move(HexPoint.get("swap-sides"), m_tomove));
- } else if (cmd.equals("game_swap_pieces")) {
- end_setup();
- humanMove(new Move(HexPoint.get("swap-pieces"), m_tomove));
- } else if (cmd.equals("game_pass")) {
- end_setup();
- humanMove(new Move(HexPoint.get("pass"), m_tomove));
- } else if (cmd.equals("game_resign")) {
- end_setup();
- humanMove(new Move(HexPoint.get("resign"), m_tomove));
- } else if (cmd.equals("game_forfeit")) {
- end_setup();
- humanMove(new Move(HexPoint.get("forfeit"), m_tomove));
- } else if (cmd.equals("game_addsetup")) {
- end_setup();
- addSetupNode();
- } else if (cmd.equals("genmove")) {
- end_setup();
- htpGenMove(m_tomove);
- } else if (cmd.equals("game_delete_branch")) {
- end_setup();
- cmdDeleteBranch();
- } else if (cmd.equals("game_make_main_branch")) {
- end_setup();
- cmdMoveBranchTop();
- } else if (cmd.equals("game_start_clock")) {
- startClock();
- } else if (cmd.equals("game_stop_clock")) {
- stopClock();
- } else if (cmd.equals("stop")) {
- m_white.interrupt();
- } else if (cmd.equals("toggle_tomove")) {
- end_setup();
- cmdToggleToMove();
- } else if (cmd.equals("set_to_move")) {
- end_setup();
- cmdSetToMove();
- } else if (cmd.equals("setup-black")) {
- cmdSetupBlack();
- } else if (cmd.equals("setup-white")) {
- cmdSetupWhite();
- }
- //
- // other
- //
- else if (cmd.equals("show_consider_set"))
- {
- Runnable cb = new Runnable()
- { public void run() { cbShowInferiorCells(); } };
- Runnable callback = new GuiRunnable(cb);
- sendCommand("vc-build " + m_tomove.toString() + "\n", callback);
- }
- else if (cmd.equals("solve_state"))
- {
- sendCommand("param_dfpn use_guifx 1\n", null);
- Runnable callback = new GuiRunnable(new Runnable()
- {
- public void run() { cbSolveState(); }
- });
- sendCommand("dfpn-solve-state " + m_tomove + "\n", callback);
- }
- else if (cmd.equals("program_options"))
- {
- AnalyzeCommand command;
- if (m_white_name.equalsIgnoreCase("Mohex") || m_white_name.equalsIgnoreCase("HexHex"))
- {
- command = new AnalyzeCommand
- (new AnalyzeDefinition("param/blah/param_mohex"));
- Runnable cb = new Runnable()
- { public void run() { cbEditParameters(); } };
- Runnable callback = new GuiRunnable(cb);
- m_curAnalyzeCommand = command;
- sendCommand(command.getCommand() + "\n", callback);
- }
- else if (m_white_name.equalsIgnoreCase("Wolve"))
- {
- command = new AnalyzeCommand
- (new AnalyzeDefinition("param/blah/param_wolve"));
- Runnable cb = new Runnable()
- { public void run() { cbEditParameters(); } };
- Runnable callback = new GuiRunnable(cb);
- m_curAnalyzeCommand = command;
- sendCommand(command.getCommand() + "\n", callback);
- }
- else
- ShowError.msg(this, "Unknown program!");
- }
- //
- // unknown command
- //
- else
- {
- System.out.println("Unknown command: '" + cmd + "'.");
- }
- }
-
- //------------------------------------------------------------
- /** Return true if keyboard shortcuts should be enabled. This
- * should be the case unless the user is currently typing in the
- * text area. */
- public boolean shortcutsEnabled()
- {
- return !m_comment.m_textPane.isFocusOwner();
- }
-
- //------------------------------------------------------------
- private void cmdShutdown()
- {
- if (gameChanged() && !askSaveGame())
- return;
-
- System.out.println("Shutting down...");
-
- if (m_white_process != null)
- {
- System.out.println("Stopping [" + m_white_name + " " +
- m_white_version + "] process...");
- m_white_process.destroy();
- }
- System.exit(0);
- }
-
- private void cmdNewProgram()
- {
- Program program = new Program();
- new EditProgramDialog(this, program, "Add New Program", true);
-
- if (program.m_name == null) // user canceled
- return;
-
- // add the program to the list of programs
- m_programs.add(program);
- Program.save(m_programs);
- }
-
- private void cmdEditProgram()
- {
- if (m_programs.isEmpty())
- {
- ShowError.msg(this, "No programs, add a program first.");
- return;
- }
-
- ChooseProgramDialog dialog
- = new ChooseProgramDialog(this, "Choose program to edit", m_programs);
- dialog.setVisible(true);
- Program program = dialog.getProgram();
- dialog.dispose();
-
- if (program == null)
- return;
-
- new EditProgramDialog(this, program, "Edit Program", false);
-
- Program.save(m_programs);
- }
-
- private void cmdDeleteProgram()
- {
- if (m_programs.isEmpty())
- {
- ShowError.msg(this, "No programs, add a program first.");
- return;
- }
-
- ChooseProgramDialog dialog
- = new ChooseProgramDialog(this, "Choose program to delete",
- m_programs);
- dialog.setVisible(true);
- Program program = dialog.getProgram();
- dialog.dispose();
-
- if (program == null)
- return;
-
- if (!m_programs.remove(program))
- System.out.println("cmdDeleteProgram: program was not in list!");
-
- Program.save(m_programs);
- }
-
- private void cmdConnectLocalProgram()
- {
- ChooseProgramDialog dialog
- = new ChooseProgramDialog(this, "Choose program to connect",
- m_programs);
- dialog.setVisible(true);
- Program program = dialog.getProgram();
- dialog.dispose();
-
- if (program == null) // user aborted
- return;
-
- cmdConnectLocalProgram(program);
- }
-
-
- /** @note NOT CURRENTLY USED! */
- private void cmdConnectRemoteProgram()
- {
- int port = 20000;
- String hostname = "localhost";
-
- String remote = m_preferences.get("remote-host-name");
- String name = RemoteProgramDialog.show(this, remote);
- if (name == null) // user aborted
- return;
-
- hostname = name;
- System.out.print("Connecting to HTP program at [" + hostname +
- "] on port " + port + "...");
- System.out.flush();
-
- try
- {
- m_white_socket = new Socket(hostname, port);
- }
- catch (UnknownHostException e)
- {
- ShowError.msg(this, "Unknown host: '" + e.getMessage() + "'");
- System.out.println("\nconnection attempt aborted.");
- return;
- }
- catch (IOException e)
- {
- ShowError.msg(this, "Error creating socket: '"
- + e.getMessage() + "'");
- System.out.println("\nconnection attempt aborted.");
- return;
- }
- System.out.println("connected.");
-
- InputStream in;
- OutputStream out;
- try
- {
- in = m_white_socket.getInputStream();
- out = m_white_socket.getOutputStream();
- }
- catch (IOException e)
- {
- ShowError.msg(this, "Error obtaining socket stream: "
- + e.getMessage());
- m_white = null;
- return;
- }
- m_preferences.put("remote-host-name", hostname);
- connectProgram(in, out);
- }
-
- //------------------------------------------------------------
-
- private void cmdConnectLocalProgram(Program program)
- {
- Runtime runtime = Runtime.getRuntime();
-
- String cmd = program.m_command;
- System.out.println("Executing '" + program.m_name + "':");
- System.out.println("Command = '" + cmd + "'");
- System.out.println("Working directory = '" + program.m_working + "'");
-
- File working = null;
- if (!program.m_working.trim().equals(""))
- {
- ShowError.msg(this,
- "Working directory not implemented! " +
- "Running with no working directory.");
-
-// working = new File(program.m_working);
-// if (!working.isDirectory())
-// {
-// ShowError.msg(this, "Invalid working directory: '"
-// + working.getName() + "'");
-// }
- }
-
- try
- {
- // Create command array with StringUtil::splitArguments
- // because Runtime.exec(String) uses a default StringTokenizer
- // which does not respect ".
- String[] cmdArray = StringUtils.splitArguments(cmd);
- // Make file name absolute, if working directory is not current
- // directory. With Java 1.5, it seems that Runtime.exec succeeds
- // if the relative path is valid from the current, but not from
- // the given working directory, but the process is not usable
- // (reading from its input stream immediately returns
- // end-of-stream)
- if (cmdArray.length > 0)
- {
- File file = new File(cmdArray[0]);
- // Only replace if executable is a path to a file, not
- // an executable in the exec-path
- if (file.exists())
- cmdArray[0] = file.getAbsolutePath();
- }
-
- m_white_process = runtime.exec(cmdArray);
- //m_white_process = runtime.exec(cmdArray, null, workingDirectory);
- //m_white_process = runtime.exec(cmd);
- }
- catch (Throwable e)
- {
- ShowError.msg(this, "Error starting " + program.m_name + ": '"
- + e.getMessage() + "'");
- return;
- }
-
- m_program = program;
- m_preferences.put("is-program-attached", true);
- m_preferences.put("attached-program", program.m_name);
-
- Process proc = m_white_process;
-
- ///////////////////////////////
- /// FIXME: DEBUGING!!! REMOVE!
- Thread blah = new Thread(new StreamCopy(false, proc.getErrorStream(),
- System.out, false));
- blah.start();
- ///////////////////////////////
-
- connectProgram(proc.getInputStream(), proc.getOutputStream());
- }
-
- private void createAnalyzeDialog()
- {
- m_analyzeDialog = new AnalyzeDialog(this, this, m_analyzeCommands,
- m_messageDialogs);
- m_analyzeDialog.addWindowListener(new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- m_analyzeDialog.setVisible(false);
- m_menubar.setAnalyzeVisible(false);
- }
- });
- m_analyzeDialog.setBoardSize(m_guiboard.getBoardSize().width);
- m_analyzeDialog.setSelectedColor(m_tomove);
- }
-
- public void actionDisposeAnalyzeDialog()
- {
- if (m_analyzeDialog != null)
- {
- m_analyzeDialog.dispose();
- m_analyzeDialog = null;
- m_menubar.setAnalyzeVisible(false);
- }
- }
-
- private void connectProgram(InputStream in, OutputStream out)
- {
- m_shell = new HtpShell(this, this);
- m_shell.addWindowListener(new WindowAdapter()
- {
- public void windowClosing(WindowEvent winEvt)
- {
- m_menubar.setShellVisible(false);
- }
- });
- m_white = new HtpController(in, out, m_shell, this);
-
- // get name and version information; block until
- // version is returned.
-
- acquireSemaphore();
- htpName();
- htpVersion(); // releases semaphore when finished.
- acquireSemaphore();
- releaseSemaphore();
-
- m_shell.setTitle("HexGui: [" + m_white_name + " "
- + m_white_version + "] Shell");
-
- // get list of accepted commands; block until
- // this is completed.
- acquireSemaphore();
- htpAnalyzeCommands(); // releases semaphore when finished
- acquireSemaphore();
- releaseSemaphore();
-
- createAnalyzeDialog();
-
- m_toolbar.setProgramConnected(true);
- m_menubar.setProgramConnected(true);
-
- m_shell.setVisible(m_preferences.getBoolean("shell-show-on-connect"));
- m_analyzeDialog.setVisible(m_preferences.getBoolean("analyze-show-on-connect"));
-
- htpBoardsize(m_guiboard.getBoardSize());
-
- // Replay all moves up to the current node.
- replayUpToNode(m_current);
- htpShowboard();
- }
-
- // Replay all moves up to the given node. Do this without changing
- // the current node.
- private void replayUpToNode(Node node)
- {
- Vector path = new Vector();
- while (node != null) {
- path.add(node);
- node = node.getParent();
- }
- m_guiboard.clearAll();
- htpClearBoard();
- for (int i = path.size()-1; i>=0; i--) {
- node = path.elementAt(i);
- if (node.hasMove()) {
- Move move = node.getMove();
- guiPlay(move);
- htpPlay(move);
- }
- if (node.hasSetup()) {
- playSetup(node);
- }
- }
- }
-
- /** Run HTP commands to set up the current board position from
- scratch. This may be necessary when a setup move removes a
- piece, or changes the color of an existing piece, or when
- swap-pieces is played, since there is no valid HTP command to
- do so. */
- private void htpSetUpCurrentBoard()
- {
- htpClearBoard();
- Dimension size = m_guiboard.getBoardSize();
- for (int y = 0; y < size.height; y++) {
- for (int x = 0; x < size.width; x++) {
- HexPoint point = HexPoint.get(x, y);
- HexColor c = m_guiboard.getColor(point);
- if (c == HexColor.BLACK || c == HexColor.WHITE) {
- htpPlay(new Move(point, c));
- }
- }
- }
- }
-
- private void cmdDisconnectProgram()
- {
- if (m_white == null)
- return;
-
- htpQuit();
- try
- {
- if (m_white_process != null)
- {
- m_white_process.waitFor();
- m_white_process = null;
- }
- if (m_white_socket != null)
- {
- m_white_socket.close();
- m_white_socket = null;
- }
- m_white = null;
- m_shell.dispose();
- m_shell = null;
- actionDisposeAnalyzeDialog();
- m_program = null;
- m_menubar.setProgramConnected(false);
- m_toolbar.setProgramConnected(false);
- m_preferences.put("is-program-attached", false);
- }
- catch (Throwable e)
- {
- ShowError.msg(this, "Error: " + e.getMessage());
- }
- }
-
- private void cmdReconnectProgram()
- {
- Program prog = m_program;
- cmdDisconnectProgram();
- cmdConnectLocalProgram(prog);
- }
-
- //------------------------------------------------------------
-
- private void cmdNewGame()
- {
- if (gameChanged() && !askSaveGame())
- return;
-
- String size = m_menubar.getSelectedBoardSize();
- Dimension dim = new Dimension(-1,-1);
- if (size.equals("Other..."))
- {
- size = BoardSizeDialog.show(this, m_guiboard.getBoardSize());
- if (size == null) return;
- }
-
- try
- {
- StringTokenizer st = new StringTokenizer(size);
- int w = Integer.parseInt(st.nextToken());
- st.nextToken();
- int h = Integer.parseInt(st.nextToken());
- dim.setSize(w,h);
- }
- catch (Throwable t)
- {
- ShowError.msg(this, "Size should be in format 'w x h'.");
- return;
- }
-
- if (dim.width < 1 || dim.height < 1)
- {
- ShowError.msg(this, "Invalid board size.");
- }
- else
- {
- m_tomove = HexColor.BLACK;
- m_toolbar.setToMove(m_tomove.toString());
-
- m_root = new Node();
- m_current = m_root;
- m_gameinfo = new GameInfo();
- m_gameinfo.setBoardSize(dim);
- stopClock(HexColor.BLACK);
- stopClock(HexColor.WHITE);
- m_blackClock.setElapsed(0);
- m_whiteClock.setElapsed(0);
- setComment(m_current);
-
- m_file = null;
- resetGameChanged();
- setFrameTitle();
-
- m_guiboard.initSize(dim.width, dim.height);
- m_guiboard.repaint();
-
- m_preferences.put("gui-board-width", dim.width);
- m_preferences.put("gui-board-height", dim.height);
-
- m_toolbar.updateButtonStates(m_current, this);
- m_menubar.updateMenuStates(this);
-
- htpBoardsize(m_guiboard.getBoardSize());
- htpShowboard();
-
- setCursorType();
- }
- }
-
- private boolean cmdSaveGame()
- {
- if (m_file == null)
- m_file = showSaveAsDialog();
-
- if (m_file != null)
- {
- System.out.println("Saving to file: " + m_file.getName());
- if (save(m_file))
- {
- resetGameChanged();
- setFrameTitle();
- m_preferences.put("path-save-game", m_file.getPath());
- return true;
- }
- }
- return false;
- }
-
- private boolean cmdSaveGameAs()
- {
- File file = showSaveAsDialog();
- if (file == null)
- return false;
-
- m_file = file;
- return cmdSaveGame();
- }
-
- private void cmdSavePositionAs()
- {
- File file = showSaveAsDialog();
- if (file != null)
- savePosition(file);
- }
-
- private void cmdLoadGame()
- {
- if (gameChanged() && !askSaveGame())
- return;
- File file = showOpenDialog();
- if (file != null)
- loadGame(file);
- }
-
- private void cmdPrintPreview()
- {
- JFrame frame = new JFrame();
- //frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- Container con = frame.getContentPane();
-
- PrintPreview pp = new PrintPreview(m_guiboard);
- con.add(pp, BorderLayout.CENTER);
-
- frame.pack();
- frame.setVisible(true);
- frame.toFront();
- }
-
- private void cmdPrint()
- {
- Print.run(this, m_guiboard);
- }
-
- private void cmdAbout()
- {
- m_about.setVisible(true);
- }
-
- //------------------------------------------------------------
-
- private void cmdGuiToolbarVisible()
- {
- boolean visible = m_menubar.getToolbarVisible();
- m_toolbar.setVisible(visible);
- }
-
- private void cmdGuiShellVisible()
- {
- if (m_shell == null) return;
- boolean visible = m_menubar.getShellVisible();
- m_shell.setVisible(visible);
- }
-
- private void cmdGuiAnalyzeVisible()
- {
- if (m_analyzeDialog == null) return;
- boolean visible = m_menubar.getAnalyzeVisible();
- m_analyzeDialog.setVisible(visible);
- }
-
- private void cmdGuiBoardDrawType()
- {
- String type = m_menubar.getCurrentBoardDrawType();
- System.out.println(type);
- m_guiboard.setDrawType(type);
- m_guiboard.repaint();
- }
-
- private void cmdGuiBoardOrientation()
- {
- String type = m_menubar.getCurrentBoardOrientation();
- System.out.println(type);
- m_guiboard.setOrientation(type);
- m_guiboard.repaint();
- }
-
- private void cmdClearMarks()
- {
- m_guiboard.clearMarks();
- m_guiboard.repaint();
- }
-
- private void cmdShowPreferences()
- {
- new PreferencesDialog(this, m_preferences);
- }
-
- /** Toggle the player to move, by explicit user request. This
- also updates the PL property in the current node. */
- private void cmdToggleToMove()
- {
- this.toggleToMove();
- m_current.setPlayerToMove(m_tomove);
- }
-
- /** Toggle the player to move, without setting the PL property */
- private void toggleToMove()
- {
- m_tomove = m_tomove.otherColor();
- m_toolbar.setToMove(m_tomove.toString());
- m_menubar.setToMove(m_tomove.toString());
- setCursorType();
- }
-
- /** Set the player to move, by explicit user request. This
- also updates the PL property in the current node. */
- private void cmdSetToMove()
- {
- this.setToMove();
- m_current.setPlayerToMove(m_tomove);
- }
-
- /** Set the player to move, without setting the PL property */
- private void setToMove()
- {
- m_tomove = HexColor.get(m_menubar.getToMove());
- m_toolbar.setToMove(m_tomove.toString());
- setCursorType();
- }
-
- private void cmdSetupBlack()
- {
- setCursorType();
- }
-
- private void cmdSetupWhite()
- {
- setCursorType();
- }
-
- // Update the cursor according to the current move type.
- public void setCursorType()
- {
- String clickContext = m_toolbar.getClickContext();
- if (clickContext == "black") {
- m_guiboard.setCursorType("black-setup");
- } else if (clickContext == "white") {
- m_guiboard.setCursorType("white-setup");
- } else {
- if (m_tomove == HexColor.BLACK) {
- m_guiboard.setCursorType("black");
- } else {
- m_guiboard.setCursorType("white");
- }
- }
- }
-
- //------------------------------------------------------------
-
- public void actionClearAnalyzeCommand()
- {
-
- }
-
- public void actionSetAnalyzeCommand(AnalyzeCommand command)
- {
- actionSetAnalyzeCommand(command, false, true, true, false);
- }
-
- public void actionSetAnalyzeCommand(AnalyzeCommand command,
- boolean autoRun, boolean clearBoard,
- boolean oneRunOnly,
- boolean reuseTextWindow)
- {
- AnalyzeType type = command.getType();
- if (command.needsPointArg())
- {
- Vector selected = getSelectedCells();
- if (selected.size() < 1)
- {
- m_statusbar.setMessage("Please select a cell before " +
- "running.");
- return;
- }
- command.setPointArg(selected.get(0));
- }
- if (command.needsPointListArg())
- {
- Vector selected = getSelectedCells();
- if (type == AnalyzeType.VC && selected.size() != 2)
- {
- m_statusbar.setMessage("Please select a pair of cells before " +
- "running.");
- return;
- }
- PointList blah = new PointList(selected);
- command.setPointListArg(blah);
- }
- String cmd = command.replaceWildCards(m_tomove);
- String cleaned = StringUtils.cleanWhiteSpace(cmd.trim());
- String args[] = cleaned.split(" ");
- String c = args[0];
- m_curAnalyzeCommand = command;
-
- Runnable cb = null;
- switch(type)
- {
- case GROUP:
- cb = new Runnable() { public void run() { cbGroupGet(); } };
- break;
- case GFX:
- cb = new Runnable() { public void run() { cbGfx(); } };
- break;
- case INFERIOR:
- cb = new Runnable() { public void run() {cbShowInferiorCells();}};
- break;
- case MOVE:
- cb = new Runnable() { public void run() { cbGenMove(); } };
- break;
- case PLIST:
- cb = new Runnable() { public void run() { cbDisplayPointList(); } };
- break;
- case PSPAIRS:
- cb = new Runnable() { public void run() { cbDisplayPointText(); } };
- break;
- case PARAM:
- cb = new Runnable() { public void run() { cbEditParameters(); } };
- break;
- case VC:
- cb = new Runnable() { public void run() { cbVCs(); } };
- break;
- case STRING:
- cb = new Runnable() { public void run() { cbString(); } };
- break;
- case VAR:
- cb = new Runnable() { public void run() { cbVar(); } };
- break;
- }
- // if (c.equals("dfpn-get-bounds"))
- // cb = new Runnable() { public void run() { cbDfpnDisplayBounds();} };
- // else if (c.equals("book-scores"))
- // cb = new Runnable() { public void run() { cbDisplayBookScores(); } };
- // else if (c.equals("eval-resist"))
- // cb = new Runnable() { public void run() { cbEvalResist(); } };
- Runnable callback = null;
- if (cb != null)
- callback = new GuiRunnable(cb);
- sendCommand(cmd + "\n", callback);
- }
-
- /** HtpShell Callback.
- By the name of the command it choose the proper callback function.
- Arguments are passed as given.
- */
- public void commandEntered(String cmd)
- {
- sendCommand(cmd, null);
- }
-
- //----------------------------------------------------------------------
-
- private boolean commandNeedsToLockGUI(String cmd)
- {
- if ((cmd.length() > 7 && cmd.substring(0, 7).equals("genmove")) ||
- (cmd.length() > 15 && cmd.substring(0, 15).equals("dfs-solve-state")) ||
- (cmd.length() > 16 && cmd.substring(0, 16).equals("dfpn-solve-state")) ||
- (cmd.length() > 23 && cmd.substring(0, 23).equals("dfs-solver-find-winning")) ||
- (cmd.length() > 24 && cmd.substring(0, 24).equals("dfpn-solver-find-winning")))
- return true;
- return false;
- }
-
- private void lockGUI()
- {
- m_locked = true;
- m_toolbar.lockToolbar();
- }
-
- private void unlockGUI()
- {
- m_toolbar.unlockToolbar(m_current, this);
- m_locked = false;
- }
-
- /** A (command, callback) pair. */
- private class HtpCommand
- {
- public HtpCommand()
- {
- }
-
- public HtpCommand(String cmd, Runnable callback)
- {
- this.str = cmd;
- this.callback = callback;
- }
-
- public String str;
- public Runnable callback;
- }
-
- /** Waits for commands to be added to the queue, then processes
- each in turn. */
- private class CommandHandler
- implements Runnable
- {
-
- public CommandHandler(Component parent,
- ArrayBlockingQueue queue)
- {
- m_parent = parent;
- m_queue = queue;
- }
-
- public void run()
- {
- while (true)
- {
- HtpCommand cmd = null;
- try
- {
- // block until queue contains an element
- cmd = m_queue.take();
- }
- catch(InterruptedException e)
- {
- System.out.println("INTERRUPTED! HUH?");
- }
-
- if (m_white != null && m_white.connected())
- {
- if (commandNeedsToLockGUI(cmd.str))
- lockGUI();
-
- try {
- m_white.sendCommand(cmd.str);
- if (cmd.callback != null) {
- cmd.callback.run();
- }
- }
- catch (HtpError e) {
- System.out.println("Caught error '"
- + e.getMessage() + "'");
- ShowError.msg(m_parent, e.getMessage());
- }
-
- if (commandNeedsToLockGUI(cmd.str))
- unlockGUI();
- }
- else
- {
- System.out.println("Not sending to disconnected: '"
- + cmd.str.trim() + "'");
- }
- }
- }
-
- Component m_parent;
- ArrayBlockingQueue m_queue;
- }
-
- private void sendCommand(String cmd, Runnable callback)
- {
- if (m_white == null)
- return;
-
- try {
- System.out.println("sendCommand: '" + cmd.trim() + "'");
- m_htp_queue.put(new HtpCommand(cmd, callback));
- }
- catch (InterruptedException e)
- {
- System.out.println("Interrupted while adding!");
- }
- }
-
- // FIXME: add callback?
- private void htpQuit()
- {
- sendCommand("quit\n", null);
- }
-
- private void htpName()
- {
- Runnable cb = new Runnable() { public void run() { cbName(); } };
- sendCommand("name\n", cb);
- }
-
- private void htpVersion()
- {
- Runnable cb = new Runnable() { public void run() { cbVersion(); } };
- sendCommand("version\n", cb);
- }
-
- private void htpAnalyzeCommands()
- {
- Runnable cb = new Runnable()
- { public void run() { cbAnalyzeCommands(); } };
- sendCommand("hexgui-analyze_commands\n", cb);
- }
-
- private void htpClearBoard()
- {
- sendCommand("clear_board\n", null);
- }
-
- private void htpShowboard()
- {
- sendCommand("showboard\n", null);
- }
-
- /** Play a move on the attached HTP backend. This only works if
- * move is a legal move of color black or white. There is no HTP
- * command for setup moves that remove a piece, or that change the
- * color of an already existing piece, and swap, pass, resign, and
- * forfeit moves are possibly not implemented in HTP, or may not
- * be undoable correctly. If the move is swap-pieces, just
- * update HTP to the current board position; so gui should always
- * be updated before calling this. */
- private void htpPlay(Move move)
- {
- if (move.getPoint() == HexPoint.RESIGN
- || move.getPoint() == HexPoint.FORFEIT
- || move.getPoint() == HexPoint.SWAP_SIDES
- || move.getPoint() == HexPoint.PASS) {
- return;
- }
- if (move.getPoint() == HexPoint.SWAP_PIECES) {
- htpSetUpCurrentBoard();
- return;
- }
- sendCommand("play " + move.getColor().toString() +
- " " + move.getPoint().toString() + "\n", null);
- }
-
- /** GUI must already be updated prior to calling this. */
- private void htpUndo(Move move)
- {
- if (move.getPoint() == HexPoint.RESIGN
- || move.getPoint() == HexPoint.FORFEIT
- || move.getPoint() == HexPoint.SWAP_SIDES
- || move.getPoint() == HexPoint.PASS) {
- return;
- }
- sendCommand("undo\n", null);
- }
-
- private void htpGenMove(HexColor color)
- {
- if (! checkBoardSizeSupported())
- return;
- m_statusbar.setMessage(format("{0} is thinking...", m_white_name));
- Runnable callback = new GuiRunnable(new Runnable()
- {
- public void run() { cbGenMove(); }
- });
- sendCommand("genmove " + color.toString() + "\n", callback);
- }
-
- private void htpBoardsize(Dimension size)
- {
- Runnable callback = new Runnable()
- {
- public void run() {
- m_unsupportedBoardSize = ! m_white.wasSuccess();
- checkBoardSizeSupported();
- }
- };
- sendCommand("boardsize " + size.width + " " + size.height + "\n",
- callback);
- m_statusbar.setMessage("New game");
- }
-
- //
- // Callbacks
- //
- public void cbName()
- {
- String str = m_white.getResponse();
- // FIXME: handle errors!
- m_white_name = str.trim();
- }
-
- public void cbVersion()
- {
- String str = m_white.getResponse();
- // FIXME: handle errors!
- m_white_version = str.trim();
- releaseSemaphore();
- }
-
- private void cbAnalyzeCommands()
- {
- String programAnalyzeCommands = m_white.getResponse();
- try
- {
- m_analyzeCommands
- = AnalyzeDefinition.read(programAnalyzeCommands);
- }
- catch (ErrorMessage e)
- {
- ShowError.msg(this, "Could not parse analyze commands!");
- }
- releaseSemaphore();
- }
-
- public void cbGenMove()
- {
- if (!m_white.wasSuccess())
- return;
- m_guiboard.clearMarks();
- String str = m_white.getResponse();
- HexPoint point = HexPoint.get(str.trim());
- if (point == null)
- {
- System.out.println("Invalid move!!");
- }
- else
- {
- play(new Move(point, m_tomove));
- }
- }
-
- public void cbDisplayPointList()
- {
- if (!m_white.wasSuccess())
- return;
- String str = m_white.getResponse();
- Vector points = StringUtils.parsePointList(str);
- m_guiboard.clearMarks();
- for (int i=0; i points = StringUtils.parsePointList(str);
- m_guiboard.clearMarks();
- if (points.size() > 0)
- {
- m_guiboard.setAlphaColor(points.get(0), Color.blue);
- for (int i=1; i > pairs =
- StringUtils.parseStringPairList(fx.substring(inf + 10, text));
- for (int i=0; i vcs = StringUtils.parseVCList(str);
- new VCDisplayDialog(this, m_guiboard, vcs);
- }
-
- public void cbString()
- {
- if (!m_white.wasSuccess())
- return;
- String showText = m_white.getResponse();
- String title = m_curAnalyzeCommand.getResultTitle();
- if (showText != null)
- {
- if (showText.indexOf("\n") < 0)
- {
- if (showText.trim().equals(""))
- showText = "(empty response)";
- m_statusbar.setMessage(format("{0}: {1}", title, showText));
- }
- else
- {
- HexPoint pointArg = null;
- m_showAnalyzeText.show(m_curAnalyzeCommand.getType(),
- pointArg, title, showText, false);
- }
- }
- }
-
- public void cbVar()
- {
- if (!m_white.wasSuccess())
- return;
- String str = m_white.getResponse();
- Vector points = StringUtils.parsePointList(str, " ");
- m_guiboard.clearMarks();
- m_guiboard.aboutToDirtyStones();
- HexColor color = m_tomove;
- for (int i = 0; i < points.size(); i++)
- {
- m_guiboard.setColor(points.get(i), color);
- m_guiboard.setText(points.get(i), Integer.toString(i + 1));
- color = color.otherColor();
- }
- m_guiboard.repaint();
- }
-
- public void cbDisplayPointText()
- {
- if (!m_white.wasSuccess())
- return;
- String str = m_white.getResponse();
- Vector > pairs =
- StringUtils.parseStringPairList(str);
- m_guiboard.clearMarks();
- for (int i=0; i > pairs =
- StringUtils.parseStringPairList(str);
- m_guiboard.clearMarks();
- for (int i=0; i > pairs =
- StringUtils.parseStringPairList(str);
- String res = "";
- String rew = "";
- String reb = "";
- m_guiboard.clearMarks();
- for (int i=0; i 3 && fx.substring(0, 3).equals("uct"))
- guifx_uct(fx.substring(3));
- else if (fx.length() > 2 && fx.substring(0, 2).equals("ab"))
- guifx_ab(fx.substring(2));
- else if (fx.length() > 4 && fx.substring(0, 4).equals("dfpn"))
- guifx_dfpn(fx.substring(4));
- else if (fx.length() > 6 && fx.substring(0, 6).equals("solver"))
- guifx_solver(fx.substring(6));
- }
-
- private void guifx_uct(String fx)
- {
- String[] tk = fx.trim().split(" ");
- int i=0;
-
- m_guiboard.clearMarks();
- m_guiboard.aboutToDirtyStones();
-
- /** @todo Fix this to parse like guifx_ab() and
- guifx_solver(). */
-
- //////////////////////////////////////
- // display variation
- for (; i < tk.length; ++i)
- {
- String s = tk[i].trim();
- if (s.equals("VAR"))
- break;
- }
- if (i == tk.length)
- return;
- ++i; // skip "VAR";
-
- Vector var = new Vector();
- Vector col = new Vector();
- for (; i < tk.length; )
- {
- String s = tk[i].trim();
- if (s.equals("INFLUENCE"))
- break;
- ++i; // skip 'B' and 'W'
-
- col.add((s.charAt(0) == 'B') ? HexColor.BLACK : HexColor.WHITE);
- HexPoint point = HexPoint.get(tk[i++].trim());
- var.add(point);
- }
-
- m_guiboard.setColor(var.get(0), col.get(0));
- m_guiboard.setAlphaColor(var.get(0), Color.cyan);
- if (var.size() > 1)
- {
- m_guiboard.setColor(var.get(1), col.get(1));
- m_guiboard.setAlphaColor(var.get(1), Color.blue);
- }
-
- /////////////////////////////////////////
- // display score/search counts
-
- TreeMap map = new TreeMap();
-
- ++i; // skip 'INFLUENCE'
- for (; i > it = map.entrySet().iterator();
- while(it.hasNext()) {
- Map.Entry e = it.next();
- m_guiboard.setText(e.getKey(), e.getValue());
- }
-
- m_guiboard.repaint();
- m_statusbar.setMessage(fx.substring(fx.indexOf("TEXT")+5));
- }
-
- private void guifx_ab(String fx)
- {
- m_guiboard.clearMarks();
- m_guiboard.aboutToDirtyStones();
-
- int var = fx.indexOf("VAR");
- int label = fx.indexOf("LABEL");
- int text = fx.indexOf("TEXT");
-
- Vector > vr
- = StringUtils.parseVariation(fx.substring(var+3, label));
- if (vr.size() > 0)
- {
- m_guiboard.setColor(vr.get(0).second, vr.get(0).first);
- m_guiboard.setAlphaColor(vr.get(0).second, Color.green);
- if (vr.size() >= 2)
- {
- m_guiboard.setColor(vr.get(1).second, vr.get(1).first);
- m_guiboard.setAlphaColor(vr.get(1).second, Color.red);
- }
- }
- String label_str = fx.substring(label+5, text).trim();
- Vector > labels =
- StringUtils.parseStringPairList(label_str);
- for (int i = 0; i < labels.size(); ++i)
- {
- HexPoint pt = HexPoint.get(labels.get(i).first);
- m_guiboard.setText(pt, labels.get(i).second);
- }
- m_guiboard.repaint();
- m_statusbar.setMessage(fx.substring(text+5));
- }
-
- private void guifx_solver(String fx)
- {
- m_guiboard.clearMarks();
- m_guiboard.aboutToDirtyStones();
- m_statusbar.setProgressVisible(true);
-
- int var = fx.indexOf("VAR");
- int label = fx.indexOf("LABEL");
- int text = fx.indexOf("TEXT");
-
- Vector > vr
- = StringUtils.parseVariation(fx.substring(var+3, label));
- for (int i = 0; i < vr.size(); ++i)
- {
- m_guiboard.setColor(vr.get(i).second, vr.get(i).first);
- m_guiboard.setText(vr.get(i).second, Integer.toString(i+1));
- }
-
- String label_str = fx.substring(label+5, text).trim();
- showInferiorCells(label_str);
-
- String prog_str = fx.substring(text+4).trim();
- String[] levels = prog_str.split(" ");
-
- double contribution = 1.0;
- double progress = 0.0;
- for (int i = 0; i < levels.length; ++i)
- {
- String[] nums = levels[i].trim().split("/");
- int cur = Integer.decode(nums[0]).intValue();
- int max = Integer.decode(nums[1]).intValue();
- progress += contribution*cur/max;
- contribution *= 1.0/max;
- }
- m_guiboard.repaint();
- m_statusbar.setMessage(fx.substring(text+5));
- m_statusbar.setProgress(progress);
- }
-
- private void guifx_dfpn(String fx)
- {
- m_guiboard.clearMarks();
- m_guiboard.aboutToDirtyStones();
-
- int var = fx.indexOf("VAR");
- int label = fx.indexOf("LABEL");
- int text = fx.indexOf("TEXT");
-
- Vector > vr
- = StringUtils.parseVariation(fx.substring(var+3, label));
- for (int i = 0; i < vr.size(); ++i)
- {
- m_guiboard.setColor(vr.get(i).second, vr.get(i).first);
- m_guiboard.setText(vr.get(i).second, Integer.toString(i+1));
- m_guiboard.setAlphaColor(vr.get(i).second, Color.blue);
- }
- String label_str = fx.substring(label+5, text).trim();
- showDfpnBounds(label_str);
-
- m_guiboard.repaint();
- m_statusbar.setMessage(fx.substring(text+5));
- }
-
- private void showDfpnBounds(String str)
- {
- Vector > pairs =
- StringUtils.parseStringPairList(str);
- for (int i = 0; i < pairs.size(); i++)
- {
- HexPoint point = HexPoint.get(pairs.get(i).first);
- String value = pairs.get(i).second;
- m_guiboard.setText(point, value);
- if (value.trim().equals("W"))
- m_guiboard.setAlphaColor(point, Color.green);
- else if (value.trim().equals("L"))
- m_guiboard.setAlphaColor(point, Color.red);
- }
- }
-
- /** Draws the inferior cells to the gui board. */
- private void showInferiorCells(String str)
- {
- Vector > pairs =
- StringUtils.parseStringPairList(str);
- for (int i = 0; i < pairs.size(); i++)
- {
- HexPoint point = HexPoint.get(pairs.get(i).first);
- String value = pairs.get(i).second;
-
- if (value.charAt(0) == 'f') // fill-in
- {
- assert(3 == value.length());
- if (value.charAt(1) == 'd') // dead
- m_guiboard.setAlphaColor(point, Color.cyan);
- else if (value.charAt(1) == 'p') // permanently inferior
- m_guiboard.setAlphaColor(point, Color.gray);
- else // captured
- {
- assert(value.charAt(1) == 'c');
- m_guiboard.setAlphaColor(point, Color.red);
- }
- if (value.charAt(2) == 'b')
- m_guiboard.setColor(point, HexColor.BLACK);
- else
- {
- assert(value.charAt(2) == 'w');
- m_guiboard.setColor(point, HexColor.WHITE);
- }
- }
- else if (value.charAt(0) == 'i') // ignorable
- {
- assert(4 <= value.length());
- if (value.charAt(1) == 'v') // vulnerable
- m_guiboard.setAlphaColor(point, Color.green);
- else if (value.charAt(1) == 'r') // reversible
- m_guiboard.setAlphaColor(point, Color.magenta);
- else // dominated
- {
- assert(value.charAt(1) == 'd');
- m_guiboard.setAlphaColor(point, Color.yellow);
- }
- assert(value.charAt(2) == '[' &&
- value.charAt(value.length()-1) == ']');
- String pts = value.substring(3, value.length()-1);
- Vector pp = StringUtils.parsePointList(pts,"-");
- for (int j=0; j getSelectedCells()
- {
- return m_selected_cells;
- }
-
- public HexColor getColorToMove()
- {
- return m_tomove;
- }
-
- public void humanMove(Move move)
- {
- play(move);
- htpPlay(move);
- htpShowboard();
- if (! m_guiboard.isBoardFull()
- && m_preferences.getBoolean("auto-respond")
- && m_program != null)
- htpGenMove(m_tomove);
- }
-
- /** Update the GUI to reflect the given move. Do this without any
- * changes to the game tree or the HTP. */
- private void guiPlay(Move move)
- {
- if (m_guiboard.isYBoard() && move.getPoint() == HexPoint.SWAP_PIECES) {
- m_guiboard.swapColors();
- } else if (move.getPoint() == HexPoint.SWAP_PIECES) {
- m_guiboard.swapPieces();
- } else {
- m_guiboard.setColor(move.getPoint(),
- move.getColor());
- }
- m_guiboard.clearMarks();
- markLastPlayedStone();
- }
-
- public boolean isSwapAllowed()
- {
- // Count the number of pieces on the board.
- int count = m_guiboard.numberOfPieces();
- // Check whether the game tree allows swapping.
- boolean isswap = m_current.isSwap();
- return count == 1 && !isswap;
- }
-
- private void play(Move move)
- {
- // see if variation already exists; if so, do not add a duplicate
- int variation = -1;
- for (int i=0; i labels = node.getLabels();
- for (int i = 0; i < labels.size(); ++i)
- {
- String lb = labels.get(i);
- String[] strs = lb.split(":");
- HexPoint p = HexPoint.get(strs[0].trim());
- m_guiboard.setText(p, strs[1].trim());
- }
- }
-
- // Play the setup moves of the given node in the Gui, not HTP.
- private void guiPlaySetup(Node node)
- {
- Vector black = node.getSetup(HexColor.BLACK);
- Vector white = node.getSetup(HexColor.WHITE);
- Vector empty = node.getSetup(HexColor.EMPTY);
- for (int j=0; j m_analyzeCommands;
-
- private final MessageDialogs m_messageDialogs =
- new MessageDialogs("HexGui");
-
- private Vector m_selected_cells;
-
- private Program m_program;
- private Vector m_programs;
-
- private ShowAnalyzeText m_showAnalyzeText;
-
- private ArrayBlockingQueue m_htp_queue;
- private Semaphore m_semaphore;
- private HtpController m_white;
- private String m_white_name;
- private String m_white_version;
- private AnalyzeCommand m_curAnalyzeCommand;
- private Process m_white_process;
- private Socket m_white_socket;
-
- private File m_file;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/gui/HtpShell.java b/src/hexgui/gui/HtpShell.java
deleted file mode 100644
index 6f2f142..0000000
--- a/src/hexgui/gui/HtpShell.java
+++ /dev/null
@@ -1,129 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.gui;
-
-import hexgui.hex.*;
-import hexgui.htp.HtpController;
-
-import javax.swing.*;
-import javax.swing.text.*;
-import java.awt.*;
-import java.awt.event.*;
-
-/** Non-modal dialog displaying the communication between HexGui and a
- HTP compatible program. */
-public class HtpShell
- extends JDialog implements ActionListener, HtpController.IOInterface
-{
- public interface Callback
- {
- void commandEntered(String str);
- }
-
- public HtpShell(JFrame owner, Callback callback)
- {
- super(owner, "HexGui: Shell");
- m_callback = callback;
-
- m_editor = new JTextPane();
- m_editor.setEditable(false);
- m_document = m_editor.getStyledDocument();
- addStylesToDocument(m_document);
-
- m_scrollpane = new JScrollPane(m_editor);
- m_scrollpane.setVerticalScrollBarPolicy(
- JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
-
- Dimension size = owner.getSize();
- getContentPane().add(m_scrollpane, BorderLayout.CENTER);
-
- setPreferredSize(new Dimension(400, size.height));
- setMinimumSize(new Dimension(400, 200));
- setLocation(size.width, 0);
-
- m_field = new JTextField();
- m_field.addActionListener(this);
- m_field.setActionCommand("command-entered");
- getContentPane().add(m_field, BorderLayout.SOUTH);
-
- pack();
- }
-
- public void appendText(String text)
- {
- appendText(text, null);
- }
-
- public void appendText(String text, AttributeSet style)
- {
- try {
- m_document.insertString(m_document.getLength(), text, style);
- }
- catch (BadLocationException e) {
- System.out.println("Bad location!");
- }
- }
-
-
- /** HtpController.IOInterface */
- public void sentCommand(String str)
- {
- appendText(str, m_document.getStyle("blue"));
- }
-
- public void receivedResponse(String str)
- {
- appendText(str, m_document.getStyle("bold"));
- }
-
- public void receivedError(String str)
- {
- appendText(str, m_document.getStyle("red"));
- }
-
- protected void addStylesToDocument(StyledDocument doc) {
- Style def = StyleContext.getDefaultStyleContext().
- getStyle(StyleContext.DEFAULT_STYLE);
-
- Style regular = doc.addStyle("regular", def);
- StyleConstants.setFontFamily(def, "Monospaced");
- StyleConstants.setFontSize(def, 12);
-
- Style s = doc.addStyle("italic", regular);
- StyleConstants.setItalic(s, true);
-
- s = doc.addStyle("bold", regular);
- StyleConstants.setBold(s, true);
-
- s = doc.addStyle("blue", regular);
- StyleConstants.setForeground(s, Color.blue);
-
- s = doc.addStyle("red", regular);
- StyleConstants.setForeground(s, Color.RED);
-
- s = doc.addStyle("gray", regular);
- StyleConstants.setForeground(s, Color.gray);
-
- s = doc.addStyle("yellow", regular);
- StyleConstants.setForeground(s, Color.YELLOW);
- }
-
- public void actionPerformed(ActionEvent e)
- {
- String cmd = e.getActionCommand();
- if (cmd.equals("command-entered")) {
- String text = m_field.getText() + "\n";
- m_callback.commandEntered(text);
- m_field.setText(null);
- }
- }
-
- JTextPane m_editor;
- JTextField m_field;
- JScrollPane m_scrollpane;
- StyledDocument m_document;
- Callback m_callback;
-}
-
diff --git a/src/hexgui/gui/MessageDialogs.java b/src/hexgui/gui/MessageDialogs.java
deleted file mode 100644
index f2621b7..0000000
--- a/src/hexgui/gui/MessageDialogs.java
+++ /dev/null
@@ -1,359 +0,0 @@
-// MessageDialogs.java
-
-package hexgui.gui;
-
-import java.awt.Component;
-import java.util.TreeSet;
-import java.util.Set;
-import java.util.prefs.Preferences;
-import javax.swing.Box;
-import javax.swing.JComponent;
-import javax.swing.JCheckBox;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import static hexgui.gui.GuiUtil.insertLineBreaks;
-import hexgui.util.Platform;
-import hexgui.util.PrefUtil;
-import hexgui.util.StringUtils;
-
-/** Simple message dialogs. */
-public final class MessageDialogs
-{
- public MessageDialogs(String applicationName)
- {
- m_applicationName = applicationName;
- }
-
- public void showError(Component frame, String mainMessage,
- String optionalMessage)
- {
- showError(frame, mainMessage, optionalMessage, true);
- }
-
- public void showError(Component frame, String mainMessage,
- String optionalMessage, boolean isCritical)
- {
- int type;
- if (isCritical)
- type = JOptionPane.ERROR_MESSAGE;
- else
- type = JOptionPane.PLAIN_MESSAGE;
- Object[] options = { "Close" };
- Object defaultOption = options[0];
- String title = "Error" + " - " + m_applicationName;
- show(null, frame, title, mainMessage, optionalMessage, type,
- JOptionPane.DEFAULT_OPTION, options, defaultOption, -1);
- }
-
- public void showError(Component frame, String message, Exception e)
- {
- showError(frame, message, e, true);
- }
-
- public void showError(Component frame, String message, Exception e,
- boolean isCritical)
- {
- showError(frame, message, StringUtils.getErrorMessage(e), isCritical);
- }
-
- public void showInfo(Component frame, String mainMessage,
- String optionalMessage, boolean isCritical)
- {
- showInfo(null, frame, mainMessage, optionalMessage, isCritical);
- }
-
- public void showInfo(String disableKey, Component frame,
- String mainMessage, String optionalMessage,
- boolean isCritical)
- {
- if (checkDisabled(disableKey))
- return;
- int type;
- if (isCritical)
- type = JOptionPane.INFORMATION_MESSAGE;
- else
- type = JOptionPane.PLAIN_MESSAGE;
- Object[] options = { "Close" };
- Object defaultOption = options[0];
- String title = "Information" + " - " + m_applicationName;
- show(disableKey, frame, title, mainMessage, optionalMessage,
- type, JOptionPane.DEFAULT_OPTION, options, defaultOption, -1);
- }
-
- public int showYesNoCancelQuestion(Component parent, String mainMessage,
- String optionalMessage,
- String destructiveOption,
- String nonDestructiveOption)
- {
- return showYesNoCancelQuestion(null, parent, mainMessage,
- optionalMessage, destructiveOption,
- nonDestructiveOption);
- }
-
- /** Show a question with two options and cancel.
- @return 0 for the destructive option; 1 for the non-destructive
- option; 2 for cancel */
- public int showYesNoCancelQuestion(String disableKey, Component parent,
- String mainMessage,
- String optionalMessage,
- String destructiveOption,
- String nonDestructiveOption)
- {
- if (checkDisabled(disableKey))
- return 0;
- Object[] options = new Object[3];
- int destructiveIndex;
- if (Platform.isMac())
- {
- options[0] = nonDestructiveOption;
- options[1] = "Cancel";
- options[2] = destructiveOption;
- destructiveIndex = 2;
- }
- else
- {
- options[0] = nonDestructiveOption;
- options[1] = destructiveOption;
- options[2] = "Cancel";
- destructiveIndex = -1;
- }
- Object defaultOption = options[0];
- int type = JOptionPane.QUESTION_MESSAGE;
- String title = "Question" + " - " + m_applicationName;
- Object value = show(disableKey, parent, title, mainMessage,
- optionalMessage, type,
- JOptionPane.YES_NO_CANCEL_OPTION, options,
- defaultOption, destructiveIndex);
- int result;
- if (value == destructiveOption)
- result = 0;
- else if (value == nonDestructiveOption)
- result = 1;
- else
- result = 2;
- return result;
- }
-
- public void showWarning(Component parent, String mainMessage,
- String optionalMessage, boolean isCritical)
- {
- showWarning(null, parent, mainMessage, optionalMessage, isCritical);
- }
-
- public void showWarning(String disableKey, Component parent,
- String mainMessage, String optionalMessage,
- boolean isCritical)
- {
- if (checkDisabled(disableKey))
- return;
- int type;
- if (isCritical)
- type = JOptionPane.WARNING_MESSAGE;
- else
- type = JOptionPane.PLAIN_MESSAGE;
- Object[] options = { "Close" };
- Object defaultOption = options[0];
- String title = "Warning" + " - " + m_applicationName;
- show(disableKey, parent, title, mainMessage, optionalMessage, type,
- JOptionPane.DEFAULT_OPTION, options, defaultOption, -1);
- }
-
- public boolean showQuestion(Component parent, String mainMessage,
- String optionalMessage,
- String destructiveOption, boolean isCritical)
- {
- return showQuestion(null, parent, mainMessage, optionalMessage,
- destructiveOption, isCritical);
- }
-
- public boolean showQuestion(String disableKey, Component parent,
- String mainMessage,
- String optionalMessage,
- String destructiveOption,
- boolean isCritical)
- {
- return showQuestion(disableKey, parent, mainMessage, optionalMessage,
- destructiveOption, "Cancel",
- isCritical);
- }
-
- /** Show warning message to confirm destructive actions.
- @return true, if destructive was chosen; false if cancel was
- chosen. */
- public boolean showQuestion(String disableKey, Component parent,
- String mainMessage,
- String optionalMessage,
- String affirmativeOption,
- String cancelOption,
- boolean isCritical)
- {
- if (checkDisabled(disableKey))
- return true;
- Object[] options = new Object[2];
- if (Platform.isMac())
- {
- options[0] = cancelOption;
- options[1] = affirmativeOption;
- }
- else
- {
- options[0] = affirmativeOption;
- options[1] = cancelOption;
- }
- Object defaultOption = affirmativeOption;
- int type;
- if (isCritical)
- // No reason to show a warning icon for confirmation dialogs
- // of frequent actions
- type = JOptionPane.QUESTION_MESSAGE;
- else
- type = JOptionPane.PLAIN_MESSAGE;
- String title = "Question" + " - " + m_applicationName;
- Object result = show(disableKey, parent, title, mainMessage,
- optionalMessage, type, JOptionPane.YES_NO_OPTION,
- options, defaultOption, -1);
- return (result == affirmativeOption);
- }
-
- public boolean showWarningQuestion(Component parent, String mainMessage,
- String optionalMessage,
- String destructiveOption,
- boolean isCritical)
- {
- return showWarningQuestion(null, parent, mainMessage, optionalMessage,
- destructiveOption, isCritical);
- }
-
- public boolean showWarningQuestion(String disableKey, Component parent,
- String mainMessage,
- String optionalMessage,
- String destructiveOption,
- boolean isCritical)
- {
- return showWarningQuestion(disableKey, parent, mainMessage,
- optionalMessage, destructiveOption,
- "Cancel", isCritical);
- }
-
- /** Show warning message to confirm destructive actions.
- @return true, if destructive was chosen; false if cancel was chosen. */
- public boolean showWarningQuestion(String disableKey, Component parent,
- String mainMessage,
- String optionalMessage,
- String destructiveOption,
- String nonDestructiveOption,
- boolean isCritical)
- {
- if (checkDisabled(disableKey))
- return true;
- Object[] options = new Object[2];
- if (Platform.isMac())
- {
- options[0] = nonDestructiveOption;
- options[1] = destructiveOption;
- }
- else
- {
- options[0] = destructiveOption;
- options[1] = nonDestructiveOption;
- }
- Object defaultOption = nonDestructiveOption;
- int type;
- if (isCritical)
- type = JOptionPane.WARNING_MESSAGE;
- else
- type = JOptionPane.PLAIN_MESSAGE;
- String title = "Warning" + " - " + m_applicationName;
- Object result = show(disableKey, parent, title, mainMessage,
- optionalMessage, type, JOptionPane.YES_NO_OPTION,
- options, defaultOption, -1);
- return (result == destructiveOption);
- }
-
- private final String m_applicationName;
-
- private final Set m_disabled = new TreeSet();
-
- private static void addFiller(JComponent component)
- {
- Box.Filler filler = GuiUtil.createFiller();
- filler.setAlignmentX(Component.LEFT_ALIGNMENT);
- component.add(filler);
- }
-
- private boolean checkDisabled(String disableKey)
- {
- if (disableKey == null)
- return false;
- Preferences prefs =
- PrefUtil.createNode("net/sf/hexgui/gui/messagedialogs/disabled");
- boolean permanentlyDisabled = prefs.getBoolean(disableKey, false);
- if (permanentlyDisabled)
- return true;
- // Make sure this entry exists (right now these settings can only
- // be directly edited in the backing store)
- prefs.putBoolean(disableKey, permanentlyDisabled);
- return m_disabled.contains(disableKey);
- }
-
- private Object show(String disableKey, Component parent, String title,
- String mainMessage, String optionalMessage,
- int messageType, int optionType, Object[] options,
- Object defaultOption, int destructiveIndex)
- {
- if (optionalMessage == null)
- optionalMessage = "";
- boolean isMac = Platform.isMac();
- Box box = Box.createVerticalBox();
-
- String css = GuiUtil.getMessageCss();
-
- JLabel label =
- new JLabel("" + css + "" + insertLineBreaks(mainMessage)
- + ""
- + insertLineBreaks(optionalMessage) + "
");
- label.setAlignmentX(Component.LEFT_ALIGNMENT);
- box.add(label);
-
- addFiller(box);
- addFiller(box);
- JCheckBox disableCheckBox = null;
- if (disableKey != null)
- {
- if (messageType == JOptionPane.QUESTION_MESSAGE)
- disableCheckBox = new JCheckBox("Do not show this message again");
- else if (messageType == JOptionPane.WARNING_MESSAGE)
- disableCheckBox =
- new JCheckBox("Do not show this warning again");
- else
- disableCheckBox =
- new JCheckBox("Do not show this message again");
- disableCheckBox.setToolTipText("Do not show this message again");
- disableCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT);
- box.add(disableCheckBox);
- }
- if (isMac)
- // Don't show icons on Mac, problem with icon generation in
- // Quaqua 3.7.2
- messageType = JOptionPane.PLAIN_MESSAGE;
- JOptionPane optionPane =
- new JOptionPane(box, messageType, optionType, null, options,
- defaultOption);
- if (destructiveIndex >= 0)
- {
- String key = "Quaqua.OptionPane.destructiveOption";
- optionPane.putClientProperty(key,
- Integer.valueOf(destructiveIndex));
- }
- if (isMac && parent.isVisible())
- // Dialogs don't have titles on the Mac
- title = null;
- JDialog dialog = optionPane.createDialog(parent, title);
- dialog.setVisible(true);
- dialog.dispose();
- if (disableKey != null && disableCheckBox.isSelected())
- m_disabled.add(disableKey);
- return optionPane.getValue();
- }
-}
diff --git a/src/hexgui/gui/ParameterDialog.java b/src/hexgui/gui/ParameterDialog.java
deleted file mode 100644
index b2012e7..0000000
--- a/src/hexgui/gui/ParameterDialog.java
+++ /dev/null
@@ -1,430 +0,0 @@
-// ParameterDialog.java
-
-package hexgui.gui;
-
-import java.awt.Component;
-import java.awt.Frame;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.awt.Dimension;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.StringReader;
-import static java.lang.Math.max;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import javax.swing.Box;
-import javax.swing.JDialog;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
-import static javax.swing.JOptionPane.PLAIN_MESSAGE;
-import static javax.swing.JOptionPane.UNINITIALIZED_VALUE;
-import static javax.swing.JOptionPane.VALUE_PROPERTY;
-import javax.swing.JPanel;
-import javax.swing.JSeparator;
-import javax.swing.JTextField;
-import javax.swing.SwingConstants;
-import hexgui.htp.AnalyzeUtil;
-import hexgui.htp.HtpError;
-import hexgui.htp.ParameterType;
-import hexgui.util.ObjectUtil;
-import hexgui.util.StringUtils;
-import hexgui.htp.HtpController;
-
-/** Dialog for editing parameters in response to an analyze command of type
- param. */
-public class ParameterDialog
-{
- public static void editParameters(final String paramCommand, Frame owner,
- String title, String response,
- final HtpController htp,
- final MessageDialogs messageDialogs)
- {
- final ArrayList parameters = parseResponse(response);
- Component mainComponent = createMainComponent(parameters);
- final Object options[] = { "OK", "Cancel" };
- final JOptionPane optionPane =
- new JOptionPane(mainComponent, PLAIN_MESSAGE, OK_CANCEL_OPTION,
- null, options, options[0]);
- final JDialog dialog = new JDialog(owner, title, true);
- dialog.setContentPane(optionPane);
-
- optionPane.addPropertyChangeListener(new PropertyChangeListener() {
- public void propertyChange(PropertyChangeEvent event) {
- String prop = event.getPropertyName();
- if (dialog.isVisible() && event.getSource() == optionPane
- && prop.equals(VALUE_PROPERTY))
- {
- Object value = optionPane.getValue();
- if (ObjectUtil.equals(value, UNINITIALIZED_VALUE))
- return;
- if (ObjectUtil.equals(value, options[0]))
- {
- for (int i = 0; i < parameters.size(); ++i)
- {
- Parameter parameter = parameters.get(i);
- if (! parameter.isChanged())
- continue;
- try
- {
- String command =
- getNewValueCommand(paramCommand,
- parameter);
- htp.sendCommand(command);
- }
- catch (HtpError e)
- {
- showError(dialog, messageDialogs,
- parameter, e);
- optionPane.setValue(UNINITIALIZED_VALUE);
- return;
- }
- }
- }
- dialog.setVisible(false);
- }
- }
- });
- dialog.pack();
- dialog.setLocationByPlatform(true);
- dialog.addWindowListener(new WindowAdapter() {
- public void windowOpened(WindowEvent e) {
- // JDK 1.5 docs require to invoke selectInitialValue after
- // the window is made visible
- optionPane.selectInitialValue();
- } });
- dialog.setVisible(true);
- }
-
- /** Length of a textfield for editing string parameters. */
- private static final int TEXTFIELD_LEN = 13;
-
- private static final int MAX_PARAM_PER_COLUMN = 15;
-
- private abstract static class Parameter
- {
- public Parameter(String key, String value)
- {
- m_key = key;
- m_value = value;
- m_label = StringUtils.capitalize(key.replace('_', ' '));
- }
-
- public String getKey()
- {
- return m_key;
- }
-
- public String getLabel()
- {
- return m_label;
- }
-
- public String getValue()
- {
- return m_value;
- }
-
- public abstract String getNewValue();
-
- public abstract boolean isChanged();
-
- public abstract void createComponents(int gridy, JPanel panel,
- GridBagLayout gridbag);
-
- private final String m_key;
-
- private final String m_label;
-
- private final String m_value;
- }
-
- private static class BoolParameter
- extends Parameter
- {
- public BoolParameter(String key, String value)
- {
- super(key, value);
- try
- {
- m_initialValue = (Integer.parseInt(value) != 0);
- }
- catch (NumberFormatException e)
- {
- m_initialValue = false;
- }
- }
-
- public String getNewValue()
- {
- if (m_checkBox.isSelected())
- return "1";
- return "0";
- }
-
- public boolean isChanged()
- {
- return (m_checkBox.isSelected() != m_initialValue);
- }
-
- public void createComponents(int gridy, JPanel panel,
- GridBagLayout gridbag)
- {
- m_checkBox = new JCheckBox(getLabel(), m_initialValue);
- GridBagConstraints constraints = new GridBagConstraints();
- constraints.gridx = 0;
- constraints.gridy = gridy;
- constraints.gridwidth = GridBagConstraints.REMAINDER;
- constraints.weightx = 1.0;
- constraints.anchor = GridBagConstraints.WEST;
- gridbag.setConstraints(m_checkBox, constraints);
- panel.add(m_checkBox);
- }
-
- private boolean m_initialValue;
-
- private JCheckBox m_checkBox;
- }
-
- private static class ListParameter
- extends Parameter
- {
- public ListParameter(String type, String key, String value)
- {
- super(key, value);
- String[] args = type.split("/");
- assert args[0].equals("list");
- m_items = new String[args.length - 1];
- m_labels = new String[args.length - 1];
- int initialIndex = 0;
- int maxLength = 0;
- for (int i = 1; i < args.length; ++i)
- {
- String item = args[i];
- if (item.equals(value))
- initialIndex = i - 1;
- maxLength = max(item.length(), maxLength);
- m_items[i - 1] = item;
- m_labels[i - 1] =
- StringUtils.capitalize(item.replace('_', ' '));
- }
- m_initialIndex = initialIndex;
- }
-
- public String getNewValue()
- {
- return m_items[m_comboBox.getSelectedIndex()];
- }
-
- public boolean isChanged()
- {
- return (m_comboBox.getSelectedIndex() != m_initialIndex);
- }
-
- public void createComponents(int gridy, JPanel panel,
- GridBagLayout gridbag)
- {
- JLabel label = new JLabel(getLabel() + ":");
- GridBagConstraints constraints = new GridBagConstraints();
- constraints.gridx = 0;
- constraints.gridy = gridy;
- constraints.weightx = 1.0;
- constraints.ipadx = SMALL_PAD;
- constraints.insets = new Insets(SMALL_PAD, 0, 0, 0);
- constraints.anchor = GridBagConstraints.EAST;
- gridbag.setConstraints(label, constraints);
- panel.add(label);
-
- m_comboBox = new JComboBox(m_labels);
- m_comboBox.setSelectedIndex(m_initialIndex);
- constraints = new GridBagConstraints();
- constraints.gridx = 1;
- constraints.gridy = gridy;
- constraints.weightx = 1.0;
- constraints.insets = new Insets(SMALL_PAD, 0, 0, 0);
- constraints.anchor = GridBagConstraints.WEST;
- gridbag.setConstraints(m_comboBox, constraints);
- panel.add(m_comboBox);
- }
-
- private final int m_initialIndex;
-
- private final String[] m_items;
-
- private final String[] m_labels;
-
- private JComboBox m_comboBox;
- }
-
- private static class StringParameter
- extends Parameter
- {
- public StringParameter(String key, String value)
- {
- super(key, value);
- }
-
- public String getNewValue()
- {
- return m_textField.getText().trim();
- }
-
- public boolean isChanged()
- {
- return ! getNewValue().equals(getValue());
- }
-
- public void createComponents(int gridy, JPanel panel,
- GridBagLayout gridbag)
- {
- JLabel label = new JLabel(getLabel() + ":");
- GridBagConstraints constraints = new GridBagConstraints();
- constraints.gridx = 0;
- constraints.gridy = gridy;
- constraints.weightx = 1.0;
- constraints.ipadx = SMALL_PAD;
- constraints.insets = new Insets(SMALL_PAD, 0, 0, 0);
- constraints.anchor = GridBagConstraints.EAST;
- gridbag.setConstraints(label, constraints);
- panel.add(label);
-
- m_textField = new JTextField(TEXTFIELD_LEN);
- m_textField.setText(getValue());
- constraints = new GridBagConstraints();
- constraints.gridx = 1;
- constraints.gridy = gridy;
- constraints.weightx = 1.0;
- constraints.insets = new Insets(SMALL_PAD, 0, 0, 0);
- constraints.anchor = GridBagConstraints.WEST;
- gridbag.setConstraints(m_textField, constraints);
- panel.add(m_textField);
- }
-
- private JTextField m_textField;
- }
-
- private static ArrayList parseResponse(String response)
- {
- ArrayList parameters = new ArrayList();
- BufferedReader reader =
- new BufferedReader(new StringReader(response));
- while (true)
- {
- String line = null;
- try
- {
- line = reader.readLine();
- }
- catch (IOException e)
- {
- }
- if (line == null)
- break;
- AnalyzeUtil.Result result = AnalyzeUtil.parseParameterLine(line);
- if (result == null)
- continue;
- if (result.m_type == ParameterType.BOOL)
- parameters.add(new BoolParameter(result.m_key,
- result.m_value));
- else if (result.m_type == ParameterType.LIST)
- parameters.add(new ListParameter(result.m_typeInfo,
- result.m_key,
- result.m_value));
- else
- // Treat unknown types as string for compatibility with future
- // types
- parameters.add(new StringParameter(result.m_key,
- result.m_value));
- }
- return parameters;
- }
-
- private static Component
- createMainComponent(ArrayList parameters)
- {
- int numberParameters = parameters.size();
- Box outerBox = Box.createHorizontalBox();
- int i = 0;
- int numberColumns = 0;
- JPanel panel = null;
- GridBagLayout gridbag = null;
- int gridy = 0;
- int paramPerColumn =
- (numberParameters + 1)
- / (numberParameters / MAX_PARAM_PER_COLUMN + 1);
- while (i < numberParameters)
- {
- if (i % paramPerColumn == 0)
- {
- if (panel != null)
- {
- if (numberColumns > 0)
- {
- outerBox.add(createFiller());
- outerBox.add(new JSeparator(SwingConstants.VERTICAL));
- outerBox.add(createFiller());
- }
- outerBox.add(panel);
- ++numberColumns;
- }
- gridbag = new GridBagLayout();
- panel = new JPanel(gridbag);
- gridy = 0;
- }
- parameters.get(i).createComponents(gridy, panel, gridbag);
- ++gridy;
- ++i;
- }
- if (panel != null)
- {
- if (numberColumns > 0)
- {
- outerBox.add(createFiller());
- outerBox.add(new JSeparator(SwingConstants.VERTICAL));
- outerBox.add(createFiller());
- }
- outerBox.add(panel);
- }
- return outerBox;
- }
-
- private static String getNewValueCommand(String paramCommand,
- Parameter parameter)
- {
- String key = parameter.getKey();
- String value = parameter.getNewValue();
- return AnalyzeUtil.getParameterCommand(paramCommand, key, value);
- }
-
- private static void showError(JDialog owner, MessageDialogs messageDialogs,
- Parameter parameter, HtpError e)
- {
- String mainMessage =
- MessageFormat.format("Could not change ",
- parameter.getLabel());
- String optionalMessage = StringUtils.capitalize(e.getMessage());
- messageDialogs.showError(owner, mainMessage, optionalMessage);
- }
-
- private static final int SMALL_PAD = 2;
-
- private static final int PAD = 5;
-
- private static final Dimension FILLER_DIMENSION =
- new Dimension(PAD, PAD);
-
- public static Box.Filler createFiller()
- {
- return new Box.Filler(FILLER_DIMENSION, FILLER_DIMENSION,
- FILLER_DIMENSION);
- }
-
-}
diff --git a/src/hexgui/gui/PreferencesDialog.java b/src/hexgui/gui/PreferencesDialog.java
deleted file mode 100644
index dc7c375..0000000
--- a/src/hexgui/gui/PreferencesDialog.java
+++ /dev/null
@@ -1,152 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.gui;
-
-import hexgui.hex.*;
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.*;
-
-/** Dialog for changes user preferences.
- */
-public final class PreferencesDialog
- extends JDialog implements ItemListener, ActionListener
-{
- public PreferencesDialog(Frame owner, GuiPreferences preferences)
- {
- super(owner, true);
-
- m_preferences = preferences;
-
- JPanel generalPanel = createGeneralPanel();
- JPanel boardPanel = createBoardPanel();
- JPanel drawPanel = createDrawPanel();
- JPanel buttonPane = createButtonPanel();
-
- JTabbedPane tabbedPane = new JTabbedPane();
- tabbedPane.addTab("General", null,
- generalPanel,
- "General preferences");
- tabbedPane.addTab("Board", null,
- boardPanel,
- "Board preferences");
- tabbedPane.addTab("Draw", null,
- drawPanel,
- "Drawing preferences");
-
- add(tabbedPane, BorderLayout.CENTER);
- add(buttonPane, BorderLayout.SOUTH);
- pack();
-
- setVisible(true);
- }
-
- public void itemStateChanged(ItemEvent e)
- {
- System.out.println("ItemEvent!");
- Object source = e.getItemSelectable();
-
- }
-
- public void actionPerformed(ActionEvent e)
- {
- String cmd = e.getActionCommand();
- if (cmd.equals("OK")) {
- savePreferences();
- dispose();
- } else if (cmd.equals("Cancel")) {
- dispose();
- }
- }
-
- private void savePreferences()
- {
- System.out.println("Saving preferences...");
-
- m_preferences.put("shell-show-on-connect",
- (showShellOnConnect.getSelectedObjects() != null));
- m_preferences.put("analyze-show-on-connect",
- (showAnalyzeOnConnect.getSelectedObjects() != null));
- m_preferences.put("auto-respond",
- (autoRespond.getSelectedObjects() != null));
-
- }
-
- private JPanel createGeneralPanel()
- {
- JPanel panel = new JPanel();
- panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
-
- showShellOnConnect = createCheckBox("Show Shell on Program Connect",
- "shell-show-on-connect");
-
- showAnalyzeOnConnect = createCheckBox("Show Analyze on Program Connect",
- "analyze-show-on-connect");
-
- autoRespond = createCheckBox("Auto-respond", "auto-respond");
-
- panel.add(showShellOnConnect);
- panel.add(showAnalyzeOnConnect);
- panel.add(autoRespond);
-
- return panel;
- }
-
- private JPanel createDrawPanel()
- {
- JPanel panel = new JPanel();
- panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
-
-// JLabel label;
-
-// label = new JLabel("Field alpha percentage");
-// SpinnerNumberModel model =
-// new SpinnerNumberModel(m_preferences.getDouble("");
-// fieldAlpha = new JSpinner(new );
-
- return panel;
- }
-
-
- private JPanel createBoardPanel()
- {
- JPanel panel = new JPanel(new BorderLayout());
- panel.add(new JLabel("Board stuff"));
- return panel;
- }
-
- private JPanel createButtonPanel()
- {
- JPanel panel = new JPanel();
-
- JButton button = new JButton(" OK ");
- button.addActionListener(this);
- button.setActionCommand("OK");
- panel.add(button);
-
- button = new JButton("Cancel");
- button.addActionListener(this);
- button.setActionCommand("Cancel");
- panel.add(button);
-
- return panel;
- }
-
- private JCheckBox createCheckBox(String name, String prefname)
- {
- JCheckBox box = new JCheckBox(name);
- box.setSelected(m_preferences.getBoolean(prefname));
- box.addItemListener(this);
- return box;
- }
-
- JCheckBox showShellOnConnect, showAnalyzeOnConnect;
- JCheckBox autoRespond;
-
- JSpinner fieldAlpha;
-
- GuiPreferences m_preferences;
-}
-
diff --git a/src/hexgui/gui/Print.java b/src/hexgui/gui/Print.java
deleted file mode 100644
index ab9b247..0000000
--- a/src/hexgui/gui/Print.java
+++ /dev/null
@@ -1,35 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-package hexgui.gui;
-
-import java.awt.Component;
-import java.awt.print.Printable;
-import java.awt.print.PrinterJob;
-
-/** Print a printable. */
-public final class Print
-{
- public static void run(Component parent, Printable printable)
- {
- PrinterJob job = PrinterJob.getPrinterJob();
- job.setPrintable(printable);
- if (! job.printDialog())
- return;
- try
- {
- job.print();
- }
- catch (Exception e)
- {
- System.out.println("Printing failed!");
- }
- }
-
- /** Make constructor unavailable; class is for namespace only. */
- private Print()
- {
- }
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/gui/Program.java b/src/hexgui/gui/Program.java
deleted file mode 100644
index 5101dc9..0000000
--- a/src/hexgui/gui/Program.java
+++ /dev/null
@@ -1,87 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.gui;
-
-import hexgui.util.PrefUtil;
-
-import java.util.Vector;
-import java.util.prefs.Preferences;
-
-/** Hex playing Program. */
-public class Program
-{
- public String m_name;
- public String m_command;
- public String m_working;
-
- public Program()
- {
- }
-
- public Program(String name, String command, String working)
- {
- m_name = name;
- m_command = command;
- m_working = working;
- }
-
- public String toString()
- {
- return m_name;
- }
-
- //------------------------------------------------------------------------
-
- public static Vector load()
- {
- Vector programs = new Vector();
- Preferences prefs = PrefUtil.getNode("hexgui/gui/program");
- if (prefs == null)
- return programs;
- int size = prefs.getInt("size", 0);
- for (int i = 0; i < size; ++i)
- {
- prefs = PrefUtil.getNode("hexgui/gui/program/" + i);
- if (prefs == null)
- break;
- String name = prefs.get("name", "");
- String version = prefs.get("version", "");
- String command = prefs.get("command", "");
- String workingDirectory = prefs.get("working-directory", "");
- programs.add(new Program(name, command, workingDirectory));
- }
- return programs;
- }
-
- public static void save(Vector programs)
- {
- Preferences prefs = PrefUtil.createNode("hexgui/gui/program");
- if (prefs == null)
- return;
- prefs.putInt("size", programs.size());
- for (int i = 0; i < programs.size(); ++i)
- {
- prefs = PrefUtil.createNode("hexgui/gui/program/" + i);
- if (prefs == null)
- break;
- Program p = programs.get(i);
- prefs.put("name", p.m_name);
- prefs.put("command", p.m_command);
- prefs.put("working-directory", p.m_working);
- }
- }
-
- public static Program findWithName(String name, Vector programs)
- {
- for (int i=0; ihstring.
-*/
-public final class TextViewer
- extends JDialog
-{
- /** Callback for events generated by TextViewer. */
- public interface Listener
- {
- /** Callback if some text is selected.
- If text is unselected again this function will be called
- with the complete text content of the window.
- */
- void textSelected(String text);
- }
-
- public TextViewer(Frame owner, String title, String text,
- boolean highlight, Listener listener)
- {
- super(owner, title);
- initialize(text, highlight, listener);
- }
-
- public TextViewer(Dialog owner, String title, String text,
- boolean highlight, Listener listener)
- {
- super(owner, title);
- initialize(text, highlight, listener);
- }
-
- public void setText(String title, String text, boolean highlight)
- {
- setTitle(title);
- insertText(text);
- if (highlight)
- doSyntaxHighlight();
- }
-
- private JTextPane m_textPane;
-
- private Listener m_listener;
-
- private void insertText(String text)
- {
- Document doc = m_textPane.getDocument();
- while (text.charAt(text.length() - 1) == '\n')
- text = text.substring(0, text.length() - 1);
- try
- {
- doc.remove(0, doc.getLength());
- doc.insertString(0, text, null);
- }
- catch (BadLocationException e)
- {
- assert false;
- }
- }
-
- private void doSyntaxHighlight()
- {
- GuiUtil.addStyle(m_textPane, "title", null, null, true);
- GuiUtil.addStyle(m_textPane, "point", new Color(0.25f, 0.5f, 0.7f));
- GuiUtil.addStyle(m_textPane, "number", new Color(0f, 0.54f, 0f));
- GuiUtil.addStyle(m_textPane, "const", new Color(0.8f, 0f, 0f));
- GuiUtil.addStyle(m_textPane, "color", new Color(0.54f, 0f, 0.54f));
- m_textPane.setEditable(true);
- highlight("number", "\\b-?\\d+\\.?\\d*([Ee][+-]\\d+)?\\b");
- highlight("const", "\\b[A-Z_][A-Z_]+[A-Z]\\b");
- highlight("color",
- "\\b([Bb][Ll][Aa][Cc][Kk]|[Ww][Hh][Ii][Tt][Ee])\\b");
- highlight("point", "\\b([Pp][Aa][Ss][Ss]|[A-Ta-t](1\\d|[1-9]))\\b");
- highlight("title", "^\\S+:(\\s|$)");
- m_textPane.setEditable(false);
- }
-
- private void highlight(String styleName, String regex)
- {
- Document doc = m_textPane.getDocument();
- Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
- try
- {
- CharSequence text = doc.getText(0, doc.getLength());
- Matcher matcher = pattern.matcher(text);
- while (matcher.find())
- {
- int start = matcher.start();
- int end = matcher.end();
- GuiUtil.setStyle(m_textPane, start, end - start, styleName);
- }
- }
- catch (BadLocationException e)
- {
- assert false;
- }
- }
-
- private void initialize(String text, boolean highlight, Listener listener)
- {
- m_listener = listener;
- JPanel panel = new JPanel(new BorderLayout());
- Container contentPane = getContentPane();
- contentPane.add(panel, BorderLayout.CENTER);
- m_textPane = new JTextPane();
- GuiUtil.setMonospacedFont(m_textPane);
- insertText(text);
- JScrollPane scrollPane = new JScrollPane(m_textPane);
- panel.add(scrollPane, BorderLayout.CENTER);
- setDefaultCloseOperation(DISPOSE_ON_CLOSE);
- KeyListener keyListener = new KeyAdapter()
- {
- public void keyReleased(KeyEvent e)
- {
- int c = e.getKeyCode();
- if (c == KeyEvent.VK_ESCAPE)
- dispose();
- }
- };
- m_textPane.addKeyListener(keyListener);
- CaretListener caretListener = new CaretListener()
- {
- public void caretUpdate(CaretEvent event)
- {
- if (m_listener == null)
- return;
- int start = m_textPane.getSelectionStart();
- int end = m_textPane.getSelectionEnd();
- Document doc = m_textPane.getDocument();
- try
- {
- if (start == end)
- {
- String text = doc.getText(0, doc.getLength());
- m_listener.textSelected(text);
- return;
- }
- String text = doc.getText(start, end - start);
- m_listener.textSelected(text);
- }
- catch (BadLocationException e)
- {
- assert false;
- }
- }
- };
- m_textPane.addCaretListener(caretListener);
- if (highlight)
- doSyntaxHighlight();
- m_textPane.setCaretPosition(0);
- m_textPane.setEditable(false);
- packTextViewer();
- }
-
- private void packTextViewer()
- {
- pack();
- // Workaround for problems with oversized windows on some platforms
- // Also increase width by 10%, because automatic computation of
- // JTextPane/JTextArea width according to content text does not
- // work (maybe related to Sun Bug 4829215)
- Dimension size = getSize();
- size.width *= 1.1;
- Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
- int maxHeight = (int)(0.9 * screenSize.height);
- int maxWidth = (int)(0.9 * screenSize.width);
- if (size.height > maxHeight || size.width > maxWidth)
- {
- size.width = Math.min(size.width, maxWidth);
- size.height = Math.min(size.height, maxHeight);
- }
- setMinimumSize(new Dimension(128, 96));
- size.height = Math.max(size.height, 96);
- size.width = Math.max(size.width, 128);
- setPreferredSize(size);
- setSize(size);
- }
-}
diff --git a/src/hexgui/gui/VCDisplayDialog.java b/src/hexgui/gui/VCDisplayDialog.java
deleted file mode 100644
index 2e1119c..0000000
--- a/src/hexgui/gui/VCDisplayDialog.java
+++ /dev/null
@@ -1,100 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.gui;
-
-import hexgui.hex.*;
-import hexgui.htp.HtpController;
-
-import javax.swing.*;
-import javax.swing.text.*;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.event.ListSelectionEvent;
-
-import java.awt.*;
-import java.awt.event.*;
-
-import java.util.*;
-
-//----------------------------------------------------------------------------
-
-/** Non-modal dialog displaying list of VCs. Clicking on a vc displays
- it to the given GuiBoard. */
-public class VCDisplayDialog
- extends JDialog implements ListSelectionListener,
- FocusListener
-{
- public VCDisplayDialog(JFrame owner, GuiBoard board, Vector vcs)
- {
- super(owner, "HexGui: VCs");
-
- addWindowListener(new WindowAdapter()
- {
- public void windowClosing(WindowEvent winEvt) {
- dispose();
- }
- });
-
- m_guiboard = board;
-
- JPanel panel = new JPanel();
- panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
-
- m_list = new JList();
- m_list.addFocusListener(this);
- m_list.addListSelectionListener(this);
- m_list.setDragEnabled(false);
- m_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-
- m_scrollpane = new JScrollPane(m_list);
- m_scrollpane.setVerticalScrollBarPolicy(
- JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
-
- panel.add(m_scrollpane);
- add(panel);
-
- pack();
-
- Dimension size = owner.getSize();
- setLocation(0, size.height);
-
- setVCs(vcs);
- setVisible(true);
- }
-
- public void setVCs(Vector vcs)
- {
- m_vcs = vcs;
- m_list.setListData(vcs);
- }
-
- public void valueChanged(ListSelectionEvent e)
- {
- if (m_list.isSelectionEmpty())
- return;
-
- VC vc = m_vcs.get(m_list.getSelectedIndex());
- if (vc.getType().equals("softlimit")) // do nothing on this
- return;
- m_guiboard.clearMarks();
- m_guiboard.displayVC(vc);
- m_guiboard.repaint();
- }
-
- public void focusGained(FocusEvent e)
- {
- }
-
- public void focusLost(FocusEvent e)
- {
- m_list.clearSelection();
- }
-
- private JList m_list;
- private JScrollPane m_scrollpane;
- private Vector m_vcs;
- private GuiBoard m_guiboard;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/hex/ConstPointList.java b/src/hexgui/hex/ConstPointList.java
deleted file mode 100644
index e70b203..0000000
--- a/src/hexgui/hex/ConstPointList.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// ConstPointList.java
-
-package hexgui.hex;
-
-import java.util.Iterator;
-
-/** Const functions of go.PointList.
- @see PointList */
-public interface ConstPointList
- extends Iterable
-{
- boolean contains(Object elem);
-
- boolean equals(Object object);
-
- HexPoint get(int index);
-
- int hashCode();
-
- boolean isEmpty();
-
- Iterator iterator();
-
- int size();
-
- String toString();
-}
diff --git a/src/hexgui/hex/HexColor.java b/src/hexgui/hex/HexColor.java
deleted file mode 100644
index bd19fe5..0000000
--- a/src/hexgui/hex/HexColor.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package hexgui.hex;
-
-/** Possible states of a cell on a Hex board (black, white, or empty). */
-public final class HexColor
-{
- public static final HexColor EMPTY;
- public static final HexColor WHITE;
- public static final HexColor BLACK;
-
- /** Returns a string representation of this color.
- @return "black", "white", or "empty".
- */
- public String toString()
- {
- return m_string;
- }
-
- /** Returns the other opposite color.
- @return WHITE for BLACK, BLACK for WHITE, EMPTY otherwise.
- */
- public HexColor otherColor()
- {
- return m_otherColor;
- }
-
- public static HexColor get(String name)
- {
- if (name.equals("black")) return BLACK;
- if (name.equals("white")) return WHITE;
- if (name.equals("empty")) return EMPTY;
- return null;
- }
-
- private final String m_string;
- private HexColor m_otherColor;
-
- static
- {
- BLACK = new HexColor("black");
- WHITE = new HexColor("white");
- EMPTY = new HexColor("empty");
- BLACK.setOtherColor(WHITE);
- WHITE.setOtherColor(BLACK);
- EMPTY.setOtherColor(EMPTY);
- }
-
- private HexColor(String string)
- {
- m_string = string;
- }
- private void setOtherColor(HexColor color)
- {
- m_otherColor = color;
- }
-}
diff --git a/src/hexgui/hex/HexPoint.java b/src/hexgui/hex/HexPoint.java
deleted file mode 100644
index 838f75d..0000000
--- a/src/hexgui/hex/HexPoint.java
+++ /dev/null
@@ -1,185 +0,0 @@
-package hexgui.hex;
-
-import java.lang.Exception;
-import java.lang.NumberFormatException;
-import java.awt.Dimension;
-
-/** A cell on a Hex board.
- In addition to each playable cell, HexPoints are created for each edge of
- the board and for some special cases like swap moves, resignations, and
- forfeitures. */
-public final class HexPoint implements Comparable
-{
- /** Exception. */
- public static class InvalidHexPointException
- extends Exception
- {
- public InvalidHexPointException(String message)
- {
- super("Invalid point: " + message);
- }
- }
-
- public static final HexPoint NORTH;
- public static final HexPoint SOUTH;
- public static final HexPoint WEST;
- public static final HexPoint EAST;
- public static final HexPoint SWAP_SIDES;
- public static final HexPoint SWAP_PIECES;
- public static final HexPoint PASS;
- public static final HexPoint RESIGN;
- public static final HexPoint FORFEIT;
- public static final HexPoint INVALID;
-
- public static final int MAX_WIDTH = 19;
- public static final int MAX_HEIGHT = 19;
- public static final int MAX_POINTS = MAX_WIDTH*MAX_HEIGHT + 10;
-
- public static final int DEFAULT_SIZE = 11;
-
- private static HexPoint s_points[];
-
- static
- {
- s_points = new HexPoint[MAX_POINTS];
-
- INVALID = s_points[0] = new HexPoint(0, "invalid");
- RESIGN = s_points[1] = new HexPoint(1, "resign");
- FORFEIT = s_points[2] = new HexPoint(2, "forfeit");
- SWAP_SIDES = s_points[3] = new HexPoint(3, "swap-sides");
- SWAP_PIECES = s_points[4] = new HexPoint(4, "swap-pieces");
- PASS = s_points[5] = new HexPoint(5, "pass");
-
- NORTH = s_points[6] = new HexPoint(6, "north");
- EAST = s_points[7] = new HexPoint(7, "east");
- SOUTH = s_points[8] = new HexPoint(8, "south");
- WEST = s_points[9] = new HexPoint(9, "west");
-
- for (int y=0; y= 0);
- assert(i < MAX_POINTS);
- return s_points[i];
- }
-
- /** Returns the point with the given coordinates. Note that it is
- not possible to obtain points for board edges and special
- moves with this method. Use the get(String)
- method for these types of points.
-
- @param x x-coordinate of point
- @param y y-coordinate of point
- @return point with coordinates (x,y).
- */
- public static HexPoint get(int x, int y)
- {
- assert(x >= 0);
- assert(y >= 0);
- assert(x < MAX_WIDTH);
- assert(y < MAX_HEIGHT);
- return s_points[10 + y*MAX_WIDTH + x];
- }
-
- /** Returns the point with the given string representation.
- Valid special moves include: "north", "south", "east", "west"
- "swap-sides", "swap-pieces", "pass", "resign", and "forfeit".
- @param name The name of the point to return
- @return the point or null if name is invalid.
- */
- public static HexPoint get(String name)
- {
- if (name.equalsIgnoreCase("swap"))
- return SWAP_SIDES;
-
- for (int x=0; x= 0;
- }
-
-
-
- public final int x, y;
- private final String m_string;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/hex/Move.java b/src/hexgui/hex/Move.java
deleted file mode 100644
index a7c4067..0000000
--- a/src/hexgui/hex/Move.java
+++ /dev/null
@@ -1,63 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.hex;
-
-//----------------------------------------------------------------------------
-
-/** Move.
- Contains a HexPoint and a HexColor. To construct swap moves or
- other special moves use the appropriate HexPoint. Immutable.
-*/
-public final class Move
-{
- /** Constructs a move with the given point and color.
- @param p location of move
- @param c black or white.
- */
- public Move(HexPoint p, HexColor c)
- {
- m_point = p;
- m_color = c;
- }
-
- /** Convert to string */
- public String toString()
- {
- return "Move(" + m_point + ", " + m_color + ")";
- }
-
- /** Determines whether this move is equal to the given move.
- @param other move to compare it to.
- @return true if points and colors are equal, false otherwise.
- */
- public boolean equals(Move other)
- {
- if (m_point == other.getPoint() && m_color == other.getColor())
- return true;
- return false;
- }
-
- /** Returns the point of this move.
- @return HexPoint of the location.
- */
- public HexPoint getPoint()
- {
- return m_point;
- }
-
- /** Returns the color of the move.
- @return HexColor of the move (WHITE or BLACK or, in case of a
- setup move, sometimes EMPTY).
- */
- public HexColor getColor()
- {
- return m_color;
- }
-
- private final HexPoint m_point;
- private final HexColor m_color;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/hex/PointList.java b/src/hexgui/hex/PointList.java
deleted file mode 100644
index 6e0f7df..0000000
--- a/src/hexgui/hex/PointList.java
+++ /dev/null
@@ -1,130 +0,0 @@
-// PointList.java
-
-package hexgui.hex;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.Vector;
-
-/** List containing points. */
-public final class PointList
- extends ArrayList
- implements ConstPointList
-{
- public class ConstIterator
- implements Iterator
- {
- public boolean hasNext()
- {
- return (m_index < size());
- }
-
- public HexPoint next()
- {
- return get(m_index++);
- }
-
- public void remove()
- {
- throw new UnsupportedOperationException();
- }
-
- private int m_index;
- }
-
- /** Construct empty point list. */
- public PointList()
- {
- this(0);
- }
-
- /** Construct empty point list with initial capacity.
- @param initialCapacity The number of points to reserve memory for. */
- public PointList(int initialCapacity)
- {
- super(initialCapacity);
- }
-
- /** Construct point list with a single element.
- @param p The initial point element. */
- public PointList(HexPoint p)
- {
- this(1);
- add(p);
- }
-
- /** Construct point list as a copy of another point list.
- @param list The list to copy the points from. */
- public PointList(ConstPointList list)
- {
- super((PointList)list);
- }
-
- public PointList(Vector v)
- {
- for (int i = 0; i < v.size(); i++)
- add(v.get(i));
- }
-
- /** Add points of another list at the end of this list. */
- public void addAllFromConst(ConstPointList list)
- {
- addAll((PointList)list);
- }
-
- /** Get an empty constant point list.
- Can be used at places where an empty temporary point list is needed
- that is never modified to avoid memory allocation. */
- public static ConstPointList getEmptyList()
- {
- return EMPTY_LIST;
- }
-
- /** Returns an iterator over the points elements in this list.
- An iterator of type PointList.ConstIterator is returned, which
- does not support Iterator.remove(), to allow for-each-loops for
- ConstPointList references. */
- public Iterator iterator()
- {
- return new ConstIterator();
- }
-
- /** Remove and return last element.
- Requires that list is not empty. */
- public HexPoint pop()
- {
- int index = size() - 1;
- if (index < 0)
- {
- assert false;
- return null;
- }
- HexPoint p = get(index);
- remove(index);
- return p;
- }
-
- public String toString()
- {
- StringBuilder buffer = new StringBuilder();
- for (int i = 0; i < size(); ++i)
- {
- if (i > 0)
- buffer.append(' ');
- buffer.append(get(i));
- }
- return buffer.toString();
- }
-
- /** Convert point list to string.
- Null arguments will be converted to an empty string. */
- public static String toString(ConstPointList list)
- {
- if (list == null)
- return "";
- else
- return list.toString();
- }
-
- private static final ConstPointList EMPTY_LIST = new PointList();
-}
diff --git a/src/hexgui/hex/VC.java b/src/hexgui/hex/VC.java
deleted file mode 100644
index 067570e..0000000
--- a/src/hexgui/hex/VC.java
+++ /dev/null
@@ -1,107 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.hex;
-
-import java.util.Vector;
-
-//----------------------------------------------------------------------------
-
-/**
- VC.
- A connection between two cells.
-*/
-public class VC
-{
- /** Constructs a VC. */
- public VC(HexPoint from, HexPoint to, HexColor c, String type)
- {
- this(from, to, c, type, "unknown", 0,
- new Vector(),
- new Vector(),
- new Vector());
- }
-
- public VC(HexPoint from, HexPoint to,
- HexColor c, String type,
- String source, int moves,
- Vector carrier,
- Vector stones,
- Vector key)
- {
- m_from = from;
- m_to = to;
- m_color = c;
- m_type = type;
- m_source = source;
- m_moves = moves;
- m_carrier = carrier;
- m_stones = stones;
- m_key = key;
- }
-
- public String toString()
- {
- StringBuilder ret = new StringBuilder();
-
- if (m_type.equals("softlimit")) {
- return "---------------- softlimit ----------------";
- }
-
- ret.append(m_from.toString());
- ret.append(" ");
- ret.append(m_to.toString());
- ret.append(" ");
- ret.append(m_color.toString());
- ret.append(" ");
- ret.append(m_type);
- ret.append(" ");
- ret.append(m_source);
- ret.append(" ");
- ret.append(Integer.toString(m_moves));
- ret.append(" ");
-
- ret.append("[");
- for (int i=0; i getCarrier() { return m_carrier; }
- public Vector getStones() { return m_stones; }
- public Vector getKey() { return m_key; }
- public String getSource() { return m_source; }
-
- private HexPoint m_from;
- private HexPoint m_to;
- private HexColor m_color;
- private String m_type;
- private int m_moves;
- private Vector m_carrier;
- private Vector m_stones;
- private Vector m_key;
- private String m_source;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/htp/AnalyzeCommand.java b/src/hexgui/htp/AnalyzeCommand.java
deleted file mode 100644
index d378c79..0000000
--- a/src/hexgui/htp/AnalyzeCommand.java
+++ /dev/null
@@ -1,272 +0,0 @@
-// AnalyzeCommand.java
-
-package hexgui.htp;
-
-import java.io.File;
-import hexgui.hex.ConstPointList;
-import hexgui.hex.HexColor;
-import static hexgui.hex.HexColor.BLACK;
-import static hexgui.hex.HexColor.WHITE;
-import hexgui.hex.HexPoint;
-import hexgui.hex.PointList;
-
-/** Concrete analyze command including data for wildcard replacements.
- See GoGui documentation, chapter "Analyze Commands" */
-public class AnalyzeCommand
-{
- public AnalyzeCommand(AnalyzeDefinition definition)
- {
- m_definition = definition;
- }
-
- public String getLabel()
- {
- return m_definition.getLabel();
- }
-
- public String getCommand()
- {
- return m_definition.getCommand();
- }
-
- public HexColor getColorArg()
- {
- return m_colorArg;
- }
-
- public HexPoint getPointArg()
- {
- return m_pointArg;
- }
-
- public PointList getPointListArg()
- {
- return m_pointListArg;
- }
-
- public AnalyzeType getType()
- {
- return m_definition.getType();
- }
-
- public String getResultTitle()
- {
- StringBuilder buffer = new StringBuilder(getLabel());
- if (needsColorArg() && m_colorArg != null)
- {
- if (m_colorArg == BLACK)
- buffer.append(" Black");
- else
- {
- assert m_colorArg == WHITE;
- buffer.append(" White");
- }
- }
- if (needsPointArg() && m_pointArg != null)
- {
- buffer.append(' ');
- buffer.append(m_pointArg);
- }
- else if (needsPointListArg())
- {
- for (HexPoint p : m_pointListArg)
- {
- buffer.append(' ');
- buffer.append(p);
- }
- }
- if (needsStringArg() && m_stringArg != null)
- {
- buffer.append(' ');
- buffer.append(m_stringArg);
- }
- return buffer.toString();
- }
-
- public boolean isPointArgMissing()
- {
- if (needsPointArg())
- return (m_pointArg == null);
- if (needsPointListArg())
- return m_pointListArg.isEmpty();
- return false;
- }
-
- public boolean isTextType()
- {
- return m_definition.isTextType();
- }
-
- public boolean needsColorArg()
- {
- return m_definition.needsColorArg();
- }
-
- public boolean needsFileArg()
- {
- return m_definition.needsFileArg();
- }
-
- public boolean needsFileOpenArg()
- {
- return m_definition.needsFileOpenArg();
- }
-
- public boolean needsFileSaveArg()
- {
- return m_definition.needsFileSaveArg();
- }
-
- public boolean needsOnlyPointArg()
- {
- return m_definition.needsOnlyPointArg();
- }
-
- public boolean needsOnlyPointAndColorArg()
- {
- return m_definition.needsOnlyPointAndColorArg();
- }
-
- public boolean needsPointArg()
- {
- return m_definition.needsPointArg();
- }
-
- public boolean needsPointListArg()
- {
- return m_definition.needsPointListArg();
- }
-
- public boolean needsStringArg()
- {
- return m_definition.needsStringArg();
- }
-
- public boolean needsOptStringArg()
- {
- return m_definition.needsOptStringArg();
- }
-
- public String replaceWildCards(HexColor toMove)
- {
- String command = m_definition.getCommand();
- String toMoveString = (toMove == BLACK ? "b" : "w");
- String result = command.replace("%m", toMoveString);
- if (needsPointArg() && m_pointArg != null)
- result = result.replace("%p", m_pointArg.toString());
- if (needsPointListArg())
- {
- String pointList = HexPoint.toString(m_pointListArg);
- if (getType() == AnalyzeType.EPLIST
- && m_pointListArg.size() > 0)
- result = result + ' ' + pointList;
- else
- result = result.replace("%P", pointList);
- }
- if (needsFileArg())
- {
- String fileArg = m_fileArg.toString();
- if (fileArg.indexOf(' ') >= 0)
- fileArg = "\"" + fileArg + "\"";
- result = result.replace("%f", fileArg);
- }
- if (needsFileOpenArg())
- {
- String fileOpenArg = m_fileOpenArg.toString();
- if (fileOpenArg.indexOf(' ') >= 0)
- fileOpenArg = "\"" + fileOpenArg + "\"";
- result = result.replace("%r", fileOpenArg);
- }
- if (needsFileSaveArg())
- {
- String fileSaveArg = m_fileSaveArg.toString();
- if (fileSaveArg.indexOf(' ') >= 0)
- fileSaveArg = "\"" + fileSaveArg + "\"";
- result = result.replace("%w", fileSaveArg);
- }
- if (needsStringArg())
- {
- assert m_stringArg != null;
- result = result.replace("%s", m_stringArg);
- }
- if (needsOptStringArg())
- {
- assert m_optStringArg != null;
- result = result.replace("%o", m_optStringArg);
- }
- if (needsColorArg())
- {
- String colorString = "empty";
- if (m_colorArg == BLACK)
- colorString = "b";
- else if (m_colorArg == WHITE)
- colorString = "w";
- result = result.replace("%c", colorString);
- }
- return result;
- }
-
- public void setColorArg(HexColor color)
- {
- assert needsColorArg();
- m_colorArg = color;
- }
-
- public void setFileArg(File file)
- {
- assert needsFileArg();
- m_fileArg = file;
- }
-
- public void setFileOpenArg(File file)
- {
- assert needsFileOpenArg();
- m_fileOpenArg = file;
- }
-
- public void setFileSaveArg(File file)
- {
- assert needsFileSaveArg();
- m_fileSaveArg = file;
- }
-
- public void setPointArg(HexPoint point)
- {
- m_pointArg = point;
- }
-
- public void setPointListArg(ConstPointList pointList)
- {
- m_pointListArg = new PointList(pointList);
- }
-
- public void setStringArg(String value)
- {
- assert needsStringArg();
- m_stringArg = value;
- }
-
- public void setOptStringArg(String value)
- {
- assert needsOptStringArg();
- m_optStringArg = value;
- }
-
- private final AnalyzeDefinition m_definition;
-
- private HexColor m_colorArg;
-
- private File m_fileArg;
-
- private File m_fileOpenArg;
-
- private File m_fileSaveArg;
-
- private String m_optStringArg;
-
- private String m_stringArg;
-
- private HexPoint m_pointArg;
-
- private PointList m_pointListArg = new PointList();
-}
diff --git a/src/hexgui/htp/AnalyzeDefinition.java b/src/hexgui/htp/AnalyzeDefinition.java
deleted file mode 100644
index dda889e..0000000
--- a/src/hexgui/htp/AnalyzeDefinition.java
+++ /dev/null
@@ -1,257 +0,0 @@
-// AnalyzeDefinition.java
-
-package hexgui.htp;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-import java.net.URL;
-import java.util.ArrayList;
-import hexgui.util.ErrorMessage;
-import hexgui.util.StringUtils;
-
-/** Definition of an analyze command.
- See GoGui documentation, chapter "Analyze Commands".
- This class is immutable. */
-public class AnalyzeDefinition
-{
- public AnalyzeDefinition(String line)
- {
- String array[] = line.split("/");
- String typeStr = array[0];
- if (typeStr.equals("bwboard"))
- m_type = AnalyzeType.BWBOARD;
- else if (typeStr.equals("cboard"))
- m_type = AnalyzeType.CBOARD;
- else if (typeStr.equals("dboard"))
- m_type = AnalyzeType.DBOARD;
- else if (typeStr.equals("eplist"))
- m_type = AnalyzeType.EPLIST;
- else if (typeStr.equals("gfx"))
- m_type = AnalyzeType.GFX;
- else if (typeStr.equals("group"))
- m_type = AnalyzeType.GROUP;
- else if (typeStr.equals("hstring"))
- m_type = AnalyzeType.HSTRING;
- else if (typeStr.equals("hpstring"))
- m_type = AnalyzeType.HPSTRING;
- else if (typeStr.equals("inferior"))
- m_type = AnalyzeType.INFERIOR;
- else if (typeStr.equals("move"))
- m_type = AnalyzeType.MOVE;
- else if (typeStr.equals("param"))
- m_type = AnalyzeType.PARAM;
- else if (typeStr.equals("plist"))
- m_type = AnalyzeType.PLIST;
- else if (typeStr.equals("pspairs"))
- m_type = AnalyzeType.PSPAIRS;
- else if (typeStr.equals("pstring"))
- m_type = AnalyzeType.PSTRING;
- else if (typeStr.equals("string"))
- m_type = AnalyzeType.STRING;
- else if (typeStr.equals("sboard"))
- m_type = AnalyzeType.SBOARD;
- else if (typeStr.equals("var"))
- m_type = AnalyzeType.VAR;
- else if (typeStr.equals("varb"))
- m_type = AnalyzeType.VARB;
- else if (typeStr.equals("varc"))
- m_type = AnalyzeType.VARC;
- else if (typeStr.equals("varp"))
- m_type = AnalyzeType.VARP;
- else if (typeStr.equals("varpo"))
- m_type = AnalyzeType.VARPO;
- else if (typeStr.equals("varw"))
- m_type = AnalyzeType.VARW;
- else if (typeStr.equals("vc"))
- m_type = AnalyzeType.VC;
- else
- m_type = AnalyzeType.NONE;
- m_label = array[1];
- m_command = array[2];
- }
-
- public AnalyzeDefinition(AnalyzeType type, String label, String command)
- {
- m_type = type;
- m_label = label;
- m_command = command;
- }
-
- public String getCommand()
- {
- return m_command;
- }
-
- public String getLabel()
- {
- return m_label;
- }
-
- public AnalyzeType getType()
- {
- return m_type;
- }
-
- /** Should the response be shown as text.
- Returns true for types that should be shown (not necessarily only)
- as text to the user.
- That is string and variation commands. */
- public boolean isTextType()
- {
- return m_type == AnalyzeType.STRING
- || m_type == AnalyzeType.HSTRING
- || m_type == AnalyzeType.HPSTRING
- || m_type == AnalyzeType.PSTRING
- || m_type == AnalyzeType.VAR
- || m_type == AnalyzeType.VARC
- || m_type == AnalyzeType.VARW
- || m_type == AnalyzeType.VARB
- || m_type == AnalyzeType.VARP
- || m_type == AnalyzeType.VARPO;
- }
-
- public boolean needsColorArg()
- {
- return (m_command.indexOf("%c") >= 0);
- }
-
- public boolean needsFileArg()
- {
- return (m_command.indexOf("%f") >= 0);
- }
-
- public boolean needsFileOpenArg()
- {
- return (m_command.indexOf("%r") >= 0);
- }
-
- public boolean needsFileSaveArg()
- {
- return (m_command.indexOf("%w") >= 0);
- }
-
- public boolean needsOnlyPointArg()
- {
- return (needsPointArg()
- && ! needsColorArg()
- && ! needsFileArg()
- && ! needsFileOpenArg()
- && ! needsFileSaveArg()
- && ! needsPointListArg()
- && ! needsStringArg()
- && ! needsOptStringArg());
- }
-
- public boolean needsOnlyPointAndColorArg()
- {
- return (needsPointArg() && needsColorArg()
- && ! needsFileArg()
- && ! needsFileOpenArg()
- && ! needsFileSaveArg()
- && ! needsPointListArg()
- && ! needsStringArg()
- && ! needsOptStringArg());
- }
-
- public boolean needsPointArg()
- {
- return (m_command.indexOf("%p") >= 0);
- }
-
- public boolean needsPointListArg()
- {
- return (m_command.indexOf("%P") >= 0 || m_type == AnalyzeType.EPLIST);
- }
-
- public boolean needsStringArg()
- {
- return (m_command.indexOf("%s") >= 0);
- }
-
- public boolean needsOptStringArg()
- {
- return (m_command.indexOf("%o") >= 0);
- }
-
- public static ArrayList
- read(String programAnalyzeCommands)
- throws ErrorMessage
- {
- if (programAnalyzeCommands == null)
- throw new ErrorMessage("no analyze commands!");
-
- Reader stringReader = new StringReader(programAnalyzeCommands);
- BufferedReader reader = new BufferedReader(stringReader);
- return readConfig(reader,
- "program response to hexgui-analyze_commands",
- null);
- }
-
- private final AnalyzeType m_type;
-
- private final String m_label;
-
- private final String m_command;
-
- private static ArrayList
- readConfig(BufferedReader reader, String name,
- ArrayList supportedCommands) throws ErrorMessage
- {
- ArrayList result
- = new ArrayList();
- ArrayList labels = new ArrayList();
- try
- {
- String line;
- int lineNumber = 0;
- while ((line = reader.readLine()) != null)
- {
- ++lineNumber;
- line = line.trim();
- if (line.length() > 0 && line.charAt(0) != '#')
- {
- String array[] = line.split("/");
- if (array.length < 3 || array.length > 5)
- throw new ErrorMessage("Error in " + name + " line "
- + lineNumber);
- if (supportedCommands != null)
- {
- String[] cmdArray
- = StringUtils.splitArguments(array[2].trim());
- if (cmdArray.length == 0
- || ! supportedCommands.contains(cmdArray[0]))
- continue;
- }
- String label = array[1];
- if (labels.contains(label))
- continue;
- labels.add(label);
- result.add(new AnalyzeDefinition(line));
- }
- }
- return result;
- }
- catch (IOException e)
- {
- throw new ErrorMessage("Error reading " + name);
- }
- finally
- {
- try
- {
- reader.close();
- }
- catch (IOException e)
- {
- throw new ErrorMessage("Error reading " + name);
- }
- }
- }
-}
diff --git a/src/hexgui/htp/AnalyzeType.java b/src/hexgui/htp/AnalyzeType.java
deleted file mode 100644
index 47680de..0000000
--- a/src/hexgui/htp/AnalyzeType.java
+++ /dev/null
@@ -1,55 +0,0 @@
-// AnalyzeType.java
-
-package hexgui.htp;
-
-/** Type of an analyze command. */
-public enum AnalyzeType
-{
- BWBOARD,
-
- CBOARD,
-
- DBOARD,
-
- EPLIST,
-
- GFX,
-
- GROUP,
-
- HSTRING,
-
- HPSTRING,
-
- INFERIOR,
-
- MOVE,
-
- NONE,
-
- PARAM,
-
- PLIST,
-
- PSTRING,
-
- PSPAIRS,
-
- STRING,
-
- SBOARD,
-
- VAR,
-
- VARB,
-
- VARC,
-
- VARP,
-
- VARPO,
-
- VARW,
-
- VC
-}
diff --git a/src/hexgui/htp/AnalyzeUtil.java b/src/hexgui/htp/AnalyzeUtil.java
deleted file mode 100644
index 75ec916..0000000
--- a/src/hexgui/htp/AnalyzeUtil.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// AnalyzeUtil.java
-
-package hexgui.htp;
-
-import java.util.ArrayList;
-import java.util.Scanner;
-import java.util.NoSuchElementException;
-
-public final class AnalyzeUtil
-{
- /** Result of AnalyzeUtil.parseParameterLine(). */
- public static final class Result
- {
- public ParameterType m_type;
-
- /** Complete type metainformation. */
- public String m_typeInfo;
-
- public String m_key;
-
- public String m_value;
- }
-
- /** Get command for setting a parameter.
- See chapter "Analyze Commands" of the GoGui documentation. */
- public static String getParameterCommand(String command, String key,
- String value)
- {
- return command + " " + key + " " + value + "\n";
- }
-
- /** Parse a line in the response of an analyze command of type "param".
- See chapter "Analyze Commands" of the GoGui documentation.
- @return The result or null, if line could not be parsed. */
- public static Result parseParameterLine(String line)
- {
- line = line.trim();
- if (line.startsWith("[") && line.endsWith("]"))
- {
- // Might be used as label for grouping parameters on tabbing
- // panes in a later version of GoGui, so we silently accept it
- return null;
- }
- if (line.length() == 0)
- return null;
- Scanner scanner = new Scanner(line);
- Result result = new Result();
- try
- {
- result.m_typeInfo = scanner.next("^\\[[^\\]]*\\]");
- line = line.substring(result.m_typeInfo.length()).trim();
- result.m_typeInfo =
- result.m_typeInfo.substring(1, result.m_typeInfo.length() - 1);
- }
- catch (NoSuchElementException e)
- {
- // Treat unknown types as string for compatibility with future
- // types
- result.m_typeInfo = "string";
- }
- int pos = line.indexOf(' ');
- if (pos < 0)
- {
- result.m_key = line.trim();
- result.m_value = "";
- }
- else
- {
- result.m_key = line.substring(0, pos).trim();
- result.m_value = line.substring(pos + 1).trim();
- }
- if (result.m_typeInfo.equals("bool"))
- result.m_type = ParameterType.BOOL;
- else if (result.m_typeInfo.startsWith("list/"))
- result.m_type = ParameterType.LIST;
- else
- // Treat unknown types as string for compatibility with future
- // types
- result.m_type = ParameterType.STRING;
- return result;
- }
-
- /** Make constructor unavailable; class is for namespace only. */
- private AnalyzeUtil()
- {
- }
-}
diff --git a/src/hexgui/htp/HtpController.java b/src/hexgui/htp/HtpController.java
deleted file mode 100644
index ff9e9c5..0000000
--- a/src/hexgui/htp/HtpController.java
+++ /dev/null
@@ -1,212 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.htp;
-
-import hexgui.hex.HexPoint;
-import hexgui.util.Pair;
-import hexgui.util.StringUtils;
-
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.BufferedReader;
-import java.io.PrintStream;
-import java.io.IOException;
-import java.util.Vector;
-
-//----------------------------------------------------------------------------
-
-/** Sends HTP commands and parses the response. */
-public class HtpController
-{
- public interface IOInterface
- {
- void sentCommand(String str);
- void receivedResponse(String str);
- void receivedError(String str);
- }
-
- //------------------------------------------------------------
-
- public interface GuiFxCallback
- {
- void guifx(String cmd);
- }
-
- //------------------------------------------------------------
-
- /** Constructor */
- public HtpController(InputStream in, OutputStream out,
- IOInterface io, GuiFxCallback guifx)
- {
- System.out.println("controller: in constructor.");
- m_in = new BufferedReader(new InputStreamReader(in));
- m_out = new PrintStream(out);
- m_io = io;
- m_guifx = guifx;
- m_connected = true;
- m_waiting = false;
- }
-
- public void interrupt()
- {
- System.out.println("Sending interrupt");
- m_out.print("# interrupt\n");
- m_out.flush();
- m_io.sentCommand("# interrupt");
- }
-
- /** Sends command over the htp channel.
-
- Note this method is synchronized, and so HtpController will
- process only a single command at a time.
- */
- public synchronized void sendCommand(String cmd)
- throws HtpError
- {
- if (!m_connected)
- return;
-
- System.out.println("controller: sending '" + cmd.trim() + "'");
- m_out.print(cmd);
- m_out.flush();
- m_io.sentCommand(cmd);
- handleResponse();
- }
-
- public boolean cmdInProgress() { return m_waiting; }
-
- public boolean wasSuccess() { return m_success; }
-
- public String getResponse() { return m_response; }
-
- private void handleResponse() throws HtpError
- {
- m_waiting = true;
-
- while (m_waiting) {
-
- String response;
- try {
- response = waitResponse();
- }
- catch (IOException e) {
- m_waiting = false;
- throw new HtpError("IOException waiting for response!");
- }
-
- // Since the response must, by definition of the GTP
- // protocol, always end with two newline characters,
- // remove them.
- response = response.replaceAll("[\n\r]$", "");
-
- //System.out.println("got: '" + response + "'");
-
- if (!m_connected) {
- m_success = false;
- m_response = "";
- m_waiting = false;
- throw new HtpError("Program Disconnected.");
- }
- else if (response == null) {
- m_success = false;
- m_response = "";
- m_waiting = false;
- throw new HtpError("Null response received!");
- } else if (response.length() < 2) {
- m_success = false;
- m_response = response;
- m_waiting = false;
- throw new HtpError("Response length too short! '"+response+"'");
- } else if (response.length() > 10 &&
- response.substring(0, 10).equals("gogui-gfx:"))
- {
-
- String fx
- = StringUtils.cleanWhiteSpace(response.substring(10).trim());
-
- m_guifx.guifx(fx);
-
- } else if (response.substring(0,2).equals("= ")) {
- m_success = true;
- m_response = response.substring(2);
- System.out.print("controller: success: ");
- m_io.receivedResponse(response);
- m_waiting = false;
- } else if (response.substring(0,2).equals("? ")) {
- m_success = false;
- m_response = response.substring(2);
- System.out.print("controller: error: ");
- m_io.receivedError(response);
- m_waiting = false;
- } else {
- m_response = response;
- m_success = false;
- System.out.print("controller: invalid: ");
- m_waiting = false;
- throw new HtpError("Invalid HTP response:'" + response + "'.");
- }
- }
-
- System.out.println("'" + m_response.trim() + "'");
- }
-
- private String waitResponse() throws IOException
- {
- StringBuilder ret = new StringBuilder();
- while (true) {
- //System.out.println("blocking on response");
- String line = m_in.readLine();
- //System.out.println("readline: '" + line + "'");
- if (line == null) {
- System.out.println("controller: Disconnected!");
- m_connected = false;
- break;
- }
- String clean = cleanInput(line);
- ret.append(clean);
- ret.append('\n');
-
- if (clean.equals(""))
- break;
- }
- System.out.println("controller: done waiting on response.");
- return ret.toString();
- }
-
- /** Cleans the input. Removes all occurrences of '\r'.
- Converts all '\t' to ' '.
- */
- private String cleanInput(String in)
- {
- StringBuilder out = new StringBuilder();
- for (int i=0; i();
- m_swap_bug = false;
- try {
- findGameTree();
- m_gametree = parseGameTree(null, true);
- m_reader.close();
- }
- catch (IOException e) {
- throw sgfError("IO error occurred while parsing file.");
- }
- }
-
- public Node getGameTree()
- {
- return m_gametree;
- }
-
- public GameInfo getGameInfo()
- {
- return m_gameinfo;
- }
-
- public Vector getWarnings()
- {
- if (m_warnings.size() == 0)
- return null;
- return m_warnings;
- }
-
- //------------------------------------------------------------
-
- /** Fast forward to the first "(". */
- private void findGameTree() throws SgfError, IOException
- {
- while (true) {
- int ttype = m_tokenizer.nextToken();
- if (ttype == StreamTokenizer.TT_EOF)
- throw sgfError("No game tree found!");
-
- if (ttype == '(') {
- m_tokenizer.pushBack();
- break;
- }
- }
- }
-
- private Node parseGameTree(Node parent, boolean isroot)
- throws SgfError, IOException
- {
- int ttype = m_tokenizer.nextToken();
- if (ttype != '(')
- throw sgfError("Missing '(' at head of game tree.");
-
- Node node = parseNode(parent, isroot);
-
- ttype = m_tokenizer.nextToken();
- if (ttype != ')')
- throw sgfError("Game tree not closed!");
-
- return node;
- }
-
- private Node parseNode(Node parent, boolean isroot)
- throws SgfError, IOException
- {
- int ttype = m_tokenizer.nextToken();
- if (ttype != ';')
- throw sgfError("Error at head of node!");
-
- Node node = new Node();
- node.setParent(parent);
- if (parent != null)
- parent.addChild(node);
-
- boolean done = false;
- while (!done) {
- ttype = m_tokenizer.nextToken();
- switch(ttype) {
- case '(':
- m_tokenizer.pushBack();
- parseGameTree(node, false);
- break;
-
- case ';':
- m_tokenizer.pushBack();
- parseNode(node, false);
- done = true;
- break;
-
- case ')':
- m_tokenizer.pushBack();
- done = true;
- break;
-
- case StreamTokenizer.TT_WORD:
- parseProperty(node, isroot);
- break;
-
- case StreamTokenizer.TT_EOF:
- throw sgfError("Unexpected EOF in node!");
-
- default:
- throw sgfError("Error in SGF file.");
- }
- }
-
- return node;
- }
-
- /** Parse a point or move value.
- Supports both standard SGF notation for Hex (a1, ...) and Go-like
- notation used by Little Golem (aa, ...) */
- private HexPoint parsePoint(String s) throws SgfError
- {
- s = s.trim().toLowerCase(Locale.ENGLISH);
- HexPoint result = null;
- if (s.length() >= 2)
- {
- if (s.length() == 2 && s.charAt(1) >= 'a' && s.charAt(1) <= 'z')
- {
- // Go-like SGF notation
- int x = s.charAt(0) - 'a';
- int y = s.charAt(1) - 'a';
- if (x < HexPoint.MAX_WIDTH && y < HexPoint.MAX_HEIGHT)
- result = HexPoint.get(x, y);
- }
- else
- {
- // Standard SGF notation for Hex
- try
- {
- int x = s.charAt(0) - 'a';
- int y = Integer.parseInt(s.substring(1)) - 1;
- if (y >= 0 && y < HexPoint.MAX_HEIGHT)
- result = HexPoint.get(x, y);
- }
- catch (NumberFormatException e)
- {
- }
- }
- }
- if (result == null)
- throw sgfError(format("Invalid point {0}", s));
- return result;
- }
-
- private HexPoint parseMove(String s) throws SgfError
- {
- s = s.trim().toLowerCase(Locale.ENGLISH);
-
- // Special case: some or all versions of HexGui up to 0.9.GIT
- // incorrectly used "swap-pieces" instead of "swap-sides".
- // The SGF specification states:
- //
- // * swap-sides - the player elects to swap sides with his
- // opponent; if he was playing Black he now plays White, and
- // vice versa.
- //
- // * swap-pieces - the player elects to swap pieces with his
- // opponent - all of Black's pieces are colored White, and
- // White's pieces are colored Black. Then the entire board
- // is reflected in the long diagonal axis.
- //
- // For backward compatibility, we must compensate for the
- // incorrect use of "swap-pieces" when reading SGF files
- // written by HexGui 0.9.GIT or earlier.
-
- if (m_swap_bug && s.equals("swap-pieces")) {
- s = "swap-sides";
- }
-
- // HexPoint.get() handles special move values like "swap"
- HexPoint result = HexPoint.get(s);
- if (result == null)
- // Handles Go-style point notation (aa, ...)
- result = parsePoint(s);
- return result;
- }
-
- private void parseProperty(Node node, boolean isroot)
- throws SgfError, IOException
- {
- int x,y;
- String name = m_tokenizer.sval;
-
- boolean done = false;
- while(!done) {
-
- int ttype = m_tokenizer.nextToken();
- if (ttype != '[') {
- done = true;
- }
- m_tokenizer.pushBack();
- if (done) {
- break;
- }
-
- String val;
- if (name.equals("C")) {
- val = parseComment();
- } else {
- val = parseValue();
- }
- //System.out.println(name + "[" + val + "]");
-
- if (name.equals("W")) {
- HexPoint point = parseMove(val);
- node.setMove(new Move(point, HexColor.WHITE));
- }
- else if (name.equals("B")) {
- HexPoint point = parseMove(val);
- node.setMove(new Move(point, HexColor.BLACK));
- }
- else if (name.equals("AB")) {
- node.addSetup(HexColor.BLACK, parsePoint(val));
- }
- else if (name.equals("AW")) {
- node.addSetup(HexColor.WHITE, parsePoint(val));
- }
- else if (name.equals("AE")) {
- node.addSetup(HexColor.EMPTY, parsePoint(val));
- }
- else if (name.equals("LB")) {
- node.addLabel(val);
- }
- else if (name.equals("FF")) {
- node.setSgfProperty(name, val);
- x = parseInt(val);
- if (x < 1 || x > 4)
- throw sgfError("Invalid SGF Version! (" + x + ")");
- }
- else if (name.equals("GM")) {
- node.setSgfProperty(name, val);
- if (!isroot) sgfWarning("GM property in non-root node!");
- if (parseInt(val) != GM_HEXGAME) throw sgfError("Not a Hex game!");
- }
- else if (name.equals("SZ")) {
- node.setSgfProperty(name, val);
- if (!isroot) sgfWarning("GM property in non-root node!");
- Dimension dim = new Dimension();
- String sp[] = val.split(":");
- if (sp.length == 1) {
- x = parseInt(sp[0]);
- dim.setSize(x,x);
- } else if (sp.length == 2) {
- x = parseInt(sp[0]);
- y = parseInt(sp[1]);
- dim.setSize(x,y);
- } else {
- throw sgfError("Malformed boardsize!");
- }
- m_gameinfo.setBoardSize(dim);
- }
- else if (name.equals("AP")) {
- node.setSgfProperty(name, val);
- String regex = "HexGui:0\\.[0-9](\\z|[^0-9].*)";
- if (val.matches(regex)) {
- // version HexGui:0.9 or earlier
- m_swap_bug = true;
- }
- }
- else {
- node.setSgfProperty(name, val);
- }
- }
- }
-
- // Parse an SGF "SimpleText" property value.
- private String parseValue() throws SgfError, IOException
- {
- int ttype = m_tokenizer.nextToken();
- if (ttype != '[') {
- throw sgfError("Property missing opening '['.");
- }
-
- StringBuilder sb = new StringBuilder(256);
- boolean quoted = false;
- while (true) {
- int ch = m_reader.read();
- if (ch < 0) {
- throw sgfError("Property runs to EOF.");
- }
- // Don't rely on the default conversion, because
- // sb.append(ch) would convert the integer to a string
- // rather than a character.
- char c = (char)ch;
-
- if (!quoted) {
- if (c == ']') {
- break;
- }
- if (c == '\\') {
- quoted = true;
- } else {
- if (Character.isWhitespace(c)) {
- // The spec says "Whitespaces other than space
- // must be converted to space".
- sb.append(' ');
- } else {
- sb.append(c);
- }
- }
- } else {
- quoted = false;
- if (Character.isWhitespace(c)) {
- // The spec says "Any char following "\" is
- // inserted verbatim (exception: whitespaces still
- // have to be converted to space!)."
- sb.append(' ');
- } else {
- sb.append(c);
- }
- }
- }
-
- return sb.toString();
- }
-
- // Parse an SGF "Text" property value.
- private String parseComment() throws SgfError, IOException
- {
- int ttype = m_tokenizer.nextToken();
- if (ttype != '[') {
- throw sgfError("Comment missing opening '['.");
- }
-
- StringBuilder sb = new StringBuilder(4096);
- boolean quoted = false;
- while (true) {
- int ch = m_reader.read();
- if (ch < 0) {
- throw sgfError("Comment runs to EOF.");
- }
- char c = (char)ch;
-
- if (!quoted) {
- if (c == ']') {
- break;
- }
-
- if (c == '\\') {
- quoted = true;
- } else {
- if (Character.isWhitespace(c) && c != '\n') {
- // The spec says "White spaces other than
- // linebreaks are converted to space (e.g. no
- // tab, vertical tab, ..)."
-
- // Also note that the LineNumberReader class
- // already takes care of newline conversion,
- // i.e., "\n", "\r", and "\r\n" are all
- // converted to '\n'.
- sb.append(' ');
- } else {
- sb.append(c);
- }
- }
- } else {
- quoted = false;
- if (c == '\n') {
- // Append nothing. The spec says: "Soft line
- // break: linebreaks preceded by a "\" (soft
- // linebreaks are converted to "", i.e. they are
- // removed)".
- } else if (Character.isWhitespace(c)) {
- // The spec says: "Any char following "\" is
- // inserted verbatim (exception: whitespaces still
- // have to be converted to space!).
- sb.append(' ');
- } else {
- sb.append(c);
- }
- }
- }
-
- return sb.toString();
- }
-
- private int parseInt(String str) throws SgfError
- {
- int ret;
- try {
- ret = Integer.parseInt(str);
- }
- catch (NumberFormatException e) {
- throw sgfError("Error parsing integer.");
- }
- return ret;
- }
-
- //----------------------------------------------------------------------
-
- private void verifyGame(Node root) throws SgfError
- {
- if (m_gameinfo.getBoardSize()==null) {
- throw sgfError("Missing SZ property.");
- }
- }
-
- private SgfError sgfError(String msg)
- {
- return new SgfError("Line " + m_reader.getLineNumber() + ": " + msg);
- }
-
- private void sgfWarning(String msg)
- {
- m_warnings.add("Line " + m_reader.getLineNumber() + ": " + msg);
- }
-
- private StreamTokenizer m_tokenizer;
- private LineNumberReader m_reader;
- private Node m_gametree;
- private GameInfo m_gameinfo;
- private Vector m_warnings;
- private boolean m_swap_bug;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/sgf/SgfWriter.java b/src/hexgui/sgf/SgfWriter.java
deleted file mode 100644
index 05135f3..0000000
--- a/src/hexgui/sgf/SgfWriter.java
+++ /dev/null
@@ -1,177 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.sgf;
-
-import hexgui.version.Version;
-import hexgui.hex.HexColor;
-import hexgui.hex.HexPoint;
-import hexgui.hex.Move;
-import hexgui.game.Node;
-import hexgui.game.GameInfo;
-
-import java.io.*;
-import java.awt.Dimension;
-import java.util.Map;
-import java.util.Iterator;
-import java.util.Vector;
-
-//----------------------------------------------------------------------------
-
-/** SGF Writer.
- See https://www.red-bean.com/sgf/ for the SGF definition.
-*/
-public final class SgfWriter
-{
-
- /** Write a game tree. */
- public SgfWriter(OutputStream out, Node root, GameInfo game)
- {
- m_out = new PrintStream(out);
- m_buffer = new StringBuffer(128);
- m_gameinfo = game;
-
- writeTree(root, true);
- print("\n");
- flushBuffer();
- m_out.flush();
- m_out.close();
- }
-
- private void writeTree(Node root, boolean isroot)
- {
- print("(");
- writeNode(root, isroot);
- print(")");
- }
-
- private void writeNode(Node node, boolean isroot)
- {
- print(";");
-
- if (isroot) {
- String value;
-
- node.setSgfProperty("FF", "4");
- node.setSgfProperty("AP", "HexGui:"+Version.id);
- node.setSgfProperty("GM", "11");
-
- Dimension dim = m_gameinfo.getBoardSize();
- value = Integer.toString(dim.width);
- if (dim.width != dim.height)
- value += ":" + Integer.toString(dim.height);
- node.setSgfProperty("SZ", value);
-
- }
-
- if (node.getMove() != null) {
- printMove(node.getMove());
- }
-
- Map map = node.getProperties();
- Iterator > it = map.entrySet().iterator();
- while(it.hasNext()) {
- Map.Entry e = it.next();
- if (!(e.getKey().equals("C") && e.getValue().equals(""))) {
- String val = e.getValue();
- if (e.getKey().equals("C")) {
- // For now we only escape comments, although there
- // may be other text values that should be escaped
- // too. Avoids escaping the ":" in AP field.
- val = escapeString(val);
- }
- print(e.getKey() + "[" + val + "]");
- }
- }
-
- if (node.hasSetup()) {
- Vector list;
- list = node.getSetup(HexColor.BLACK);
- if (!list.isEmpty()) {
- print("AB");
- printPointList(list);
- }
- list = node.getSetup(HexColor.WHITE);
- if (!list.isEmpty()) {
- print("AW");
- printPointList(list);
- }
- list = node.getSetup(HexColor.EMPTY);
- if (!list.isEmpty()) {
- print("AE");
- printPointList(list);
- }
- }
-
- int num = node.numChildren();
- if (num == 0) return;
-
- if (num == 1) {
- writeNode(node.getChild(), false);
- return;
- }
-
- for (int i=0; i list)
- {
- for (int i=0; i 72) {
- m_out.append(m_buffer.toString());
- m_out.append("\n");
- m_buffer.setLength(0);
- }
- m_buffer.append(str);
- }
-
- private void flushBuffer()
- {
- m_out.append(m_buffer.toString());
- m_buffer.setLength(0);
- }
-
- private PrintStream m_out;
- private StringBuffer m_buffer;
- private GameInfo m_gameinfo;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/util/BoardLayout.java b/src/hexgui/util/BoardLayout.java
deleted file mode 100644
index d3d8995..0000000
--- a/src/hexgui/util/BoardLayout.java
+++ /dev/null
@@ -1,52 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.util;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.*;
-
-public class BoardLayout
- implements LayoutManager
-{
- public void addLayoutComponent(String name, Component comp)
- {
-
- }
-
- public void layoutContainer(Container parent)
- {
- if (parent.getComponentCount() != 1) {
- System.err.println("BoardLayout: needs exactly one component!");
- }
- Dimension size = parent.getSize();
- Insets insets = parent.getInsets();
- size.width -= insets.left + insets.right;
- size.height -= insets.top + insets.bottom;
- int w = size.width;
- int h = size.height;
- //if (h*3/2 > w) h = 2*w/3;
- //if (h*3/2 < w) w = h*3/2;
-
- int x = (size.width - w) / 2;
- int y = (size.height - h) / 2;
- parent.getComponent(0).setBounds(x + insets.left, y + insets.top, w, h);
- }
-
- public Dimension minimumLayoutSize(Container parent)
- {
- return parent.getComponent(0).getMinimumSize();
- }
- public Dimension preferredLayoutSize(Container parent)
- {
- return parent.getComponent(0).getPreferredSize();
- }
-
- public void removeLayoutComponent(Component comp)
- {
-
- }
-
-}
diff --git a/src/hexgui/util/ErrorMessage.java b/src/hexgui/util/ErrorMessage.java
deleted file mode 100644
index ef2200f..0000000
--- a/src/hexgui/util/ErrorMessage.java
+++ /dev/null
@@ -1,17 +0,0 @@
-// ErrorMessage.java
-
-package hexgui.util;
-
-/** Error with error message.
- ErrorMessage are exceptions with a message meaningful for presentation
- to the user. */
-public class ErrorMessage
- extends Exception
-{
- /** Constructor.
- @param message The error message text. */
- public ErrorMessage(String message)
- {
- super(message);
- }
-}
diff --git a/src/hexgui/util/FileUtil.java b/src/hexgui/util/FileUtil.java
deleted file mode 100644
index 5b8dc5d..0000000
--- a/src/hexgui/util/FileUtil.java
+++ /dev/null
@@ -1,175 +0,0 @@
-// FileUtil.java
-
-package hexgui.util;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-
-/** Static file utility functions. */
-public final class FileUtil
-{
- /** Return the file extension of a file name.
- @param file The file.
- @return File extension or null if file name has no extension. */
- public static String getExtension(File file)
- {
- String ext = null;
- String s = file.getName();
- int i = s.lastIndexOf('.');
- if (i > 0 && i < s.length() - 1)
- ext = s.substring(i + 1);
- return ext;
- }
-
- /** Returns relative URI between to files.
- Can be used instead of URI.relativize(), which does not compute
- relative URI's correctly, if toFile is not a subdirectory of fromFile
- (Sun's Java 1.5.0).
- @todo Handle special characters and file names containing slashes.
- @param fromFile File to compute the URI relative to.
- @param toFile Target file or directory.
- @return Relative URI. */
- public static String getRelativeURI(File fromFile, File toFile)
- {
- assert ! fromFile.exists() || ! fromFile.isDirectory();
- fromFile = fromFile.getAbsoluteFile().getParentFile();
- assert fromFile != null;
- ArrayList fromList = splitFile(fromFile);
- ArrayList toList = splitFile(toFile);
- int fromSize = fromList.size();
- int toSize = toList.size();
- int i = 0;
- while (i < fromSize && i < toSize
- && fromList.get(i).equals(toList.get(i)))
- ++i;
- StringBuilder result = new StringBuilder();
- for (int j = i; j < fromSize; ++j)
- result.append("../");
- for (int j = i; j < toSize; ++j)
- {
- result.append(toList.get(j));
- if (j < toSize - 1)
- result.append('/');
- }
- return result.toString();
- }
-
- /** Return URI for file.
- Replacement for File.toURI() with defined (empty) authority. */
- public static URI getURI(File file)
- {
- try
- {
- return new URI("file", "", file.toURI().getPath(), null, null);
- }
- catch (URISyntaxException e)
- {
- return null;
- }
- }
-
- /** Check for extension (case-insensitive). */
- public static boolean hasExtension(File f, String extension)
- {
- String ext = getExtension(f);
- if (ext == null)
- return false;
- return ext.equalsIgnoreCase(extension);
- }
-
- /** Read a list of strings from a file.
- The file is expected to contain one string per line; leading and
- trailing whitespaces are removed. Empty lines or lines beginning
- with the comment character '#' are ignored. */
- public static ArrayList readStringListFromFile(File file)
- throws IOException
- {
- ArrayList result = new ArrayList();
- FileReader reader = new FileReader(file);
- BufferedReader in = new BufferedReader(reader);
- try
- {
- while (true)
- {
- String line = in.readLine();
- if (line == null)
- break;
- line = line.trim();
- if (! line.equals("") && ! line.startsWith("#"))
- result.add(line);
- }
- return result;
- }
- finally
- {
- in.close();
- }
- }
-
- /** Remove extension in file name.
- If the file does not have the extension oldExtension,
- the extension will not be removed. */
- public static String removeExtension(File file, String oldExtension)
- {
- String name = file.toString();
- if (hasExtension(file, oldExtension))
- {
- int index = name.lastIndexOf('.');
- assert index >= 0;
- return name.substring(0, index);
- }
- return name;
- }
-
- /** Replace extension in file name.
- If the file does not have the extension oldExtension,
- the extension will not be replaced but the new extension will be
- appended. */
- public static String replaceExtension(File file, String oldExtension,
- String newExtension)
- {
- String name = file.toString();
- if (hasExtension(file, oldExtension))
- {
- int index = name.lastIndexOf('.');
- assert index >= 0;
- return name.substring(0, index) + "." + newExtension;
- }
- return name + "." + newExtension;
- }
-
- public static String replaceExtension(String file, String oldExtension,
- String newExtension)
- {
- return replaceExtension(new File(file), oldExtension, newExtension);
- }
-
- /** Make constructor unavailable; class is for namespace only. */
- private FileUtil()
- {
- }
-
- private static ArrayList splitFile(File file)
- {
- ArrayList list = new ArrayList();
- file = file.getAbsoluteFile();
- try
- {
- file = file.getCanonicalFile();
- }
- catch (IOException e)
- {
- }
- while (file != null)
- {
- list.add(0, file.getName());
- file = file.getParentFile();
- }
- return list;
- }
-}
diff --git a/src/hexgui/util/Hexagon.java b/src/hexgui/util/Hexagon.java
deleted file mode 100644
index b1ad712..0000000
--- a/src/hexgui/util/Hexagon.java
+++ /dev/null
@@ -1,78 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.util;
-
-import java.awt.*;
-
-//----------------------------------------------------------------------------
-
-/** Creates hexagons. */
-public final class Hexagon
-{
-
- /** Creates a hexagon with flat sides centered at the specified point.
- @param p center of hexagon.
- @param width the width of the hexagon.
- @param height the height of the hexagon.
- @return an instance of Polygon with the above properties.
- */
- public static Polygon
- createVerticalHexagon(Point p, int width, int height)
- {
- int xpoints[] = new int[6];
- int ypoints[] = new int[6];
-
- int sx = width/2;
- int ly = height/2;
- int sy = ly/2;
-
- xpoints[0] = 0; ypoints[0] = -ly;
- xpoints[1] = -sx; ypoints[1] = -sy;
- xpoints[2] = -sx; ypoints[2] = +sy;
- xpoints[3] = 0; ypoints[3] = +ly;
- xpoints[4] = +sx; ypoints[4] = +sy;
- xpoints[5] = +sx; ypoints[5] = -sy;
-
- Polygon ret = new Polygon(xpoints, ypoints, 6);
- ret.translate(p.x, p.y);
-
- return ret;
- }
-
- /** Creates a hexagon with flat top and bottom centered at
- the specified point.
- @param p center of hexagon.
- @param width the width of the hexagon.
- @param height the height of the hexagon.
- @return an instance of Polygon with the above properties.
- */
- public static Polygon
- createHorizontalHexagon(Point p, int width, int height)
- {
- int xpoints[] = new int[6];
- int ypoints[] = new int[6];
-
- int sy = height/2;
- int lx = width/2;
- int sx = lx/2;
-
- xpoints[0] = -lx; ypoints[0] = 0;
- xpoints[1] = -sx; ypoints[1] = +sy;
- xpoints[2] = +sx; ypoints[2] = +sy;
- xpoints[3] = +lx; ypoints[3] = 0;
- xpoints[4] = +sx; ypoints[4] = -sy;
- xpoints[5] = -sx; ypoints[5] = -sy;
-
- Polygon ret = new Polygon(xpoints, ypoints, 6);
- ret.translate(p.x, p.y);
-
- return ret;
- }
-
- /** Private constructor. */
- private Hexagon() {}
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/util/ObjectUtil.java b/src/hexgui/util/ObjectUtil.java
deleted file mode 100644
index a6a3ddc..0000000
--- a/src/hexgui/util/ObjectUtil.java
+++ /dev/null
@@ -1,25 +0,0 @@
-// ObjectUtil.java
-
-package hexgui.util;
-
-/** Utils for using class java.lang.Object. */
-public final class ObjectUtil
-{
- /** Compare including the case that arguments can be null. */
- public static boolean equals(Object object1, Object object2)
- {
- if (object1 == null && object2 == null)
- return true;
- if (object1 == null && object2 != null)
- return false;
- if (object1 != null && object2 == null)
- return false;
- assert object1 != null && object2 != null;
- return object1.equals(object2);
- }
-
- /** Make constructor unavailable; class is for namespace only. */
- private ObjectUtil()
- {
- }
-}
diff --git a/src/hexgui/util/Options.java b/src/hexgui/util/Options.java
deleted file mode 100644
index 32d58b3..0000000
--- a/src/hexgui/util/Options.java
+++ /dev/null
@@ -1,329 +0,0 @@
-package hexgui.util;
-
-import java.io.*;
-import java.util.*;
-
-/** Parser for command line options.
- Options begin with a single '-' character. */
-public class Options
-{
- /** Parse options.
- @param args Command line args from main method
- @param specs Specification of allowed options. Contains option names
- (without '-'). Options that need an argument must have a ':' appended.
- The special argument '--' stops option parsing, all following
- arguments are treated as non-option arguments.
- @throws Exception If options are not valid according to specs. */
- public Options(String[] args, String[] specs) throws Exception
- {
- for (String spec : specs)
- {
- if (spec.length() > 0)
- m_map.put(spec, null);
- }
- parseArgs(args);
- }
-
- /** Check if option is present. */
- public boolean contains(String option)
- {
- String value = get(option, null);
- return (value != null);
- }
-
- /** Return string option value.
- @param option The option key.
- @return The option value or an empty string, if option is not
- present. */
- public String get(String option)
- {
- return get(option, "");
- }
-
- /** Return string option value.
- @param option The option key.
- @param defaultValue The default value.
- @return The option value or defaultValue, if option is not present. */
- public String get(String option, String defaultValue)
- {
- assert isValidOption(option);
- String value = getValue(option);
- if (value == null)
- return defaultValue;
- return value;
- }
-
- /** Get remaining arguments that are not options.
- @return The sequence of non-option arguments. */
- public ArrayList getArguments()
- {
- return m_args;
- }
-
- /** Check that the number of non-option arguments is zero.
- @throws Exception If there are any non-option arguments. */
- public void checkNoArguments() throws Exception
- {
- if (! m_args.isEmpty())
- throw new Exception(
- "Command does not allow arguments that are not options");
- }
-
- /** Parse double option.
- @param option The option key.
- @return The option value or 0, if option is not present.
- @throws Exception If option value is not a double. */
- public double getDouble(String option) throws Exception
- {
- return getDouble(option, 0);
- }
-
- /** Parse double option.
- @param option The option key.
- @param defaultValue The default value.
- @return The option value or defaultValue, if option is not present.
- @throws Exception If option value is not a double. */
- public double getDouble(String option, double defaultValue)
- throws Exception
- {
- String value = get(option, Double.toString(defaultValue));
- if (value == null)
- return defaultValue;
- try
- {
- return Double.parseDouble(value);
- }
- catch (NumberFormatException e)
- {
- throw new Exception("Option -" + option + " needs float value");
- }
- }
-
- /** Parse integer option.
- @param option The option key.
- @return The option value or 0, if option is not present.
- @throws Exception If option value is not an integer. */
- public int getInteger(String option) throws Exception
- {
- return getInteger(option, 0);
- }
-
- /** Parse integer option.
- @param option The option key.
- @param defaultValue The default value.
- @return The option value or defaultValue, if option is not present.
- @throws Exception If option value is not an integer. */
- public int getInteger(String option, int defaultValue) throws Exception
- {
- String value = get(option, Integer.toString(defaultValue));
- if (value == null)
- return defaultValue;
- try
- {
- return Integer.parseInt(value);
- }
- catch (NumberFormatException e)
- {
- throw new Exception("Option -" + option + " needs integer value");
- }
- }
-
- /** Parse integer option with range check.
- @param option The option key.
- @param defaultValue The default value.
- @param min The minimum valid value.
- @return The option value or defaultValue, if option is not present.
- @throws Exception If option value is less than min. */
- public int getInteger(String option, int defaultValue, int min)
- throws Exception
- {
- int value = getInteger(option, defaultValue);
- if (value < min)
- throw new Exception("Option -" + option + " must be greater than "
- + min);
- return value;
- }
-
- /** Parse integer option with range check.
- @param option The option key.
- @param defaultValue The default value.
- @param min The minimum valid value.
- @param max The maximum valid value.
- @return The option value or defaultValue, if option is not present.
- @throws Exception If option value is less than min or greater than
- max. */
- public int getInteger(String option, int defaultValue, int min, int max)
- throws Exception
- {
- int value = getInteger(option, defaultValue);
- if (value < min || value > max)
- throw new Exception("Option -" + option + " must be in ["
- + min + ".." + max + "]");
- return value;
- }
-
- /** Parse long integer option.
- @param option The option key.
- @return The option value or 0, if option is not present.
- @throws Exception If option value is not a long integer. */
- public long getLong(String option) throws Exception
- {
- return getLong(option, 0L);
- }
-
- /** Parse long integer option.
- @param option The option key.
- @param defaultValue The default value.
- @return The option value or defaultValue, if option is not present.
- @throws Exception If option value is not a long integer. */
- public long getLong(String option, long defaultValue) throws Exception
- {
- String value = get(option, Long.toString(defaultValue));
- if (value == null)
- return defaultValue;
- try
- {
- return Long.parseLong(value);
- }
- catch (NumberFormatException e)
- {
- throw new Exception("Option -" + option
- + " needs long integer value");
- }
- }
-
- /** Read options from a file given with the option "config".
- Requires that "config" is an allowed option.
- @throws Exception If options in file are not valid according to
- the specification. */
- public void handleConfigOption() throws Exception
- {
- if (! contains("config"))
- return;
- String filename = get("config");
- InputStream inputStream;
- try
- {
- inputStream = new FileInputStream(filename);
- }
- catch (FileNotFoundException e)
- {
- throw new Exception("File not found: " + filename);
- }
- Reader reader = new InputStreamReader(inputStream);
- BufferedReader bufferedReader = new BufferedReader(reader);
- try
- {
- StringBuilder buffer = new StringBuilder(256);
- String line;
- while (true)
- {
- line = bufferedReader.readLine();
- if (line == null)
- break;
- buffer.append(line);
- buffer.append(' ');
- }
- parseArgs(StringUtils.splitArguments(buffer.toString()));
- }
- catch (IOException e)
- {
- System.err.println(e.getMessage());
- }
- finally
- {
- try
- {
- bufferedReader.close();
- }
- catch (IOException e)
- {
- System.err.println(e.getMessage());
- }
- }
- }
-
- /** Creates a new Options instance from command line.
- Automatically calls handleConfigOption.
- @param args The command line split into arguments.
- @param specs Option specification as in constructor.
- @return The new Options instance.
- @throws Exception If options are not valid according to specs. */
- public static Options parse(String[] args, String[] specs)
- throws Exception
- {
- Options opt = new Options(args, specs);
- opt.handleConfigOption();
- return opt;
- }
-
- private final ArrayList m_args = new ArrayList();
-
- private final Map m_map = new TreeMap();
-
- private String getSpec(String option) throws Exception
- {
- if (m_map.containsKey(option))
- return option;
- else if (m_map.containsKey(option + ":"))
- return option + ":";
- throw new Exception("Unknown option -" + option);
- }
-
- private String getValue(String option)
- {
- assert isValidOption(option);
- if (m_map.containsKey(option))
- return m_map.get(option);
- return m_map.get(option + ":");
- }
-
- private boolean isOptionKey(String s)
- {
- return (s.length() > 0 && s.charAt(0) == '-');
- }
-
- private boolean isValidOption(String option)
- {
- return (m_map.containsKey(option) || m_map.containsKey(option + ":"));
- }
-
- private boolean needsValue(String spec)
- {
- return (spec.length() > 0
- && spec.substring(spec.length() - 1).equals(":"));
- }
-
- private void parseArgs(String args[]) throws Exception
- {
- boolean stopParse = false;
- int n = 0;
- while (n < args.length)
- {
- String s = args[n];
- ++n;
- if (s.equals("--"))
- {
- stopParse = true;
- continue;
- }
- if (isOptionKey(s) && ! stopParse)
- {
- String spec = getSpec(s.substring(1));
- if (needsValue(spec))
- {
- if (n >= args.length)
- throw new Exception("Option " + s + " needs value");
- String value = args[n];
- ++n;
- m_map.put(spec, value);
- }
- else
- m_map.put(spec, "1");
-
- }
- else
- m_args.add(s);
- }
- }
-}
diff --git a/src/hexgui/util/Pair.java b/src/hexgui/util/Pair.java
deleted file mode 100644
index d2e2bf5..0000000
--- a/src/hexgui/util/Pair.java
+++ /dev/null
@@ -1,22 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.util;
-
-//----------------------------------------------------------------------------
-
-/** A pair of two objects. */
-public class Pair
-{
- public E first;
- public F second;
-
- public Pair(E first, F second)
- {
- this.first = first;
- this.second = second;
- }
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/util/Platform.java b/src/hexgui/util/Platform.java
deleted file mode 100644
index d429ae3..0000000
--- a/src/hexgui/util/Platform.java
+++ /dev/null
@@ -1,225 +0,0 @@
-// Platform.java
-
-package hexgui.util;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.net.URL;
-import java.util.Locale;
-
-/** Static utility functions for platform detection and platform-dependent
- behavior. */
-public class Platform
-{
- /** Handler for events from the Application Menu on MacOS. */
- public interface SpecialMacHandler
- {
- /** Handle about menu event.
- @return true if event was handled successfully. */
- boolean handleAbout();
-
- /** Handle open file event.
- @param filename name of file.
- @return true if event was handled successfully. */
- boolean handleOpenFile(String filename);
-
- /** Handle quit application event.
- @return true if event was handled successfully, false if quit
- should be aborted. */
- boolean handleQuit();
- }
-
- public static String getJavaRuntimeName()
- {
- // java.runtime.name is not a standard property
- String name = System.getProperty("java.runtime.name");
- if (name == null)
- name = System.getProperty("java.vm.name");
- return name;
- }
-
- /** Return information on this computer.
- Returns host name and cpu information (if /proc/cpuinfo exists). */
- public static String getHostInfo()
- {
- String info;
- try
- {
- info = InetAddress.getLocalHost().getHostName();
- }
- catch (UnknownHostException e)
- {
- info = "?";
- }
- try
- {
- if (existsProcCpuinfo())
- {
- String[] cmdArray = { "/bin/sh", "-c",
- "grep '^model name' /proc/cpuinfo" };
- String result = ProcessUtil.runCommand(cmdArray);
- int start = result.indexOf(':');
- if (start >= 0)
- {
- info = info + " (";
- int end = result.indexOf("\n");
- if (end >= 0)
- info = info + result.substring(start + 1, end).trim();
- else
- info = info + result.substring(start + 1).trim();
- info = info + ")";
- }
- }
- }
- catch (IOException e)
- {
- }
- return info;
- }
-
- /** Check if the platform is Mac OS X. */
- public static boolean isMac()
- {
- return s_isMac;
- }
-
- /** Check if the platform is Unix. */
- public static boolean isUnix()
- {
- return s_isUnix;
- }
-
- /** Check if the platform is Windows. */
- public static boolean isWindows()
- {
- return s_isWindows;
- }
-
- /** Try to open a URL in an external browser.
- Tries /usr/bin/open if Platform.isMac(),
- rundll32 url.dll,FileProtocolHandler if Platform.isWindows(),
- and if isUnix() in this order:
- - xdg-open
- - kfmclient (if KDE is running)
- - firefox
- - mozilla
- - opera
- @param url URL to open.
- @return false if everything failed. */
- public static boolean openInExternalBrowser(URL url)
- {
- if (isMac())
- {
- String[] cmd = { "/usr/bin/open", url.toString() };
- if (runProcess(cmd))
- return true;
- }
- else if (isWindows())
- {
- String[] cmd = { "rundll32", "url.dll,FileProtocolHandler",
- url.toString() };
- if (runProcess(cmd))
- return true;
- }
- else if (isUnix())
- {
- {
- String[] cmd = { "xdg-open", url.toString() };
- if (runProcess(cmd))
- return true;
- }
- if (checkKDERunning())
- {
- String[] cmd = { "kfmclient", "openURL", url.toString() };
- if (runProcess(cmd))
- return true;
- }
- {
- String[] cmd = { "firefox", url.toString() };
- if (runProcess(cmd))
- return true;
- }
- {
- String[] cmd = { "mozilla", url.toString() };
- if (runProcess(cmd))
- return true;
- }
- {
- String[] cmd = { "opera", url.toString() };
- if (runProcess(cmd))
- return true;
- }
- }
- return false;
- }
-
- /** Register handler for events from the Application Menu on MacOS.
- @param handler Handler to register. */
- public static void registerSpecialMacHandler(SpecialMacHandler handler)
- {
- try
- {
- Object[] args = { handler };
- Class[] arglist = { Platform.SpecialMacHandler.class };
- String name = "net.sf.gogui.specialmac.RegisterSpecialMacHandler";
- Class> registerClass = Class.forName(name);
- Constructor constructor = registerClass.getConstructor(arglist);
- constructor.newInstance(args);
- }
- catch (Throwable e)
- {
- System.err.println("Could not register handler for Mac events." +
- " (com.apple.eawt classes not found)");
- }
- }
-
- private static boolean s_isMac;
-
- private static boolean s_isUnix;
-
- private static boolean s_isWindows;
-
- static
- {
- // See http://developer.apple.com/technotes/tn2002/tn2110.html
- String name = System.getProperty("os.name");
- s_isMac = name.toLowerCase(Locale.getDefault()).startsWith("mac os x");
- s_isUnix = (name.indexOf("nix") >= 0 || name.indexOf("nux") >= 0);
- s_isWindows = name.startsWith("Windows");
- }
-
- private static boolean checkKDERunning()
- {
- try
- {
- String[] cmdArray = { "dcop" };
- String result = ProcessUtil.runCommand(cmdArray);
- return (result.indexOf("kicker") >= 0);
- }
- catch (IOException e)
- {
- return false;
- }
- }
-
- private static boolean existsProcCpuinfo()
- {
- return new File("/proc/cpuinfo").exists();
- }
-
- private static boolean runProcess(String[] cmd)
- {
- try
- {
- ProcessUtil.runProcess(cmd);
- return true;
- }
- catch (IOException e)
- {
- return false;
- }
- }
-}
diff --git a/src/hexgui/util/PrefUtil.java b/src/hexgui/util/PrefUtil.java
deleted file mode 100644
index 4a6b974..0000000
--- a/src/hexgui/util/PrefUtil.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// PrefUtil.java
-
-package hexgui.util;
-
-import java.util.ArrayList;
-import java.util.prefs.Preferences;
-import java.util.prefs.BackingStoreException;
-
-/** Utils for using java.util.prefs package. */
-public final class PrefUtil
-{
- /** Get node path, create if not already existing.
- @param path The absolute path name of the node.
- @return The node */
- public static Preferences createNode(String path)
- {
- assert ! path.startsWith("/");
- return Preferences.userRoot().node(path);
- }
-
- /** Get a list of strings from preferences.
- The list is stored as a size property end element_N properties with
- N being the element index.
- @param path The absolute path name of the node.
- @return The list of strings. */
- public static ArrayList getList(String path)
- {
- Preferences prefs = getNode(path);
- if (prefs == null)
- return new ArrayList();
- int size = prefs.getInt("size", 0);
- if (size <= 0)
- return new ArrayList();
- ArrayList result = new ArrayList(size);
- for (int i = 0; i < size; ++i)
- {
- String element = prefs.get("element_" + i, null);
- if (element == null)
- // Should not happen
- break;
- result.add(element);
- }
- return result;
- }
-
- /** Get node for package and path, return null if not already existing.
- @param path The absolute path name of the node.
- @return The node or null, if node does not exist or failure in the
- backing store. */
- public static Preferences getNode(String path)
- {
- assert ! path.startsWith("/");
- Preferences prefs = Preferences.userRoot();
- try
- {
- if (! prefs.nodeExists(path))
- return null;
- }
- catch (BackingStoreException e)
- {
- return null;
- }
- return prefs.node(path);
- }
-
- /** Put a list of strings to preferences.
- The list is stored as a size property end element_N properties with
- N being the element index.
- @param path The absolute path name of the node.
- @param list The list of strings. */
- public static void putList(String path, ArrayList list)
- {
- Preferences prefs = createNode(path);
- if (prefs == null)
- return;
- prefs.putInt("size", list.size());
- for (int i = 0; i < list.size(); ++i)
- prefs.put("element_" + i, list.get(i));
- }
-
- /** Make constructor unavailable; class is for namespace only. */
- private PrefUtil()
- {
- }
-}
diff --git a/src/hexgui/util/ProcessUtil.java b/src/hexgui/util/ProcessUtil.java
deleted file mode 100644
index 23bd3ff..0000000
--- a/src/hexgui/util/ProcessUtil.java
+++ /dev/null
@@ -1,139 +0,0 @@
-// ProcessUtil.java
-
-package hexgui.util;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-
-class ExitWaiter
- extends Thread
-{
- public ExitWaiter(Object monitor, Process process)
- {
- m_monitor = monitor;
- m_process = process;
- }
-
- public boolean isFinished()
- {
- synchronized (m_mutex)
- {
- return m_isFinished;
- }
- }
-
- public void run()
- {
- try
- {
- m_process.waitFor();
- }
- catch (InterruptedException e)
- {
- }
- synchronized (m_mutex)
- {
- m_isFinished = true;
- }
- synchronized (m_monitor)
- {
- m_monitor.notifyAll();
- }
- }
-
- private boolean m_isFinished;
-
- private final Object m_monitor;
-
- private final Object m_mutex = new Object();
-
- private final Process m_process;
-};
-
-/** Static utility functions and classes related to processes. */
-public class ProcessUtil
-{
- /** Copies standard error of a process to System.err. */
- public static class StdErrThread
- extends Thread
- {
- public StdErrThread(Process process)
- {
- super(new StreamCopy(false, process.getErrorStream(), System.err,
- false));
- }
- }
-
- /** Run a process and return its standard output as a string. */
- public static String runCommand(String[] cmdArray) throws IOException
- {
- Runtime runtime = Runtime.getRuntime();
- Process process = runtime.exec(cmdArray);
- Thread discardErr = new StreamDiscard(process.getErrorStream());
- discardErr.start();
- InputStream in = process.getInputStream();
- BufferedReader reader = new BufferedReader(new InputStreamReader(in));
- try
- {
- StringBuilder result = new StringBuilder();
- String line;
- while ((line = reader.readLine()) != null)
- {
- result.append(line);
- result.append('\n');
- }
- try
- {
- if (process.waitFor() != 0)
- throw new IOException("Process returned error status");
- }
- catch (InterruptedException e)
- {
- throw new IOException("InterruptedException");
- }
- return result.toString();
- }
- finally
- {
- reader.close();
- }
- }
-
- /** Run a process.
- Forwards the stdout/stderr of the child process to stderr of the
- calling process. */
- public static void runProcess(String[] cmdArray) throws IOException
- {
- Runtime runtime = Runtime.getRuntime();
- Process process = runtime.exec(cmdArray);
- Thread copyOut =
- new Thread(new StreamCopy(false, process.getInputStream(),
- System.err, false));
- copyOut.start();
- Thread copyErr =
- new Thread(new StreamCopy(false, process.getErrorStream(),
- System.err, false));
- copyErr.start();
- }
-
- public static boolean waitForExit(Process process, long timeout)
- {
- Object monitor = new Object();
- ExitWaiter exitWaiter = new ExitWaiter(monitor, process);
- synchronized (monitor)
- {
- exitWaiter.start();
- try
- {
- monitor.wait(timeout);
- return exitWaiter.isFinished();
- }
- catch (InterruptedException e)
- {
- return false;
- }
- }
- }
-}
diff --git a/src/hexgui/util/RadialGradientContext.java b/src/hexgui/util/RadialGradientContext.java
deleted file mode 100644
index b19e922..0000000
--- a/src/hexgui/util/RadialGradientContext.java
+++ /dev/null
@@ -1,102 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.util;
-
-import java.awt.Color;
-import java.awt.PaintContext;
-import java.awt.geom.Point2D;
-import java.awt.image.ColorModel;
-import java.awt.image.Raster;
-import java.awt.image.WritableRaster;
-
-//----------------------------------------------------------------------------
-
-/** Creates a raster with a radial color gradient. */
-public class RadialGradientContext
- implements PaintContext
-{
- public RadialGradientContext(Point2D point, Color color1,
- Point2D radius, Color color2)
- {
- m_point = point;
- m_red1 = color1.getRed();
- m_green1 = color1.getGreen();
- m_blue1 = color1.getBlue();
- m_alpha1 = color1.getAlpha();
- m_radius = radius.distance(0, 0);
- m_redDiff = color2.getRed() - m_red1;
- m_greenDiff = color2.getGreen() - m_green1;
- m_blueDiff = color2.getBlue() - m_blue1;
- m_alphaDiff = color2.getAlpha() - m_alpha1;
- }
-
- public void dispose()
- {
- }
-
- public ColorModel getColorModel()
- {
- return ColorModel.getRGBdefault();
- }
-
- public Raster getRaster(int x, int y, int width, int height)
- {
- if (m_raster != null && x == m_x && y == m_y && width == m_width
- && height == m_height)
- return m_raster;
- m_x = x;
- m_y = y;
- m_height = height;
- m_width = width;
- ColorModel colorModel = getColorModel();
- m_raster = colorModel.createCompatibleWritableRaster(width, height);
- int[] data = new int[width * height * 4];
- int index = -1;
- for (int j = 0; j < height; ++j)
- for (int i = 0; i < width; ++i)
- {
- double distance = m_point.distance(x + i, y + j);
- double ratio = Math.min(distance / m_radius, 1.0);
- data[++index] = (int)(m_red1 + ratio * m_redDiff);
- data[++index] = (int)(m_green1 + ratio * m_greenDiff);
- data[++index] = (int)(m_blue1 + ratio * m_blueDiff);
- data[++index] = (int)(m_alpha1 + ratio * m_alphaDiff);
- }
- m_raster.setPixels(0, 0, width, height, data);
- return m_raster;
- }
-
- private final int m_red1;
-
- private final int m_redDiff;
-
- private final int m_green1;
-
- private final int m_greenDiff;
-
- private final int m_blue1;
-
- private final int m_blueDiff;
-
- private final int m_alpha1;
-
- private final int m_alphaDiff;
-
- private int m_x;
-
- private int m_y;
-
- private int m_height;
-
- private int m_width;
-
- private final double m_radius;
-
- private final Point2D m_point;
-
- private WritableRaster m_raster;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/util/RadialGradientPaint.java b/src/hexgui/util/RadialGradientPaint.java
deleted file mode 100644
index a13d1e0..0000000
--- a/src/hexgui/util/RadialGradientPaint.java
+++ /dev/null
@@ -1,82 +0,0 @@
-//----------------------------------------------------------------------------
-// $Id$
-//----------------------------------------------------------------------------
-
-package hexgui.util;
-
-import java.awt.Color;
-import java.awt.Paint;
-import java.awt.PaintContext;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.ColorModel;
-
-
-//----------------------------------------------------------------------------
-
-/** Creates a PaintContext for a radial gradient. */
-public class RadialGradientPaint
- implements Paint
-{
- public RadialGradientPaint(Point2D point, Color pointColor,
- Point2D radius, Color backgroundColor)
- {
- assert(radius.distance(0, 0) > 0);
- m_point = point;
- m_radius = radius;
- m_pointColor = pointColor;
- m_backgroundColor = backgroundColor;
- int alphaPoint = pointColor.getAlpha();
- int alphaBackground = backgroundColor.getAlpha();
- if ((alphaPoint & alphaBackground) == 0xff)
- m_transparency = OPAQUE;
- else
- m_transparency = TRANSLUCENT;
- }
-
- public PaintContext createContext(ColorModel colorModel,
- Rectangle deviceBounds,
- Rectangle2D userBounds,
- AffineTransform xform,
- RenderingHints hints)
- {
- Point2D transformedPoint = xform.transform(m_point, null);
- Point2D transformedRadius = xform.deltaTransform(m_radius, null);
- if (m_cachedContext != null
- && transformedPoint.equals(m_transformedPoint)
- && transformedRadius.equals(m_transformedRadius))
- return m_cachedContext;
- m_transformedPoint = (Point2D)transformedPoint.clone();
- m_transformedRadius = (Point2D)transformedRadius.clone();
- m_cachedContext =
- new RadialGradientContext(transformedPoint, m_pointColor,
- transformedRadius, m_backgroundColor);
- return m_cachedContext;
- }
-
- public int getTransparency()
- {
- return m_transparency;
- }
-
- private final int m_transparency;
-
- private Point2D m_transformedPoint;
-
- private Point2D m_transformedRadius;
-
- private RadialGradientContext m_cachedContext;
-
- private final Point2D m_point;
-
- private final Point2D m_radius;
-
- private final Color m_backgroundColor;
-
- private final Color m_pointColor;
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/util/SpringUtilities.java b/src/hexgui/util/SpringUtilities.java
deleted file mode 100644
index e4fdca9..0000000
--- a/src/hexgui/util/SpringUtilities.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of Sun Microsystems nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package hexgui.util;
-
-import javax.swing.*;
-import javax.swing.SpringLayout;
-import java.awt.*;
-
-/**
- * A 1.4 file that provides utility methods for
- * creating form- or grid-style layouts with SpringLayout.
- * These utilities are used by several programs, such as
- * SpringBox and SpringCompactGrid.
- */
-public class SpringUtilities {
- /**
- * A debugging utility that prints to stdout the component's
- * minimum, preferred, and maximum sizes.
- */
- public static void printSizes(Component c) {
- System.out.println("minimumSize = " + c.getMinimumSize());
- System.out.println("preferredSize = " + c.getPreferredSize());
- System.out.println("maximumSize = " + c.getMaximumSize());
- }
-
- /**
- * Aligns the first rows * cols
- * components of parent in
- * a grid. Each component is as big as the maximum
- * preferred width and height of the components.
- * The parent is made just big enough to fit them all.
- *
- * @param rows number of rows
- * @param cols number of columns
- * @param initialX x location to start the grid at
- * @param initialY y location to start the grid at
- * @param xPad x padding between cells
- * @param yPad y padding between cells
- */
- public static void makeGrid(Container parent,
- int rows, int cols,
- int initialX, int initialY,
- int xPad, int yPad) {
- SpringLayout layout;
- try {
- layout = (SpringLayout)parent.getLayout();
- } catch (ClassCastException exc) {
- System.err.println("The first argument to makeGrid must use SpringLayout.");
- return;
- }
-
- Spring xPadSpring = Spring.constant(xPad);
- Spring yPadSpring = Spring.constant(yPad);
- Spring initialXSpring = Spring.constant(initialX);
- Spring initialYSpring = Spring.constant(initialY);
- int max = rows * cols;
-
- //Calculate Springs that are the max of the width/height so that all
- //cells have the same size.
- Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)).
- getWidth();
- Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)).
- getWidth();
- for (int i = 1; i < max; i++) {
- SpringLayout.Constraints cons = layout.getConstraints(
- parent.getComponent(i));
-
- maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth());
- maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight());
- }
-
- //Apply the new width/height Spring. This forces all the
- //components to have the same size.
- for (int i = 0; i < max; i++) {
- SpringLayout.Constraints cons = layout.getConstraints(
- parent.getComponent(i));
-
- cons.setWidth(maxWidthSpring);
- cons.setHeight(maxHeightSpring);
- }
-
- //Then adjust the x/y constraints of all the cells so that they
- //are aligned in a grid.
- SpringLayout.Constraints lastCons = null;
- SpringLayout.Constraints lastRowCons = null;
- for (int i = 0; i < max; i++) {
- SpringLayout.Constraints cons = layout.getConstraints(
- parent.getComponent(i));
- if (i % cols == 0) { //start of new row
- lastRowCons = lastCons;
- cons.setX(initialXSpring);
- } else { //x position depends on previous component
- cons.setX(Spring.sum(lastCons.getConstraint(SpringLayout.EAST),
- xPadSpring));
- }
-
- if (i / cols == 0) { //first row
- cons.setY(initialYSpring);
- } else { //y position depends on previous row
- cons.setY(Spring.sum(lastRowCons.getConstraint(SpringLayout.SOUTH),
- yPadSpring));
- }
- lastCons = cons;
- }
-
- //Set the parent's size.
- SpringLayout.Constraints pCons = layout.getConstraints(parent);
- pCons.setConstraint(SpringLayout.SOUTH,
- Spring.sum(
- Spring.constant(yPad),
- lastCons.getConstraint(SpringLayout.SOUTH)));
- pCons.setConstraint(SpringLayout.EAST,
- Spring.sum(
- Spring.constant(xPad),
- lastCons.getConstraint(SpringLayout.EAST)));
- }
-
- /* Used by makeCompactGrid. */
- private static SpringLayout.Constraints getConstraintsForCell(
- int row, int col,
- Container parent,
- int cols) {
- SpringLayout layout = (SpringLayout) parent.getLayout();
- Component c = parent.getComponent(row * cols + col);
- return layout.getConstraints(c);
- }
-
- /**
- * Aligns the first rows * cols
- * components of parent in
- * a grid. Each component in a column is as wide as the maximum
- * preferred width of the components in that column;
- * height is similarly determined for each row.
- * The parent is made just big enough to fit them all.
- *
- * @param rows number of rows
- * @param cols number of columns
- * @param initialX x location to start the grid at
- * @param initialY y location to start the grid at
- * @param xPad x padding between cells
- * @param yPad y padding between cells
- */
- public static void makeCompactGrid(Container parent,
- int rows, int cols,
- int initialX, int initialY,
- int xPad, int yPad) {
- SpringLayout layout;
- try {
- layout = (SpringLayout)parent.getLayout();
- } catch (ClassCastException exc) {
- System.err.println("The first argument to makeCompactGrid must use SpringLayout.");
- return;
- }
-
- //Align all cells in each column and make them the same width.
- Spring x = Spring.constant(initialX);
- for (int c = 0; c < cols; c++) {
- Spring width = Spring.constant(0);
- for (int r = 0; r < rows; r++) {
- width = Spring.max(width,
- getConstraintsForCell(r, c, parent, cols).
- getWidth());
- }
- for (int r = 0; r < rows; r++) {
- SpringLayout.Constraints constraints =
- getConstraintsForCell(r, c, parent, cols);
- constraints.setX(x);
- constraints.setWidth(width);
- }
- x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad)));
- }
-
- //Align all cells in each row and make them the same height.
- Spring y = Spring.constant(initialY);
- for (int r = 0; r < rows; r++) {
- Spring height = Spring.constant(0);
- for (int c = 0; c < cols; c++) {
- height = Spring.max(height,
- getConstraintsForCell(r, c, parent, cols).
- getHeight());
- }
- for (int c = 0; c < cols; c++) {
- SpringLayout.Constraints constraints =
- getConstraintsForCell(r, c, parent, cols);
- constraints.setY(y);
- constraints.setHeight(height);
- }
- y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad)));
- }
-
- //Set the parent's size.
- SpringLayout.Constraints pCons = layout.getConstraints(parent);
- pCons.setConstraint(SpringLayout.SOUTH, y);
- pCons.setConstraint(SpringLayout.EAST, x);
- }
-}
diff --git a/src/hexgui/util/StreamCopy.java b/src/hexgui/util/StreamCopy.java
deleted file mode 100644
index a457b97..0000000
--- a/src/hexgui/util/StreamCopy.java
+++ /dev/null
@@ -1,72 +0,0 @@
-// StreamCopy.java
-
-package hexgui.util;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/** Thread copying the output of one stream to another stream. */
-public class StreamCopy
- implements Runnable
-{
- /** Constructor.
- @param verbose Also copy everything to stderr
- @param src Source stream
- @param dest Destination stream
- @param close Close destination after eof in source */
- public StreamCopy(boolean verbose, InputStream src, OutputStream dest,
- boolean close)
- {
- m_verbose = verbose;
- m_src = src;
- m_dest = dest;
- m_close = close;
- }
-
- /** Run method.
- Exceptions caught are written to stderr. */
- public void run()
- {
- try
- {
- byte buffer[] = new byte[1024];
- while (true)
- {
- int n = m_src.read(buffer);
- if (n < 0)
- break;
- if (m_verbose)
- System.err.write(buffer, 0, n);
- m_dest.write(buffer, 0, n);
- m_dest.flush();
- }
- }
- catch (Throwable e)
- {
- StringUtils.printException(e);
- }
- finally
- {
- if (m_close)
- {
- try
- {
- m_dest.close();
- }
- catch (IOException e)
- {
- StringUtils.printException(e);
- }
- }
- }
- }
-
- private final boolean m_verbose;
-
- private final boolean m_close;
-
- private final InputStream m_src;
-
- private final OutputStream m_dest;
-}
diff --git a/src/hexgui/util/StreamDiscard.java b/src/hexgui/util/StreamDiscard.java
deleted file mode 100644
index a00fa79..0000000
--- a/src/hexgui/util/StreamDiscard.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// StreamDiscard.java
-
-package hexgui.util;
-
-import java.io.InputStream;
-
-/** Thread discarding an output stream. */
-public class StreamDiscard
- extends Thread
-{
- public StreamDiscard(InputStream src)
- {
- m_src = src;
- }
-
- /** Run method.
- Exceptions caught are written to stderr. */
- public void run()
- {
- try
- {
- byte buffer[] = new byte[1024];
- while (true)
- {
- int n = m_src.read(buffer);
- if (n < 0)
- break;
- if (n == 0)
- {
- // Not sure if this is necessary.
- sleep(100);
- continue;
- }
- }
- }
- catch (Throwable e)
- {
- StringUtils.printException(e);
- }
- }
-
- private final InputStream m_src;
-}
diff --git a/src/hexgui/util/StringUtils.java b/src/hexgui/util/StringUtils.java
deleted file mode 100644
index 1cf965e..0000000
--- a/src/hexgui/util/StringUtils.java
+++ /dev/null
@@ -1,298 +0,0 @@
-package hexgui.util;
-
-import hexgui.hex.HexPoint;
-import hexgui.hex.HexColor;
-import hexgui.hex.VC;
-import hexgui.util.Pair;
-
-import java.io.StringReader;
-import java.io.PrintStream;
-import java.io.IOException;
-import java.util.Vector;
-import java.util.ArrayList;
-
-public final class StringUtils
-{
- /** Capitalize the first word and trim whitespaces. */
- public static String capitalize(String message)
- {
- message = message.trim();
- if (message.equals(""))
- return message;
- StringBuilder buffer = new StringBuilder(message);
- char first = buffer.charAt(0);
- if (! Character.isUpperCase(first))
- buffer.setCharAt(0, Character.toUpperCase(first));
- return buffer.toString();
- }
-
- /** Check if string is null, empty, or contains only whitespaces. */
- public static boolean isEmpty(String s)
- {
- if (s == null)
- return true;
- for (int i = 0; i < s.length(); ++i)
- if (! Character.isWhitespace(s.charAt(i)))
- return false;
- return true;
- }
-
- /** Converts all whitespace characters to a single ' '. */
- public static String cleanWhiteSpace(String str)
- {
- StringReader reader = new StringReader(str);
- StringBuilder ret = new StringBuilder();
-
- boolean white = false;
- while (true) {
- int c;
- try {
- c = reader.read();
- }
- catch (Throwable t) {
- System.out.println("Something bad happened!");
- break;
- }
-
- if (c == -1) break;
- if (c == ' ' || c == '\n' || c == '\t') {
- if (!white) ret.append(" ");
- white = true;
- } else {
- white = false;
- ret.append((char)c);
- }
- }
- return ret.toString();
- }
-
- public static Vector parsePointList(String str, String sep)
- {
- Vector ret = new Vector();
- String cleaned = cleanWhiteSpace(str.trim());
- if (cleaned.length() == 0)
- return ret;
-
- String[] pts = cleaned.split(sep);
- for (int i=0; i > parseVariation(String str)
- {
- Vector > ret
- = new Vector >();
-
- Vector > pairs
- = StringUtils.parseStringPairList(str.trim());
- for (int i=0; i(color, point));
- }
- return ret;
- }
-
- public static Vector parsePointList(String str)
- {
- return parsePointList(str, " ");
- }
-
- public static Vector parseStringList(String str)
- {
- Vector ret = new Vector();
- String cleaned = cleanWhiteSpace(str.trim());
- if (cleaned.length() == 0)
- return ret;
-
- String[] strs = cleaned.split(" ");
- for (int i=0; i > parseStringPairList(String str)
- {
- Vector > ret = new Vector >();
- String cleaned = cleanWhiteSpace(str.trim());
- if (cleaned.length() == 0)
- return ret;
-
- String[] strs = cleaned.split(" ");
- for (int i=0; i(c1, c2));
- }
- return ret;
- }
-
- public static Vector parseVCList(String str)
- {
- Vector ret = new Vector();
- String cleaned = cleanWhiteSpace(str.trim());
- if (cleaned.length() == 0)
- return ret;
-
- String[] vcs = cleaned.split(" ");
-
- for (int i=0, j=0; i carrier = new Vector();
- Vector stones = new Vector();
- Vector key = new Vector();
- String source = "unknown";
-
- try {
- color = HexColor.get(vcs[i+0]);
- from = HexPoint.get(vcs[i+1]);
- to = HexPoint.get(vcs[i+2]);
- type = vcs[i+3];
-
- j = 5;
- if (!type.equals("softlimit")) {
- source = vcs[i+4];
-
- // read carrier set
- if (!vcs[i+5].equals("["))
- throw new Throwable("No carrier!");
-
- for (j=6; j < vcs.length; j++) {
- if (vcs[i+j].equals("]")) break;
- HexPoint p = HexPoint.get(vcs[i+j]);
- carrier.add(p);
- }
-
- j++; // skip closing ']'
-
- // read stone set
- if (!vcs[i+j].equals("["))
- throw new Throwable("No stones! Should be '[', got '" +
- vcs[j] + "'");
-
- for (j++; j < vcs.length; j++) {
- if (vcs[i+j].equals("]")) break;
- HexPoint p = HexPoint.get(vcs[i+j]);
- stones.add(p);
- }
-
- j++; // skip closing ']'
-
- int blah = 0;
- if (type.equals("semi")) blah = 1;
- for (int k=0; k=0; i--) {
- ret.append(str.charAt(i));
- }
- return ret.toString();
- }
-
- /** Split command line into arguments.
- Allows " for words containing whitespaces.
- */
- public static String[] splitArguments(String string)
- {
- assert string != null;
- ArrayList result = new ArrayList();
- boolean escape = false;
- boolean inString = false;
- StringBuilder token = new StringBuilder();
- for (int i = 0; i < string.length(); ++i)
- {
- char c = string.charAt(i);
- if (c == '"' && ! escape)
- {
- if (inString)
- {
- result.add(token.toString());
- token.setLength(0);
- }
- inString = ! inString;
- }
- else if (Character.isWhitespace(c) && ! inString)
- {
- if (token.length() > 0)
- {
- result.add(token.toString());
- token.setLength(0);
- }
- }
- else
- token.append(c);
- escape = (c == '\\' && ! escape);
- }
- if (token.length() > 0)
- result.add(token.toString());
- return result.toArray(new String[result.size()]);
- }
-
- /** Return a printable error message for an exception.
- Returns the error message is for instances of ErrorMessage or
- for other exceptions the class name with the exception message
- appended, if not empty. */
- public static String getErrorMessage(Throwable e)
- {
- String message = e.getMessage();
- boolean hasMessage = ! StringUtils.isEmpty(message);
- String className = e.getClass().getName();
- String result;
- if (e instanceof ErrorMessage)
- result = message;
- else if (hasMessage)
- result = className + ":\n" + message;
- else
- result = className;
- return result;
- }
-
- /** Print exception to standard error.
- Prints the class name and message to standard error.
- For exceptions of type Error or RuntimeException, a stack trace
- is printed in addition.
- @return A slightly differently formatted error message
- for display in an error dialog. */
- public static String printException(Throwable exception)
- {
- String result = getErrorMessage(exception);
- System.err.println(result);
- boolean isSevere = (exception instanceof RuntimeException
- || exception instanceof Error);
- if (isSevere)
- exception.printStackTrace();
- return result;
- }
-
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/hexgui/version/Version.java b/src/hexgui/version/Version.java
deleted file mode 100644
index 56e30be..0000000
--- a/src/hexgui/version/Version.java
+++ /dev/null
@@ -1,24 +0,0 @@
-//----------------------------------------------------------------------------
-/** */
-//----------------------------------------------------------------------------
-
-package hexgui.version;
-
-//----------------------------------------------------------------------------
-
-/** Version information.
- Contains the current version number, the svn build number, and
- the date of the build.
-*/
-public final class Version
-{
-
- private Version()
- {
- }
-
- public static String id = "0.10.GIT";
- public static String date = "2020-05-25 03:42";
-}
-
-//----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/Main.java b/src/main/java/hexgui/Main.java
new file mode 100644
index 0000000..bded38e
--- /dev/null
+++ b/src/main/java/hexgui/Main.java
@@ -0,0 +1,98 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui;
+
+import hexgui.gui.HexGui;
+import hexgui.util.Options;
+import hexgui.version.Version;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+
+public final class Main {
+ static final String LOOKANDFEEL = "System";
+
+ private static void initLookAndFeel() {
+ String lookAndFeel = null;
+
+ if (LOOKANDFEEL != null) {
+ if (LOOKANDFEEL.equals("Metal")) {
+ lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();
+ } else if (LOOKANDFEEL.equals("System")) {
+ lookAndFeel = UIManager.getSystemLookAndFeelClassName();
+ } else if (LOOKANDFEEL.equals("Motif")) {
+ lookAndFeel = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
+ } else if (LOOKANDFEEL.equals("GTK+")) { // new in 1.4.2
+ lookAndFeel = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
+ } else {
+ System.err.println("Unexpected value of LOOKANDFEEL specified: " + LOOKANDFEEL);
+ lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();
+ }
+
+ try {
+ UIManager.setLookAndFeel(lookAndFeel);
+ } catch (ClassNotFoundException e) {
+ System.err.println("Couldn't find class for specified look and feel:" + lookAndFeel);
+ System.err.println("Did you include the L&F library in the class path?");
+ System.err.println("Using the default look and feel.");
+ } catch (UnsupportedLookAndFeelException e) {
+ System.err.println(
+ "Can't use the specified look and feel (" + lookAndFeel + ") on this platform.");
+ System.err.println("Using the default look and feel.");
+ } catch (Exception e) {
+ System.err.println(
+ "Couldn't get specified look and feel (" + lookAndFeel + "), for some reason.");
+ System.err.println("Using the default look and feel.");
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static void createAndShowGUI(File file, String command) {
+ initLookAndFeel();
+ JFrame.setDefaultLookAndFeelDecorated(true);
+ HexGui app = new HexGui(file, command);
+ }
+
+ public static void main(String[] args) throws Exception {
+ try {
+ String options[] = {"config:", "program:", "help", "version"};
+ Options opt = Options.parse(args, options);
+ if (opt.contains("help")) {
+ String helpText =
+ "Usage: hexgui [options] [file]\n"
+ + "Graphical user interface for Hex programs\n"
+ + "using the Hex Text Protocol.\n"
+ + "\n"
+ + "-config file Read command line arguments from file\n"
+ + "-help Display this help and exit\n"
+ + "-program Command for Hex program to attach\n"
+ + "-version Print version and exit\n";
+ System.out.print(helpText);
+ return;
+ }
+ if (opt.contains("version")) {
+ System.out.println("HexGui " + Version.id + " " + Version.date);
+ return;
+ }
+ final String command = opt.get("program", null);
+ ArrayList arguments = opt.getArguments();
+ final File file;
+ if (arguments.size() == 0) file = null;
+ else if (arguments.size() == 1) file = new File(arguments.get(0));
+ else throw new Exception("Only one argument allowed");
+ javax.swing.SwingUtilities.invokeLater(
+ new Runnable() {
+ public void run() {
+ createAndShowGUI(file, command);
+ }
+ });
+ } catch (Exception e) {
+ System.err.println(e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/hexgui/MainWrapper.java b/src/main/java/hexgui/MainWrapper.java
new file mode 100644
index 0000000..8d0d420
--- /dev/null
+++ b/src/main/java/hexgui/MainWrapper.java
@@ -0,0 +1,24 @@
+package hexgui;
+
+import java.lang.reflect.Method;
+
+/**
+ * Wrapper for starting HexGui. Loads the main class with the reflection API to set AWT an other
+ * properties before any AWT class is loaded (otherwise they would be ignored).
+ */
+public final class MainWrapper {
+ public static void main(String[] args) throws Exception {
+ // Use GDI rendering on Windows. There are repaint problems using
+ // DDraw (last tested with Java 1.6 on Windows 7).
+ System.setProperty("sun.java2d.noddraw", "true");
+
+ // Invoke hexgui.Main.main() with reflection API
+ Class> mainClass = Class.forName("hexgui.Main");
+ Class[] argTypes = new Class[] {String[].class};
+ Method mainMethod = mainClass.getMethod("main", argTypes);
+ mainMethod.invoke(null, (Object) args);
+ }
+
+ /** Make constructor unavailable; class is for namespace only. */
+ private MainWrapper() {}
+}
diff --git a/src/main/java/hexgui/game/Clock.java b/src/main/java/hexgui/game/Clock.java
new file mode 100644
index 0000000..c72b77f
--- /dev/null
+++ b/src/main/java/hexgui/game/Clock.java
@@ -0,0 +1,70 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.game;
+
+import hexgui.hex.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+import javax.swing.Timer;
+
+public class Clock implements ActionListener {
+ public interface Listener {
+ public void clockChanged();
+ }
+
+ /** Initializes a clock. */
+ public Clock() {
+ m_timer = new Timer(1000, this);
+ m_elapsed = 0;
+ m_startTime = -1;
+ }
+
+ public void addListener(Listener ls) {
+ m_listener = ls;
+ }
+
+ public void start() {
+ if (m_startTime != -1) // already started
+ return;
+ m_startTime = System.currentTimeMillis();
+ m_timer.setInitialDelay((m_elapsed + 999) / 1000 * 1000 - m_elapsed);
+ m_timer.start();
+ }
+
+ public void stop() {
+ if (m_startTime == -1) // already stopped
+ return;
+ m_timer.stop();
+ m_elapsed += (int) (System.currentTimeMillis() - m_startTime);
+ m_startTime = -1;
+ }
+
+ /** Returns elapsed time in milliseconds. */
+ public int elapsed() {
+ if (m_startTime == -1) return m_elapsed;
+ return m_elapsed + (int) (System.currentTimeMillis() - m_startTime);
+ }
+
+ /** Sets the time. */
+ public void setElapsed(int millis) {
+ m_elapsed = millis;
+ m_listener.clockChanged();
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (m_listener != null) m_listener.clockChanged();
+ }
+
+ private Listener m_listener;
+
+ private Timer m_timer;
+
+ private int m_elapsed;
+
+ private long m_startTime;
+}
+;
diff --git a/src/main/java/hexgui/game/Game.java b/src/main/java/hexgui/game/Game.java
new file mode 100644
index 0000000..656753c
--- /dev/null
+++ b/src/main/java/hexgui/game/Game.java
@@ -0,0 +1,40 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.game;
+
+// ----------------------------------------------------------------------------
+
+/**
+ * Game state.
+ *
+ * A game can be in one of four states: STARTING, RUNNING, PAUSED
+ * , and FINISHED. The game is STARTING when the first move has yet
+ * to be played. Once the first move is played then the game is RUNNING. The clock is
+ * ticking only when the game is running. If a side-to-side connection is achieved or a player
+ * forfeits or resigns then the game is FINISHED. Moves can only be played in the first
+ * three states.
+ */
+public final class Game {
+
+ public static final int STARTING = 0;
+ public static final int RUNNING = 1;
+ public static final int PAUSED = 2;
+ public static final int FINISHED = 3;
+
+ public Game() {
+ m_state = STARTING;
+ }
+
+ public int getState() {
+ return m_state;
+ }
+
+ private int m_state;
+
+ private Node m_root;
+ private Node m_current;
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/game/GameInfo.java b/src/main/java/hexgui/game/GameInfo.java
new file mode 100644
index 0000000..ad23d90
--- /dev/null
+++ b/src/main/java/hexgui/game/GameInfo.java
@@ -0,0 +1,25 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.game;
+
+import java.awt.Dimension;
+
+// ----------------------------------------------------------------------------
+
+/** Properties of a game. Holds properties that appear in a SGF root node. */
+public class GameInfo {
+
+ public GameInfo() {}
+
+ public void setBoardSize(Dimension dim) {
+ m_boardsize = dim;
+ }
+
+ public Dimension getBoardSize() {
+ return m_boardsize;
+ }
+
+ private Dimension m_boardsize;
+}
diff --git a/src/main/java/hexgui/game/Node.java b/src/main/java/hexgui/game/Node.java
new file mode 100644
index 0000000..8dd23e6
--- /dev/null
+++ b/src/main/java/hexgui/game/Node.java
@@ -0,0 +1,505 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.game;
+
+import hexgui.hex.HexColor;
+import hexgui.hex.HexPoint;
+import hexgui.hex.Move;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.Vector;
+
+// ----------------------------------------------------------------------------
+
+/** Node in a game tree. Stores moves and other properties. */
+public class Node {
+ /** Initializes an empty node with a null move. */
+ public Node() {
+ this(null);
+ }
+
+ /**
+ * Constructs a new node with the specified move.
+ *
+ * @param move move to initialize the node with.
+ */
+ public Node(Move move) {
+ // Properties. This can include unstructured properties found
+ // in SGF files (i.e., properties that HexGUI doesn't know
+ // about), as well as structured properties such as C
+ // (comment), PL (player to move), and maybe
+ // others. Properties that can take multiple values are not
+ // stored here; e.g., LB is stored in m_label.
+ m_property = new TreeMap();
+
+ // For setup moves.
+ m_setup = new TreeMap();
+
+ // A list of cell:label pairs can be attached to a node. This
+ // corresponds to the SGF LB property.
+ m_label = new Vector();
+
+ // When navigating the tree, the "recent" child of each parent
+ // is the one that the "forward" button will navigate to.
+ m_recent = false;
+
+ // This node's move.
+ setMove(move);
+ }
+
+ public void setMove(Move move) {
+ m_move = move;
+ }
+
+ public Move getMove() {
+ return m_move;
+ }
+
+ public boolean hasMove() {
+ return m_move != null;
+ }
+
+ public void setParent(Node parent) {
+ m_parent = parent;
+ }
+
+ public Node getParent() {
+ return m_parent;
+ }
+
+ public void setPrev(Node prev) {
+ m_prev = prev;
+ }
+
+ public Node getPrev() {
+ return m_prev;
+ }
+
+ public void setNext(Node next) {
+ m_next = next;
+ }
+
+ public Node getNext() {
+ return m_next;
+ }
+
+ /** Sets the first child of this node. This does not update the sibling pointers of the child. */
+ public void setFirstChild(Node child) {
+ m_child = child;
+ }
+
+ /** Removes this node from the gametree. */
+ public void removeSelf() {
+ Node prev = getPrev();
+ Node next = getNext();
+
+ if (prev == null) {
+ // need to fix parent since we're first child
+ if (getParent() != null) {
+ getParent().setFirstChild(next);
+ }
+ } else {
+ prev.setNext(next);
+ }
+
+ if (next != null) {
+ next.setPrev(prev);
+ }
+ }
+
+ /** Moves this node to the start of its sibling list. */
+ public void moveToFirst() {
+ Node parent = getParent();
+ if (parent == null) {
+ return;
+ }
+ this.removeSelf();
+ parent.addFirstChild(this);
+ }
+
+ /** Moves this node and all of its parents to the start of their sibling lists */
+ public void makeMain() {
+ Node node = this;
+ while (node != null) {
+ node.moveToFirst();
+ node = node.getParent();
+ }
+ }
+
+ /**
+ * Adds a child to the beginning of the list of children.
+ *
+ * @param child Node to be added to start of list.
+ */
+ public void addFirstChild(Node child) {
+ Node oldfirst = m_child;
+ m_child = child;
+ child.setParent(this);
+ child.setPrev(null);
+ child.setNext(oldfirst);
+ if (oldfirst != null) {
+ oldfirst.setPrev(child);
+ }
+ }
+
+ /**
+ * Adds a child to the end of the list of children.
+ *
+ * @param child Node to be added to end of list.
+ */
+ public void addChild(Node child) {
+ child.setNext(null);
+ child.setParent(this);
+
+ if (m_child == null) {
+ m_child = child;
+ child.setPrev(null);
+ } else {
+ Node cur = m_child;
+ while (cur.getNext() != null) cur = cur.getNext();
+ cur.setNext(child);
+ child.setPrev(cur);
+ }
+ }
+
+ public boolean hasChild() {
+ return m_child != null;
+ }
+
+ /** Returns the number of children of this node. */
+ public int numChildren() {
+ int num = 0;
+ Node cur = m_child;
+ while (cur != null) {
+ num++;
+ cur = cur.getNext();
+ }
+ return num;
+ }
+
+ /**
+ * Returns the nth child.
+ *
+ * @param n The number of the child to return.
+ * @return The nth child or null that child does not exist.
+ */
+ public Node getChild(int n) {
+ Node cur = m_child;
+ for (int i = 0; cur != null; i++) {
+ if (i == n) return cur;
+ cur = cur.getNext();
+ }
+ return null;
+ }
+
+ /**
+ * Mark the current node as the most recently used among its siblings. This also unmarks the
+ * siblings
+ */
+ public void markRecent() {
+ Node parent = getParent();
+ if (parent != null) {
+ int n = parent.numChildren();
+ for (int i = 0; i < n; i++) {
+ parent.getChild(i).setRecent(false);
+ }
+ }
+ this.setRecent(true);
+ }
+
+ /**
+ * Set the "recent" property of this node. In a list of variations, the recent one is the most
+ * recently used. It is the variation that the "forward" button should select.
+ */
+ public void setRecent(boolean b) {
+ m_recent = b;
+ }
+
+ /** Get the "recent" property of this node. */
+ public boolean isRecent() {
+ return m_recent;
+ }
+
+ /**
+ * Returns the first child.
+ *
+ * @return first child or null if no children.
+ */
+ public Node getChild() {
+ return getChild(0);
+ }
+
+ /**
+ * Returns the most recent child.
+ *
+ * @return most recent child, or first child if no recent one, or null if no
+ * children.
+ */
+ public Node getRecentChild() {
+ Node cur = m_child;
+ if (cur == null) {
+ return null;
+ }
+ for (int i = 0; cur != null; i++) {
+ if (cur.isRecent()) {
+ return cur;
+ }
+ cur = cur.getNext();
+ }
+ return m_child;
+ }
+
+ /** Returns the child that contains node in its subtree. Currently unused. */
+ public Node getChildContainingNode(Node node) {
+ for (int i = 0; i < numChildren(); i++) {
+ Node c = getChild(i);
+ if (c == node) return c;
+ }
+ for (int i = 0; i < numChildren(); i++) {
+ Node c = getChild(i);
+ if (c.getChildContainingNode(node) != null) return c;
+ }
+ return null;
+ }
+
+ /** Returns the depth of this node. */
+ public int getDepth() {
+ Node cur;
+ int depth = 0;
+ for (cur = this; ; depth++) {
+ Node parent = cur.getParent();
+ if (parent == null) break;
+ cur = parent;
+ }
+ return depth;
+ }
+
+ /** Determines if the current node is a swap node */
+ public boolean isSwap() {
+ if (this.hasMove()) {
+ HexPoint p = m_move.getPoint();
+ return p == HexPoint.SWAP_SIDES || p == HexPoint.SWAP_PIECES;
+ } else {
+ return false;
+ }
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Adds a property to this node. Node properties are (key, value) pairs of strings.
+ * These properties will stored if the gametree is saved in SGF format.
+ *
+ * @param key name of the property
+ * @param value value of the property
+ */
+ public void setSgfProperty(String key, String value) {
+ m_property.put(key, value);
+ }
+
+ public void unsetSgfProperty(String key) {
+ m_property.remove(key);
+ }
+
+ /** Append the given string to the SGF property */
+ public void appendSgfProperty(String key, String toadd) {
+ String old = m_property.get(key);
+ if (old == null) old = "";
+ m_property.put(key, old + toadd);
+ }
+
+ /**
+ * Returns the value of a property.
+ *
+ * @param key name of property
+ * @return value of key or null if key is not in the property list.
+ */
+ public String getSgfProperty(String key) {
+ return m_property.get(key);
+ }
+
+ /**
+ * Returns a map of the current set of properties.
+ *
+ * @return Map containing the properties
+ */
+ public Map getProperties() {
+ return m_property;
+ }
+
+ /** Sets the SGF Comment field of this node. */
+ public void setComment(String comment) {
+ setSgfProperty("C", comment);
+ }
+
+ public String getComment() {
+ return getSgfProperty("C");
+ }
+
+ public boolean hasCount() {
+ return (getSgfProperty("CN") != null);
+ }
+
+ public String getCount() {
+ return getSgfProperty("CN");
+ }
+
+ /** Adds a stone of specified color to the setup list and the sgf property string. */
+ public void addSetup(HexColor color, HexPoint point) {
+ m_setup.put(point, color);
+ }
+
+ public void removeSetup(HexColor color, HexPoint point) {
+ m_setup.remove(point);
+ }
+
+ /** Returns the set of setup stones of color. */
+ public Vector getSetup(HexColor color) {
+ Vector points = new Vector();
+ HexPoint key;
+ Iterator i = m_setup.keySet().iterator();
+
+ while (i.hasNext()) {
+ key = (HexPoint) i.next();
+ if (m_setup.get(key) == color) {
+ points.add(key);
+ }
+ }
+
+ return points;
+ }
+
+ /** Determine whether the current node has any setup moves */
+ public boolean hasSetup() {
+ return !m_setup.isEmpty();
+ }
+
+ /**
+ * Determine whether the current node can accept updates to setup moves. This happens if the node
+ * has no m_move and no children. In particular, setup is permitted on the root node (which never
+ * has an m_move).
+ */
+ public boolean canSetup() {
+ if (this.hasMove()) {
+ return false;
+ }
+ if (this.hasChild()) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean hasLabel() {
+ return !m_label.isEmpty();
+ }
+
+ public Vector getLabels() {
+ return m_label;
+ }
+
+ public void addLabel(String str) {
+ m_label.add(str);
+ }
+
+ /**
+ * Return the default player to move for the current node, i.e., the player who would be moving
+ * next if the PL property is not set. For normal moves, passes, and swap-pieces, this is the
+ * opponent of the player who made the move; for swap-sides, it is the player who made the move;
+ * for the root node, it is Black; for resign, forfeit, and setup moves, there is no default,
+ * i.e., return null
+ */
+ public HexColor defaultPlayerToMove() {
+ if (this.hasMove()) {
+ HexPoint p = m_move.getPoint();
+ if (p == HexPoint.RESIGN || p == HexPoint.FORFEIT) {
+ return null;
+ } else if (p == HexPoint.SWAP_SIDES) {
+ return m_move.getColor();
+ } else {
+ return m_move.getColor().otherColor();
+ }
+ } else if (this.m_parent == null) {
+ // root node
+ return HexColor.BLACK;
+ } else {
+ // non-root setup node
+ return null;
+ }
+ }
+
+ /**
+ * Sets the PL property to the given color. For moves that have a default, unset the property if
+ * the requested value is the default.
+ */
+ public void setPlayerToMove(HexColor color) {
+ if (color == defaultPlayerToMove()) {
+ unsetSgfProperty("PL");
+ } else {
+ setSgfProperty("PL", (color == HexColor.BLACK) ? "B" : "W");
+ }
+ }
+
+ /**
+ * Compute the player to move, using the "PL" property if it is set and the standard behavior
+ * otherwise. Never return null.
+ */
+ public HexColor getPlayerToMove() {
+ String cstr = getSgfProperty("PL");
+ if (cstr != null) {
+ if (cstr.equals("B")) {
+ return HexColor.BLACK;
+ } else if (cstr.equals("W")) {
+ return HexColor.WHITE;
+ }
+ }
+ HexColor color = defaultPlayerToMove();
+ if (color != null) {
+ return color;
+ }
+ if (this.hasMove()) {
+ HexPoint p = m_move.getPoint();
+ if (p == HexPoint.RESIGN || p == HexPoint.FORFEIT) {
+ if (m_parent != null) {
+ return m_parent.getPlayerToMove();
+ }
+ }
+ }
+ return HexColor.BLACK;
+ }
+
+ // ----------------------------------------------------------------------
+ // Debugging output
+
+ /** Print information about self */
+ public void printDebug() {
+ System.out.println("(");
+ System.out.println("move: " + m_move);
+ System.out.println("setup: " + m_setup);
+ System.out.println("label: " + m_label);
+ System.out.println("property: " + m_property);
+ System.out.println("recent: " + m_recent);
+ Node cur = m_child;
+ while (cur != null) {
+ cur.printDebug();
+ cur = cur.getNext();
+ }
+ System.out.println(")");
+ }
+
+ // ----------------------------------------------------------------------
+
+ private TreeMap m_property;
+
+ private Map m_setup;
+
+ private Vector m_label;
+
+ private Move m_move;
+ private Node m_parent, m_prev, m_next, m_child;
+ private boolean m_recent;
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/hexgui/game/package.html b/src/main/java/hexgui/game/package.html
old mode 100755
new mode 100644
similarity index 100%
rename from src/hexgui/game/package.html
rename to src/main/java/hexgui/game/package.html
diff --git a/src/main/java/hexgui/gui/AboutDialog.java b/src/main/java/hexgui/gui/AboutDialog.java
new file mode 100644
index 0000000..ca09ea7
--- /dev/null
+++ b/src/main/java/hexgui/gui/AboutDialog.java
@@ -0,0 +1,84 @@
+package hexgui.gui;
+
+import hexgui.version.Version;
+import java.awt.*;
+import java.awt.event.*;
+import java.net.URL;
+import javax.swing.*;
+import javax.swing.border.EtchedBorder;
+import javax.swing.text.html.HTMLEditorKit;
+
+// ----------------------------------------------------------------------------
+
+/** Shows info about HexGui. */
+public class AboutDialog extends JDialog implements ActionListener {
+ /** Display modal about dialog. */
+ public AboutDialog(Frame owner) {
+ super(owner, true);
+ setTitle("About HexGui");
+ // setPreferredSize(new Dimension(400,300));
+ setResizable(false);
+
+ JPanel panel = new JPanel();
+ panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+
+ JPanel tp = new JPanel();
+ tp.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
+
+ String benzeneUrl = "http://benzene.sf.net";
+ String goguiUrl = "http://gogui.sf.net";
+ String about =
+ ""
+ + "
"
+ + "HexGui
"
+ + "Version "
+ + Version.id
+ + "
"
+ + "Graphical user interface for Hex programs
"
+ + "(C) 2006-2011 Broderick Arneson.
"
+ + ""
+ + benzeneUrl
+ + "
"
+ + "HexGui is based in large part on
"
+ + "GoGui by Markus Enzenberger
"
+ + ""
+ + goguiUrl
+ + "
"
+ + "HexGui is full of Hexy Goodness!
"
+ + "";
+
+ JEditorPane text = new JEditorPane();
+ text.setEditable(false);
+ text.setEditorKit(new HTMLEditorKit());
+ text.setText(about);
+
+ tp.add(text);
+
+ JButton button = new JButton("OK");
+ button.setActionCommand("OK");
+ button.addActionListener(this);
+
+ panel.add(tp);
+ panel.add(button);
+ add(panel);
+
+ pack();
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ setVisible(false);
+ }
+
+ private URL getImage(String name) {
+ ClassLoader loader = getClass().getClassLoader();
+ return loader.getResource("hexgui/images/" + name);
+ }
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/AnalyzeDialog.java b/src/main/java/hexgui/gui/AnalyzeDialog.java
new file mode 100644
index 0000000..ee34d02
--- /dev/null
+++ b/src/main/java/hexgui/gui/AnalyzeDialog.java
@@ -0,0 +1,483 @@
+// AnalyzeDialog.java
+
+package hexgui.gui;
+
+import static hexgui.hex.HexColor.BLACK;
+import static hexgui.hex.HexColor.EMPTY;
+import static hexgui.hex.HexColor.WHITE;
+
+import hexgui.hex.HexColor;
+import hexgui.hex.HexPoint;
+import hexgui.htp.AnalyzeCommand;
+import hexgui.htp.AnalyzeDefinition;
+import hexgui.htp.AnalyzeType;
+// import hexgui.htp.GtpResponseFormatError;
+// import hexgui.htp.GtpUtil;
+import hexgui.util.Platform;
+import hexgui.util.PrefUtil;
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.util.ArrayList;
+import javax.swing.Box;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JScrollPane;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+/** Dialog for selecting an AnalyzeCommand. */
+public final class AnalyzeDialog extends JDialog implements ActionListener, ListSelectionListener {
+ /** Callback for actions generated by AnalyzeDialog. */
+ public interface Listener {
+ void actionClearAnalyzeCommand();
+
+ void actionSetAnalyzeCommand(
+ AnalyzeCommand command,
+ boolean autoRun,
+ boolean clearBoard,
+ boolean oneRunOnly,
+ boolean reuseTextWindow);
+ }
+
+ public AnalyzeDialog(
+ Frame owner,
+ Listener listener,
+ ArrayList commands,
+ MessageDialogs messageDialogs) {
+ super(owner, "Analyze");
+ m_messageDialogs = messageDialogs;
+ m_commands = commands;
+ m_listener = listener;
+ Container contentPane = getContentPane();
+ JPanel commandPanel = createCommandPanel();
+ contentPane.add(commandPanel, BorderLayout.CENTER);
+ comboBoxChanged();
+ setSelectedColor(BLACK);
+ int minWidth = commandPanel.getPreferredSize().width;
+ setMinimumSize(new Dimension(minWidth, 192));
+ pack();
+ addWindowListener(
+ new WindowAdapter() {
+ public void windowActivated(WindowEvent e) {
+ m_comboBoxHistory.requestFocusInWindow();
+ }
+ });
+ }
+
+ public void actionPerformed(ActionEvent event) {
+ String command = event.getActionCommand();
+ if (command.equals("clear")) clearCommand();
+ else if (command.equals("comboBoxChanged")) comboBoxChanged();
+ else if (command.equals("run")) runCommand();
+ else assert false;
+ }
+
+ public void dispose() {
+ if (!m_autoRun.isSelected()) clearCommand();
+ saveRecent();
+ super.dispose();
+ }
+
+ public boolean getReuseTextWindow() {
+ return m_reuseWindow.isSelected();
+ }
+
+ public HexColor getSelectedColor() {
+ if (m_black.isSelected()) return BLACK;
+ else return WHITE;
+ }
+
+ public void saveRecent() {
+ ArrayList recent = new ArrayList(MAX_SAVE_RECENT);
+ int start = (m_firstIsTemp ? 1 : 0);
+ for (int i = start; i < getComboBoxItemCount(); ++i) {
+ String name = getComboBoxItem(i);
+ if (recent.indexOf(name) < 0) recent.add(name);
+ }
+ for (int i = 0; i < m_fullRecentList.size(); ++i) {
+ if (recent.size() == MAX_SAVE_RECENT) break;
+ String name = m_fullRecentList.get(i);
+ if (recent.indexOf(name) < 0) recent.add(name);
+ }
+ PrefUtil.putList("net/sf/hexgui/gui/analyzedialog/recentcommands", recent);
+ }
+
+ /**
+ * Set board size. Need for verifying responses to initial value for EPLIST commands. Default is
+ * 19.
+ */
+ public void setBoardSize(int boardSize) {
+ m_boardSize = boardSize;
+ }
+
+ public void setReuseTextWindow(boolean enable) {
+ m_reuseWindow.setSelected(enable);
+ }
+
+ public void setSelectedColor(HexColor color) {
+ m_selectedColor = color;
+ selectColor();
+ }
+
+ public void valueChanged(ListSelectionEvent e) {
+ int index = m_list.getSelectedIndex();
+ if (index >= 0) selectCommand(index);
+ }
+
+ private static final int MAX_SAVE_RECENT = 100;
+
+ /**
+ * Is the first item in the history combo box a temporary item? Avoids that the first item in the
+ * history combo box is treated as a real history command, if it was not run.
+ */
+ private boolean m_firstIsTemp;
+
+ private int m_boardSize = HexPoint.DEFAULT_SIZE;
+
+ private ArrayList m_fullRecentList;
+
+ private HexColor m_selectedColor = EMPTY;
+
+ // private final MessageDialogs m_messageDialogs;
+
+ private JButton m_clearButton;
+
+ private JButton m_runButton;
+
+ private JCheckBox m_autoRun;
+
+ private JCheckBox m_clearBoard;
+
+ private JCheckBox m_reuseWindow;
+
+ private JComboBox m_comboBoxHistory;
+
+ private JList m_list;
+
+ private Box m_colorBox;
+
+ private JRadioButton m_black;
+
+ private JRadioButton m_white;
+
+ private final ArrayList m_commands;
+
+ private final MessageDialogs m_messageDialogs;
+
+ private final Listener m_listener;
+
+ private String m_lastUpdateOptionsCommand;
+
+ private void clearCommand() {
+ m_listener.actionClearAnalyzeCommand();
+ m_autoRun.setSelected(false);
+ }
+
+ private void comboBoxChanged() {
+ Object item = m_comboBoxHistory.getSelectedItem();
+ if (item == null) {
+ m_list.clearSelection();
+ return;
+ }
+ String label = item.toString();
+ updateOptions(label);
+ String selectedValue = (String) m_list.getSelectedValue();
+ if (selectedValue != null && !selectedValue.equals(label)) m_list.clearSelection();
+ }
+
+ private JPanel createButtons() {
+ JPanel innerPanel = new JPanel(new GridLayout(1, 0, 5, 0));
+ m_runButton = new JButton("Run");
+ m_runButton.setToolTipText("Run Command");
+ m_runButton.setActionCommand("run");
+ m_runButton.addActionListener(this);
+ m_runButton.setMnemonic(KeyEvent.VK_R);
+ m_runButton.setEnabled(false);
+ GuiUtil.setMacBevelButton(m_runButton);
+ innerPanel.add(m_runButton);
+ m_clearButton = new JButton("Clear");
+ m_clearButton.setToolTipText(("Clear command"));
+ m_clearButton.setActionCommand("clear");
+ m_clearButton.addActionListener(this);
+ m_clearButton.setMnemonic(KeyEvent.VK_C);
+ GuiUtil.setMacBevelButton(m_clearButton);
+ innerPanel.add(m_clearButton);
+ JPanel outerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
+ outerPanel.add(innerPanel);
+ return outerPanel;
+ }
+
+ private JComponent createColorPanel() {
+ m_colorBox = Box.createVerticalBox();
+ ButtonGroup group = new ButtonGroup();
+ m_black = new JRadioButton("Black");
+ m_black.setToolTipText("Black");
+ m_black.setEnabled(false);
+ group.add(m_black);
+ m_colorBox.add(m_black);
+ m_white = new JRadioButton("White");
+ m_white.setToolTipText("White");
+ m_white.setEnabled(false);
+ group.add(m_white);
+ m_colorBox.add(m_white);
+ return m_colorBox;
+ }
+
+ private JPanel createCommandPanel() {
+ JPanel panel = new JPanel(new BorderLayout());
+ m_list = new JList();
+ m_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ m_list.setVisibleRowCount(25);
+ m_list.addMouseListener(
+ new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ int modifiers = e.getModifiers();
+ int mask = ActionEvent.ALT_MASK;
+ if (e.getClickCount() == 2 || ((modifiers & mask) != 0)) {
+ // int index =
+ // m_list.locationToIndex(event.getPoint());
+ runCommand();
+ }
+ }
+ });
+ m_list.addFocusListener(
+ new FocusAdapter() {
+ public void focusGained(FocusEvent e) {
+ int index = getSelectedCommand();
+ if (index >= 0) m_list.setSelectedIndex(index);
+ }
+ });
+ m_list.addListSelectionListener(this);
+ JScrollPane scrollPane = new JScrollPane(m_list);
+ if (Platform.isMac())
+ // Default Apple L&F uses no border, but Quaqua 3.7.4 does
+ scrollPane.setBorder(null);
+ panel.add(scrollPane, BorderLayout.CENTER);
+ panel.add(createLowerPanel(), BorderLayout.SOUTH);
+ String[] labels = new String[m_commands.size()];
+ for (int i = 0; i < m_commands.size(); ++i) labels[i] = m_commands.get(i).getLabel();
+ m_list.setListData(labels);
+ comboBoxChanged();
+ loadRecent();
+ return panel;
+ }
+
+ private JComponent createLowerPanel() {
+ Box panel = Box.createVerticalBox();
+ panel.add(GuiUtil.createFiller());
+ m_comboBoxHistory = new JComboBox();
+ panel.add(m_comboBoxHistory);
+ Box lowerPanel = Box.createVerticalBox();
+ lowerPanel.setBorder(GuiUtil.createEmptyBorder());
+ panel.add(lowerPanel);
+ Box optionsPanel = Box.createHorizontalBox();
+ lowerPanel.add(optionsPanel);
+ JPanel leftPanel = new JPanel();
+ optionsPanel.add(leftPanel);
+ Box leftBox = Box.createVerticalBox();
+ leftPanel.add(leftBox);
+ m_autoRun = new JCheckBox("Autorun");
+ m_autoRun.addItemListener(
+ new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ if (!m_autoRun.isSelected()) m_listener.actionClearAnalyzeCommand();
+ }
+ });
+ m_autoRun.setToolTipText("Autorun");
+ m_autoRun.setEnabled(false);
+ leftBox.add(m_autoRun);
+ m_clearBoard = new JCheckBox("Clearboard");
+ m_clearBoard.setToolTipText("Clearboard");
+ m_clearBoard.setEnabled(false);
+ leftBox.add(m_clearBoard);
+ m_clearBoard.setSelected(true);
+ m_reuseWindow = new JCheckBox("Reuse Text");
+ m_reuseWindow.setToolTipText("Reuse text window");
+ leftBox.add(m_reuseWindow);
+ JPanel rightPanel = new JPanel();
+ rightPanel.add(createColorPanel());
+ optionsPanel.add(rightPanel);
+
+ // TODO: The following horizontal glue does not really work as expected
+ // (tested on Linux/Sun Java 1.6.0_14) and the left two components in
+ // the box are not aligned to the left.
+ optionsPanel.add(Box.createHorizontalGlue());
+
+ // TODO: If GTK Looks L&F is used on Linux/Sun Java 1.6.0_14 or OpenJDK
+ // 6b14-1.4.1-0ubuntu11, then the text of the checkbox items can be
+ // truncated a bit on the left (wrong minimum size calculation?). The
+ // two fillers are a workaround for this.
+ optionsPanel.add(GuiUtil.createFiller());
+ optionsPanel.add(GuiUtil.createFiller());
+
+ lowerPanel.add(createButtons());
+ m_comboBoxHistory.addActionListener(this);
+ return panel;
+ }
+
+ private String getComboBoxItem(int i) {
+ return m_comboBoxHistory.getItemAt(i).toString();
+ }
+
+ private int getComboBoxItemCount() {
+ return m_comboBoxHistory.getItemCount();
+ }
+
+ private int getCommandIndex(String label) {
+ for (int i = 0; i < m_commands.size(); ++i)
+ if (m_commands.get(i).getLabel().equals(label)) return i;
+ return -1;
+ }
+
+ private int getSelectedCommand() {
+ Object item = m_comboBoxHistory.getSelectedItem();
+ if (item == null) return -1;
+ return getCommandIndex(item.toString());
+ }
+
+ private void insertComboBoxItem(String label, int index) {
+ m_comboBoxHistory.insertItemAt(GuiUtil.createComboBoxItem(label), index);
+ }
+
+ private void loadRecent() {
+ m_comboBoxHistory.removeAllItems();
+ m_fullRecentList = PrefUtil.getList("net/sf/hexgui/gui/analyzedialog/recentcommands");
+ for (int i = 0; i < m_fullRecentList.size(); ++i) {
+ String name = m_fullRecentList.get(i);
+ if (getCommandIndex(name) >= 0) m_comboBoxHistory.addItem(GuiUtil.createComboBoxItem(name));
+ if (m_comboBoxHistory.getItemCount() > 20) break;
+ }
+ int index = getSelectedCommand();
+ if (index >= 0) selectCommand(index);
+ m_firstIsTemp = false;
+ }
+
+ private void runCommand() {
+ // if (m_gtp.isCommandInProgress())
+ // {
+ // showError("MSG_ANALYZE_CANNOT_EXECUTE",
+ // "MSG_ANALYZE_CANNOT_EXECUTE_2",
+ // false);
+ // return;
+ // }
+ int index = getSelectedCommand();
+ if (index < 0) {
+ // String name = m_gtp.getName();
+ // if (name == null)
+ // showError("MSG_ANALYZE_NOT_SUPPORTED",
+ // "MSG_ANALYZE_NOT_SUPPORTED_2", false);
+ // else
+ // showError("MSG_ANALYZE_NOT_SUPPORTED",
+ // "MSG_ANALYZE_NOT_SUPPORTED_3", false, name);
+ return;
+ }
+ updateRecent(index);
+ AnalyzeCommand command = new AnalyzeCommand(m_commands.get(index));
+ if (command.needsColorArg()) command.setColorArg(getSelectedColor());
+ String label = command.getResultTitle();
+ if (command.needsStringArg()) {
+ String stringArg =
+ JOptionPane.showInputDialog(this, label, "TIT_INPUT", JOptionPane.PLAIN_MESSAGE);
+ if (stringArg == null) return;
+ command.setStringArg(stringArg);
+ }
+ if (command.needsOptStringArg()) {}
+ if (command.getType() == AnalyzeType.EPLIST) {}
+ if (command.needsFileArg()) {
+ File fileArg = FileDialogs.showSelectFile(this, label);
+ if (fileArg == null) return;
+ command.setFileArg(fileArg);
+ }
+ if (command.needsFileOpenArg()) {
+ File fileArg = FileDialogs.showOpen(this, label);
+ if (fileArg == null) return;
+ command.setFileOpenArg(fileArg);
+ }
+ if (command.needsFileSaveArg()) {
+ File fileArg = FileDialogs.showSave(this, label, m_messageDialogs);
+ if (fileArg == null) return;
+ command.setFileSaveArg(fileArg);
+ }
+ if (command.needsColorArg()) command.setColorArg(getSelectedColor());
+ boolean autoRun = m_autoRun.isEnabled() && m_autoRun.isSelected();
+ boolean clearBoard = !m_clearBoard.isEnabled() || m_clearBoard.isSelected();
+ boolean reuseWindow = m_reuseWindow.isEnabled() && m_reuseWindow.isSelected();
+ m_listener.actionSetAnalyzeCommand(command, autoRun, clearBoard, false, reuseWindow);
+ }
+
+ private void selectCommand(int index) {
+ String label = m_commands.get(index).getLabel();
+ updateOptions(label);
+ m_comboBoxHistory.removeActionListener(this);
+ if (m_firstIsTemp && getComboBoxItemCount() > 0) m_comboBoxHistory.removeItemAt(0);
+ if (getComboBoxItemCount() == 0 || !getComboBoxItem(0).equals(label)) {
+ insertComboBoxItem(label, 0);
+ m_firstIsTemp = true;
+ m_comboBoxHistory.setSelectedIndex(0);
+ }
+ m_comboBoxHistory.addActionListener(this);
+ }
+
+ private void selectColor() {
+ if (m_selectedColor == BLACK) m_black.setSelected(true);
+ else if (m_selectedColor == WHITE) m_white.setSelected(true);
+ }
+
+ private void showError(String mainMessage, String optionalMessage, boolean isCritical) {
+ ShowError.msg(this, mainMessage);
+ }
+
+ private void showError(
+ String mainMessage, String optionalMessage, boolean isCritical, Object... args) {
+ ShowError.msg(this, mainMessage);
+ }
+
+ private void updateOptions(String label) {
+ if (label.equals(m_lastUpdateOptionsCommand)) return;
+ m_lastUpdateOptionsCommand = label;
+ int index = getCommandIndex(label);
+ if (index < 0) return;
+ AnalyzeCommand command = new AnalyzeCommand(m_commands.get(index));
+ boolean needsColorArg = command.needsColorArg();
+ m_black.setEnabled(needsColorArg);
+ m_white.setEnabled(needsColorArg);
+ m_autoRun.setEnabled(command.getType() != AnalyzeType.PARAM);
+ m_autoRun.setSelected(false);
+ m_clearBoard.setEnabled(command.getType() != AnalyzeType.PARAM);
+ m_runButton.setEnabled(true);
+ }
+
+ private void updateRecent(int index) {
+ String label = m_commands.get(index).getLabel();
+ insertComboBoxItem(label, 0);
+ m_comboBoxHistory.setSelectedIndex(0);
+ for (int i = 1; i < getComboBoxItemCount(); ++i)
+ if (getComboBoxItem(i).equals(label)) m_comboBoxHistory.removeItemAt(i);
+ m_firstIsTemp = false;
+ }
+}
diff --git a/src/main/java/hexgui/gui/BoardDrawerBase.java b/src/main/java/hexgui/gui/BoardDrawerBase.java
new file mode 100644
index 0000000..3fa4d36
--- /dev/null
+++ b/src/main/java/hexgui/gui/BoardDrawerBase.java
@@ -0,0 +1,343 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import hexgui.hex.HexColor;
+import hexgui.hex.HexPoint;
+import hexgui.util.Pair;
+
+import javax.swing.*;
+import java.awt.*;
+import java.net.URL;
+import java.util.Vector;
+
+// ----------------------------------------------------------------------------
+
+/**
+ * Base class for board drawing.
+ *
+ * Board drawers are responsible for drawing the background, labels, field outlines, and stone
+ * shadows. In addition, they are also responsible for determining the actual position of each field
+ * in the window. Field contents (i.e. stones, markers, numerical values, etc) are not drawn, they
+ * are drawn with the GuiField class.
+ *
+ *
Board sizes supported are m x n where m and n range
+ * from 1 to 26. By default, black connects top and bottom and should be labeled with letters. White
+ * connects left and right and should be labeled with numbers.
+ */
+public abstract class BoardDrawerBase {
+ public BoardDrawerBase() {
+ m_background = null;
+ m_aspect_ratio = 1.0;
+ }
+
+ /**
+ * Loads the image in filename and sets it as the background. If filename
+ * does not exist no background image is displayed. Image will be scaled to fit the
+ * window.
+ *
+ * @param filename filename of the image to use as a background.
+ */
+ public void loadBackground(String filename) {
+ ClassLoader classLoader = getClass().getClassLoader();
+ URL url = classLoader.getResource(filename);
+ if (url == null) {
+ System.out.println("loadBackground: could not load '" + filename + "'!");
+ m_background = null;
+ } else {
+ m_background = new ImageIcon(url).getImage();
+ }
+ }
+
+ /**
+ * Gets the field containing the specified point. NOTE: uses the position of fields from the last
+ * call to draw(). Also assumes the set of fields given are the same as those in the last call to
+ * draw().
+ *
+ * @param p the point
+ * @param field the set of fields to search through.
+ * @return the field in the set that p is in or null if p is not in any field.
+ */
+ public GuiField getFieldContaining(Point p, GuiField field[]) {
+ if (m_outline == null) return null;
+ for (int x = 0; x < field.length; x++) {
+ if (m_outline[x].contains(p)) return field[x];
+ }
+ return null;
+ }
+
+ /**
+ * Draws the board. The size of the region to draw to, the size of the board, and the field to
+ * draw must be given. The position of each field is then calculated and the board drawn.
+ *
+ * @param g graphics context to draw to
+ * @param w the width of the region to draw in
+ * @param h the height of the region to draw in
+ * @param bw the width of the board (in fields)
+ * @param bh the height of the board (in fields)
+ * @param alphaontop true if letters are on top, otherwise numbers
+ * @param field the fields to draw
+ * @param arrows the list of arrows to draw
+ */
+ public void draw(
+ Graphics g,
+ int w,
+ int h,
+ int bw,
+ int bh,
+ boolean alphaontop,
+ GuiField field[],
+ Vector> arrows) {
+ m_width = w;
+ m_height = h;
+
+ m_bwidth = bw;
+ m_bheight = bh;
+
+ m_alphaontop = alphaontop;
+
+ computeFieldPlacement();
+ m_outline = calcCellOutlines(field);
+
+ setAntiAliasing(g);
+ drawBackground(g);
+ drawCells(g, field);
+ drawLabels(g, alphaontop);
+ drawShadows(g, field);
+ drawFields(g, field);
+ drawAlpha(g, field);
+
+ drawArrows(g, arrows);
+ }
+
+ // ------------------------------------------------------------
+
+ protected abstract Point getLocation(HexPoint p);
+
+ /**
+ * Calculates the width of a field given the dimensions of the window and board.
+ *
+ * @param w width of window
+ * @param h height of window
+ * @param bw width of board
+ * @param bh height of board
+ */
+ protected abstract int calcFieldWidth(int w, int h, int bw, int bh);
+
+ /**
+ * Calculates the height of a field given the dimensions of the window and board.
+ *
+ * @see calcFieldWidth
+ */
+ protected abstract int calcFieldHeight(int w, int h, int bw, int bh);
+
+ protected abstract int calcStepSize();
+
+ /**
+ * Calculates the width of the board in pixels.
+ *
+ * @requires calcFieldWidth and calcFieldHeight to have been called.
+ */
+ protected abstract int calcBoardWidth();
+
+ /**
+ * Calculates the height of the board in pixels.
+ *
+ * @requires calcFieldWidth and calcFieldHeight to have been called.
+ */
+ protected abstract int calcBoardHeight();
+
+ /**
+ * Performs any necessary initializations for drawing the outlines of the fields.
+ *
+ * @param the fields it will need to draw
+ */
+ protected abstract Polygon[] calcCellOutlines(GuiField field[]);
+
+ /**
+ * Draws the outlines of the given fields.
+ *
+ * @param g graphics context to draw to.
+ * @param field the list of fields to draw.
+ */
+ protected void drawCells(Graphics g, GuiField field[]) {
+ g.setColor(Color.black);
+ for (int i = 0; i < m_outline.length; i++) {
+ if ((field[i].getAttributes() & GuiField.DRAW_CELL_OUTLINE) != 0) {
+ g.drawPolygon(m_outline[i]);
+ }
+ }
+
+ g.setColor(Color.yellow);
+ for (int i = 0; i < m_outline.length; i++) {
+ if ((field[i].getAttributes() & GuiField.SELECTED) != 0) {
+ g.drawPolygon(m_outline[i]);
+ }
+ }
+ }
+
+ protected void computeFieldPlacement() {
+ m_fieldWidth = calcFieldWidth(m_width, m_height, m_bwidth, m_bheight);
+ m_fieldHeight = calcFieldHeight(m_width, m_height, m_bwidth, m_bheight);
+
+ if (m_fieldHeight >= (int) (m_fieldWidth / m_aspect_ratio)) {
+ m_fieldHeight = (int) (m_fieldWidth / m_aspect_ratio);
+ } else {
+ m_fieldWidth = (int) (m_fieldHeight * m_aspect_ratio);
+ }
+
+ // If field dimensions are not even then the inner cell lines
+ // on the board can be doubled up.
+ // FIXME: lines still get doubled up...why?
+ if ((m_fieldWidth & 1) != 0) m_fieldWidth--;
+ if ((m_fieldHeight & 1) != 0) m_fieldHeight--;
+
+ m_fieldRadius = (m_fieldWidth < m_fieldHeight) ? m_fieldWidth : m_fieldHeight;
+
+ m_step = calcStepSize();
+
+ int bw = calcBoardWidth();
+ int bh = calcBoardHeight();
+
+ // add a half cell's worth of empty space
+ int extra = (m_width - (bw + 3 * m_fieldWidth));
+ m_marginX = extra / 2 + 3 * m_fieldWidth / 2;
+
+ m_marginY = (m_height - bh) / 2 + m_fieldHeight / 2;
+ }
+
+ // ------------------------------------------------------------
+
+ protected int getShadowOffset() {
+ return (m_fieldRadius - 2 * GuiField.getStoneMargin(m_fieldRadius)) / 12;
+ }
+
+ protected void drawBackground(Graphics g) {
+ if (m_background != null) g.drawImage(m_background, 0, 0, m_width, m_height, null);
+ }
+
+ protected void drawLabel(Graphics g, Point p, String string, int xoff) {
+ double size = Math.min(m_fieldWidth, m_fieldHeight) * 0.4;
+ Font f = g.getFont();
+ Font f2 = f.deriveFont((float) size);
+
+ FontMetrics fm = g.getFontMetrics(f2);
+ int width = fm.stringWidth(string);
+ int height = fm.getAscent();
+
+ g.setFont(f2);
+ int x = width / 2;
+ int y = height / 2;
+ g.drawString(string, p.x + xoff - x, p.y + y);
+ g.setFont(f);
+ }
+
+ protected abstract void drawLabels(Graphics g, boolean alphatop);
+
+ protected void drawShadows(Graphics graphics, GuiField[] field) {
+ if (m_fieldRadius <= 5) return;
+ Graphics2D graphics2D = graphics instanceof Graphics2D ? (Graphics2D) graphics : null;
+ if (graphics2D == null) return;
+ graphics2D.setComposite(COMPOSITE_3);
+ int size = m_fieldRadius - 2 * GuiField.getStoneMargin(m_fieldRadius);
+ int offset = getShadowOffset();
+ for (int pos = 0; pos < field.length; pos++) {
+ if (field[pos].getColor() == HexColor.EMPTY) continue;
+ Point location = getLocation(field[pos].getPoint());
+ graphics.setColor(Color.black);
+ graphics.fillOval(location.x - size / 2 + offset, location.y - size / 2 + offset, size, size);
+ }
+ graphics.setPaintMode();
+ }
+
+ protected void drawFields(Graphics g, GuiField field[]) {
+ for (int x = 0; x < field.length; x++) {
+ Point p = getLocation(field[x].getPoint());
+ field[x].draw(g, p.x, p.y, m_fieldWidth, m_fieldHeight);
+ }
+ }
+
+ protected void drawAlpha(Graphics g, GuiField field[]) {
+ if (g instanceof Graphics2D) {
+ Graphics2D g2d = (Graphics2D) g;
+
+ for (int i = 0; i < m_outline.length; i++) {
+ if ((field[i].getAttributes() & GuiField.DRAW_ALPHA) == 0) continue;
+
+ Color color = field[i].getAlphaColor();
+ if (color == null) continue;
+
+ g2d.setComposite(
+ AlphaComposite.getInstance(AlphaComposite.SRC_OVER, field[i].getAlphaBlend()));
+
+ g2d.setColor(color);
+ g2d.fillPolygon(m_outline[i]);
+ }
+ }
+ }
+
+ protected void drawArrows(Graphics g, Vector> arrows) {
+ if (g instanceof Graphics2D) {
+ Graphics2D g2d = (Graphics2D) g;
+ g2d.setColor(Color.BLUE);
+ for (int i = 0; i < arrows.size(); i++) {
+ Point fm = getLocation(arrows.get(i).first);
+ Point to = getLocation(arrows.get(i).second);
+ drawArrow(g2d, fm.x, fm.y, to.x, to.y, 1.5);
+ }
+ }
+ }
+
+ protected void setAntiAliasing(Graphics g) {
+ if (g instanceof Graphics2D) {
+ Graphics2D g2d = (Graphics2D) g;
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ }
+ }
+
+ public static void drawArrow(Graphics g2d, int x1, int y1, int x2, int y2, double stroke) {
+ double aDir = Math.atan2(x1 - x2, y1 - y2);
+ g2d.drawLine(x2, y2, x1, y1);
+ // make the arrow head solid even if dash pattern has been specified
+ // g2d.setStroke(new BasicStroke(1f));
+
+ Polygon tmpPoly = new Polygon();
+ int i1 = 12 + (int) (stroke * 2);
+ // make the arrow head the same size regardless of the length length
+ int i2 = 6 + (int) stroke;
+ tmpPoly.addPoint(x2, y2); // arrow tip
+ tmpPoly.addPoint(x2 + xCor(i1, aDir + .5), y2 + yCor(i1, aDir + .5));
+ tmpPoly.addPoint(x2 + xCor(i2, aDir), y2 + yCor(i2, aDir));
+ tmpPoly.addPoint(x2 + xCor(i1, aDir - .5), y2 + yCor(i1, aDir - .5));
+ tmpPoly.addPoint(x2, y2); // arrow tip
+ g2d.drawPolygon(tmpPoly);
+ g2d.fillPolygon(tmpPoly);
+ }
+
+ private static int yCor(int len, double dir) {
+ return (int) (len * Math.cos(dir));
+ }
+
+ private static int xCor(int len, double dir) {
+ return (int) (len * Math.sin(dir));
+ }
+
+ protected boolean m_alphaontop;
+
+ protected double m_aspect_ratio;
+
+ protected Image m_background;
+
+ protected int m_width, m_height;
+ protected int m_bwidth, m_bheight;
+ protected int m_marginX, m_marginY;
+ protected int m_fieldWidth, m_fieldHeight, m_fieldRadius, m_step;
+ protected Polygon m_outline[];
+
+ protected static final AlphaComposite COMPOSITE_3 =
+ AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/BoardDrawerDiamond.java b/src/main/java/hexgui/gui/BoardDrawerDiamond.java
new file mode 100644
index 0000000..0dcab07
--- /dev/null
+++ b/src/main/java/hexgui/gui/BoardDrawerDiamond.java
@@ -0,0 +1,114 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import hexgui.hex.HexPoint;
+import hexgui.util.Hexagon;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+// ----------------------------------------------------------------------------
+
+public class BoardDrawerDiamond extends BoardDrawerBase {
+
+ protected static final double ASPECT_RATIO = 1.1547;
+
+ public BoardDrawerDiamond() {
+ super();
+ loadBackground("hexgui/images/wood.png");
+ m_aspect_ratio = ASPECT_RATIO;
+ }
+
+ /**
+ * Returns the location in the window of the field with coordinates (x,y).
+ * Coordinates increase to the right and down, with the top left of the board having coordinates
+ * (0,0). Negative values are acceptable.
+ *
+ * @param x the x coordinate of the field.
+ * @param y the y coordinate of the field.
+ * @return the center of the field at (x,y).
+ */
+ protected Point getLocation(int x, int y) {
+ // yoffset will be positive when bwidth > bheight (to push the
+ // board down) and negative when bwidth < bheight (to lift it
+ // up) because the a1 square (0,0) will not be
+ // in the center of the vertical space occupied by the board.
+ int yoffset = (m_bwidth - m_bheight) * m_fieldHeight / 2;
+
+ Point ret = new Point();
+ ret.x = m_marginX + (y + x) * m_step;
+ ret.y = m_marginY + yoffset + (m_bheight / 2) * m_fieldHeight + (y - x) * m_fieldHeight / 2;
+ return ret;
+ }
+
+ /** Returns the location of the field with HexPoint pos. */
+ protected Point getLocation(HexPoint pos) {
+ if (pos == HexPoint.EAST) {
+ return getLocation(m_bwidth + 1, m_bheight / 2 - 1);
+ } else if (pos == HexPoint.WEST) {
+ return getLocation(-2, m_bheight / 2 + 1);
+ } else if (pos == HexPoint.SOUTH) {
+ return getLocation(m_bwidth / 2 - 1, m_bheight + 1);
+ } else if (pos == HexPoint.NORTH) {
+ return getLocation(m_bwidth / 2 + 1, -2);
+ }
+ return getLocation(pos.x, pos.y);
+ }
+
+ protected int calcFieldWidth(int w, int h, int bw, int bh) {
+ return w / (bw + (bh - 1) / 2 + 2);
+ }
+
+ protected int calcFieldHeight(int w, int h, int bw, int bh) {
+ return h / (bh + 2);
+ }
+
+ protected int calcStepSize() {
+ return m_fieldWidth / 4 + m_fieldWidth / 2;
+ }
+
+ protected int calcBoardWidth() {
+ return (m_bwidth + m_bheight - 1) * m_step;
+ }
+
+ protected int calcBoardHeight() {
+ return m_bheight * m_fieldHeight + (m_bwidth - m_bheight) * m_fieldHeight / 2;
+ }
+
+ protected Polygon[] calcCellOutlines(GuiField field[]) {
+ Polygon[] outline = new Polygon[field.length];
+ for (int x = 0; x < outline.length; x++) {
+ Point p = getLocation(field[x].getPoint());
+ outline[x] = Hexagon.createHorizontalHexagon(p, m_fieldWidth, m_fieldHeight);
+ }
+ return outline;
+ }
+
+ protected void drawLabels(Graphics g, boolean alphatop) {
+ int xoffset;
+ String string;
+ g.setColor(Color.black);
+
+ xoffset = 0;
+ for (int x = 0; x < m_bwidth; x++) {
+ if (alphatop) string = Character.toString((char) ((int) 'A' + x));
+ else string = Integer.toString(x + 1);
+ drawLabel(g, getLocation(x, -1), string, xoffset);
+ drawLabel(g, getLocation(x, m_bheight), string, xoffset);
+ }
+ xoffset = 0;
+ for (int y = 0; y < m_bheight; y++) {
+ if (!alphatop) string = Character.toString((char) ((int) 'A' + y));
+ else string = Integer.toString(y + 1);
+ drawLabel(g, getLocation(-1, y), string, xoffset);
+ drawLabel(g, getLocation(m_bwidth, y), string, xoffset);
+ }
+ }
+
+ protected Polygon[] m_outline;
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/BoardDrawerFlat.java b/src/main/java/hexgui/gui/BoardDrawerFlat.java
new file mode 100644
index 0000000..4c637eb
--- /dev/null
+++ b/src/main/java/hexgui/gui/BoardDrawerFlat.java
@@ -0,0 +1,109 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import hexgui.hex.HexPoint;
+import hexgui.util.Hexagon;
+
+import java.awt.*;
+
+// ----------------------------------------------------------------------------
+
+public class BoardDrawerFlat extends BoardDrawerBase {
+
+ protected static final double ASPECT_RATIO = 1.0 / 1.1547;
+
+ public BoardDrawerFlat() {
+ super();
+ loadBackground("hexgui/images/wood.png");
+ m_aspect_ratio = ASPECT_RATIO;
+ }
+
+ /**
+ * Returns the location in the window of the field with coordinates (x,y).
+ * Coordinates increase to the right and down, with the top left of the board having coordinates
+ * (0,0). Negative values are acceptable.
+ *
+ * @param x the x coordinate of the field.
+ * @param y the y coordinate of the field.
+ * @return the center of the field at (x,y).
+ */
+ protected Point getLocation(int x, int y) {
+ Point ret = new Point();
+ ret.x = m_marginX + y * m_fieldWidth / 2 + x * m_fieldWidth;
+ ret.y = m_marginY + y * m_step;
+ return ret;
+ }
+
+ /** Returns the location of the field with HexPoint pos. */
+ protected Point getLocation(HexPoint pos) {
+ if (pos == HexPoint.EAST) {
+ return getLocation(m_bwidth + 1, m_bheight / 2 - 1);
+ } else if (pos == HexPoint.WEST) {
+ return getLocation(-2, m_bheight / 2 + 1);
+ } else if (pos == HexPoint.SOUTH) {
+ return getLocation(m_bwidth / 2 - 1, m_bheight + 1);
+ } else if (pos == HexPoint.NORTH) {
+ return getLocation(m_bwidth / 2 + 1, -2);
+ }
+ return getLocation(pos.x, pos.y);
+ }
+
+ protected int calcFieldWidth(int w, int h, int bw, int bh) {
+ return w / (bw + (bh - 1) / 2 + 2);
+ }
+
+ protected int calcFieldHeight(int w, int h, int bw, int bh) {
+ return h / ((bh + 1) / 2 + (bh / 4) + 4);
+ }
+
+ protected int calcStepSize() {
+ return m_fieldHeight / 4 + m_fieldHeight / 2;
+ }
+
+ protected int calcBoardWidth() {
+ return m_bwidth * m_fieldWidth + (m_bheight - 1) * m_fieldWidth / 2;
+ }
+
+ protected int calcBoardHeight() {
+ return m_fieldHeight * (m_bheight + 1) / 2 + m_fieldHeight * m_bheight / 4;
+ }
+
+ protected Polygon[] calcCellOutlines(GuiField field[]) {
+ Polygon outline[] = new Polygon[field.length];
+ for (int x = 0; x < outline.length; x++) {
+ Point p = getLocation(field[x].getPoint());
+ outline[x] = Hexagon.createVerticalHexagon(p, m_fieldWidth, m_fieldHeight);
+ }
+ return outline;
+ }
+
+ protected void drawLabels(Graphics g, boolean alphatop) {
+ String string;
+ int xoffset, yoffset;
+ g.setColor(Color.black);
+
+ xoffset = m_fieldWidth / 2;
+ yoffset = 1;
+ for (int x = 0; x < m_bwidth; x++) {
+ if (alphatop) string = Character.toString((char) ((int) 'A' + x));
+ else string = Integer.toString(x + 1);
+ drawLabel(g, getLocation(x, -1), string, xoffset);
+ drawLabel(g, getLocation(x - yoffset, m_bheight), string, xoffset);
+ }
+ xoffset = 0;
+ yoffset = 0;
+ for (int y = 0; y < m_bheight; y++) {
+ if (!alphatop) string = Character.toString((char) ((int) 'A' + y));
+ else string = Integer.toString(y + 1);
+ drawLabel(g, getLocation(-1, y), string, xoffset);
+ drawLabel(g, getLocation(m_bwidth, y - yoffset), string, xoffset);
+ }
+ }
+
+ protected Polygon m_outline[];
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/BoardDrawerFlat2.java b/src/main/java/hexgui/gui/BoardDrawerFlat2.java
new file mode 100644
index 0000000..86e9ab9
--- /dev/null
+++ b/src/main/java/hexgui/gui/BoardDrawerFlat2.java
@@ -0,0 +1,109 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import hexgui.hex.HexPoint;
+import hexgui.util.Hexagon;
+
+import java.awt.*;
+
+// ----------------------------------------------------------------------------
+
+public class BoardDrawerFlat2 extends BoardDrawerBase {
+
+ protected static final double ASPECT_RATIO = 1.0 / 1.1547;
+
+ public BoardDrawerFlat2() {
+ super();
+ loadBackground("hexgui/images/wood.png");
+ m_aspect_ratio = ASPECT_RATIO;
+ }
+
+ /**
+ * Returns the location in the window of the field with coordinates (x,y).
+ * Coordinates increase to the right and down, with the top left of the board having coordinates
+ * (0,0). Negative values are acceptable.
+ *
+ * @param x the x coordinate of the field.
+ * @param y the y coordinate of the field.
+ * @return the center of the field at (x,y).
+ */
+ protected Point getLocation(int x, int y) {
+ Point ret = new Point();
+ ret.x = m_marginX + y * m_fieldWidth / 2 + x * m_fieldWidth;
+ ret.y = m_marginY + (m_bheight - 1 - y) * m_step;
+ return ret;
+ }
+
+ /** Returns the location of the field with HexPoint pos. */
+ protected Point getLocation(HexPoint pos) {
+ if (pos == HexPoint.EAST) {
+ return getLocation(m_bwidth + 1, m_bheight / 2 - 1);
+ } else if (pos == HexPoint.WEST) {
+ return getLocation(-2, m_bheight / 2 + 1);
+ } else if (pos == HexPoint.SOUTH) {
+ return getLocation(m_bwidth / 2 - 1, m_bheight + 1);
+ } else if (pos == HexPoint.NORTH) {
+ return getLocation(m_bwidth / 2 + 1, -2);
+ }
+ return getLocation(pos.x, pos.y);
+ }
+
+ protected int calcFieldWidth(int w, int h, int bw, int bh) {
+ return w / (bw + (bh - 1) / 2 + 2);
+ }
+
+ protected int calcFieldHeight(int w, int h, int bw, int bh) {
+ return h / ((bh + 1) / 2 + (bh / 4) + 4);
+ }
+
+ protected int calcStepSize() {
+ return m_fieldHeight / 4 + m_fieldHeight / 2;
+ }
+
+ protected int calcBoardWidth() {
+ return m_bwidth * m_fieldWidth + (m_bheight - 1) * m_fieldWidth / 2;
+ }
+
+ protected int calcBoardHeight() {
+ return m_fieldHeight * (m_bheight + 1) / 2 + m_fieldHeight * m_bheight / 4;
+ }
+
+ protected Polygon[] calcCellOutlines(GuiField field[]) {
+ Polygon outline[] = new Polygon[field.length];
+ for (int x = 0; x < outline.length; x++) {
+ Point p = getLocation(field[x].getPoint());
+ outline[x] = Hexagon.createVerticalHexagon(p, m_fieldWidth, m_fieldHeight);
+ }
+ return outline;
+ }
+
+ protected void drawLabels(Graphics g, boolean alphatop) {
+ String string;
+ int xoffset, yoffset;
+ g.setColor(Color.black);
+
+ xoffset = m_fieldWidth / 2;
+ yoffset = 1;
+ for (int x = 0; x < m_bwidth; x++) {
+ if (alphatop) string = Character.toString((char) ((int) 'A' + x));
+ else string = Integer.toString(x + 1);
+ drawLabel(g, getLocation(x, -1), string, xoffset);
+ drawLabel(g, getLocation(x - yoffset, m_bheight), string, xoffset);
+ }
+ xoffset = 0;
+ yoffset = 0;
+ for (int y = 0; y < m_bheight; y++) {
+ if (!alphatop) string = Character.toString((char) ((int) 'A' + y));
+ else string = Integer.toString(y + 1);
+ drawLabel(g, getLocation(-1, y), string, xoffset);
+ drawLabel(g, getLocation(m_bwidth, y - yoffset), string, xoffset);
+ }
+ }
+
+ protected Polygon m_outline[];
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/BoardDrawerGo.java b/src/main/java/hexgui/gui/BoardDrawerGo.java
new file mode 100644
index 0000000..068f188
--- /dev/null
+++ b/src/main/java/hexgui/gui/BoardDrawerGo.java
@@ -0,0 +1,128 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import hexgui.hex.HexPoint;
+
+import java.awt.*;
+
+// ----------------------------------------------------------------------------
+
+public class BoardDrawerGo extends BoardDrawerBase {
+ public BoardDrawerGo() {
+ super();
+ loadBackground("hexgui/images/wood.png");
+ }
+
+ protected Point getLocation(int x, int y) {
+ Point ret = new Point();
+ ret.x = m_marginX + (x + 2) * m_fieldWidth;
+ ret.y = m_marginY + (y + 2) * m_fieldHeight;
+ return ret;
+ }
+
+ // FIXME: center stones on even length sides!!
+ protected Point getLocation(HexPoint pos) {
+ if (pos == HexPoint.EAST) {
+ return getLocation(m_bwidth + 1, m_bheight / 2);
+ } else if (pos == HexPoint.WEST) {
+ return getLocation(-2, m_bheight / 2);
+ } else if (pos == HexPoint.SOUTH) {
+ return getLocation(m_bwidth / 2, m_bheight + 1);
+ } else if (pos == HexPoint.NORTH) {
+ return getLocation(m_bwidth / 2, -2);
+ }
+ return getLocation(pos.x, pos.y);
+ }
+
+ protected int calcFieldWidth(int w, int h, int bw, int bh) {
+ return w / (bw + 4);
+ }
+
+ protected int calcFieldHeight(int w, int h, int bw, int bh) {
+ return h / (bh + 4);
+ }
+
+ // FIXME: not needed... something is wrong with the api?
+ protected int calcStepSize() {
+ return 0;
+ }
+
+ protected int calcBoardWidth() {
+ return (m_bwidth + 4) * m_fieldWidth;
+ }
+
+ protected int calcBoardHeight() {
+ return (m_bheight + 4) * m_fieldHeight;
+ }
+
+ protected Polygon[] calcCellOutlines(GuiField field[]) {
+ int w = m_fieldWidth / 2;
+ int h = m_fieldHeight / 2;
+ Polygon outline[] = new Polygon[field.length];
+ for (int i = 0; i < field.length; i++) {
+ Point c = getLocation(field[i].getPoint());
+ outline[i] = new Polygon();
+ outline[i].addPoint(c.x - w, c.y - h);
+ outline[i].addPoint(c.x + w, c.y - h);
+ outline[i].addPoint(c.x + w, c.y + h);
+ outline[i].addPoint(c.x - w, c.y + h);
+ }
+ return outline;
+ }
+
+ protected void drawCells(Graphics g, GuiField field[]) {
+ g.setColor(Color.black);
+ Point p = getLocation(0, 0);
+ int x = p.x;
+ int y = p.y;
+ for (int i = 0; i < m_bheight; i++) {
+ g.drawLine(
+ x, y + i * m_fieldHeight, x + (m_bwidth - 1) * m_fieldWidth, y + i * m_fieldHeight);
+ }
+ for (int i = 0; i < m_bwidth; i++) {
+ g.drawLine(
+ x + i * m_fieldWidth, y, x + i * m_fieldWidth, y + (m_bheight - 1) * m_fieldHeight);
+ }
+ // diagonal lines from left edge
+ for (int i = 1; i < m_bheight; i++) {
+ int j = Math.min(i, m_bwidth - 1);
+ g.drawLine(x, y + i * m_fieldHeight, x + j * m_fieldWidth, y + (i - j) * m_fieldHeight);
+ }
+ // diagonal lines from bottom edge
+ for (int i = 1; i < m_bwidth; i++) {
+ int j = Math.min(m_bwidth - i - 1, m_bheight - 1);
+ int k = Math.max(0, (i + m_bheight - 1) - (m_bwidth - 1));
+ g.drawLine(
+ x + i * m_fieldWidth,
+ y + (m_bheight - 1) * m_fieldHeight,
+ x + (i + j) * m_fieldWidth,
+ y + k * m_fieldHeight);
+ }
+ }
+
+ protected void drawLabels(Graphics g, boolean alphatop) {
+ String string;
+ int xoffset, yoffset;
+ g.setColor(Color.black);
+
+ xoffset = yoffset = 0;
+ for (int x = 0; x < m_bwidth; x++) {
+ if (alphatop) string = Character.toString((char) ((int) 'A' + x));
+ else string = Integer.toString(x + 1);
+ drawLabel(g, getLocation(x, -1), string, xoffset);
+ drawLabel(g, getLocation(x, m_bheight), string, xoffset);
+ }
+ xoffset = yoffset = 0;
+ for (int y = 0; y < m_bheight; y++) {
+ if (!alphatop) string = Character.toString((char) ((int) 'A' + y));
+ else string = Integer.toString(y + 1);
+ drawLabel(g, getLocation(-1, y), string, xoffset);
+ drawLabel(g, getLocation(m_bwidth, y), string, xoffset);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/BoardDrawerY.java b/src/main/java/hexgui/gui/BoardDrawerY.java
new file mode 100644
index 0000000..1b805e7
--- /dev/null
+++ b/src/main/java/hexgui/gui/BoardDrawerY.java
@@ -0,0 +1,107 @@
+// ----------------------------------------------------------------------------
+package hexgui.gui;
+
+import hexgui.hex.HexPoint;
+import hexgui.util.Hexagon;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+// ----------------------------------------------------------------------------
+
+public class BoardDrawerY extends BoardDrawerBase {
+ protected static final double ASPECT_RATIO = 1.0 / 1.1547;
+
+ public BoardDrawerY() {
+ super();
+ loadBackground("hexgui/images/wood.png");
+ m_aspect_ratio = ASPECT_RATIO;
+ }
+
+ /**
+ * Returns the location in the window of the field with coordinates (x,y).
+ * Coordinates increase to the right and down, with the top left of the board having coordinates
+ * (0,0). Negative values are acceptable.
+ *
+ * @param x the x coordinate of the field.
+ * @param y the y coordinate of the field.
+ * @return the center of the field at (x,y).
+ */
+ protected Point getLocation(int x, int y) {
+ Point ret = new Point();
+ int center = m_marginX + m_bwidth * m_fieldWidth / 2;
+ ret.x = center - y * m_fieldWidth / 2 + x * m_fieldWidth;
+ ret.y = m_marginY + y * m_step;
+ return ret;
+ }
+
+ /** Returns the location of the field with HexPoint pos. */
+ protected Point getLocation(HexPoint pos) {
+ if (pos == HexPoint.EAST) {
+ return getLocation(m_bheight / 2 + 2, m_bheight / 2);
+ } else if (pos == HexPoint.WEST) {
+ return getLocation(-2, m_bheight / 2);
+ } else if (pos == HexPoint.SOUTH) {
+ return getLocation(m_bwidth / 2 + 1, m_bheight + 1);
+ }
+ return getLocation(pos.x, pos.y);
+ }
+
+ protected int calcFieldWidth(int w, int h, int bw, int bh) {
+ return w / (bw + 3); // width + 2 cells for labels + 1 for spacing
+ }
+
+ protected int calcFieldHeight(int w, int h, int bw, int bh) {
+ // each row takes 3/4 of the height of hex
+ // need 2 extra rows for labels + 1 row of spacing
+ return h / (3 * bh / 4 + 3);
+ }
+
+ protected int calcStepSize() {
+ return m_fieldHeight / 4 + m_fieldHeight / 2;
+ }
+
+ protected int calcBoardWidth() {
+ return m_bwidth * m_fieldWidth;
+ }
+
+ protected int calcBoardHeight() {
+ // return m_fieldHeight*(m_bheight+1)/2
+ // + m_fieldHeight*m_bheight/4;
+ return 3 * m_fieldHeight / 4 * (m_bheight + 2);
+ }
+
+ protected Polygon[] calcCellOutlines(GuiField field[]) {
+ Polygon outline[] = new Polygon[field.length];
+ for (int x = 0; x < outline.length; x++) {
+ Point p = getLocation(field[x].getPoint());
+ outline[x] = Hexagon.createVerticalHexagon(p, m_fieldWidth, m_fieldHeight);
+ }
+ return outline;
+ }
+
+ protected void drawLabels(Graphics g, boolean alphatop) {
+ String string;
+ int xoffset, yoffset;
+ g.setColor(Color.black);
+
+ xoffset = m_fieldWidth / 2;
+ yoffset = 1;
+ for (int x = 0; x < m_bwidth; x++) {
+ string = Character.toString((char) ((int) 'A' + x));
+ // drawLabel(g, getLocation(x, -1), string, xoffset);
+ drawLabel(g, getLocation(x, m_bheight), string, xoffset);
+ }
+ xoffset = 0;
+ yoffset = 0;
+ for (int y = 0; y < m_bheight; y++) {
+ string = Integer.toString(y + 1);
+ drawLabel(g, getLocation(-1, y), string, xoffset);
+ drawLabel(g, getLocation(y + 1, y - yoffset), string, xoffset);
+ }
+ }
+
+ protected Polygon m_outline[];
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/BoardSizeDialog.java b/src/main/java/hexgui/gui/BoardSizeDialog.java
new file mode 100644
index 0000000..c3db091
--- /dev/null
+++ b/src/main/java/hexgui/gui/BoardSizeDialog.java
@@ -0,0 +1,28 @@
+// ----------------------------------------------------------------------------
+// $Id: HexGui.java 30 2006-10-27 05:09:12Z broderic $
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import hexgui.hex.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/** Dialog for entering a board size. */
+public final class BoardSizeDialog {
+ /**
+ * Run dialog.
+ *
+ * @return Board dimensions as string in format "w x h"; returns "-1 x -1" if aborted.
+ */
+ public static String show(Component parent, Dimension current) {
+ String ret;
+ String value = "" + current.width + " x " + current.height;
+ ret = JOptionPane.showInputDialog(parent, "Board size", value);
+ return ret;
+ }
+
+ /** Make constructor unavailable; class is for namespace only. */
+ private BoardSizeDialog() {}
+}
diff --git a/src/main/java/hexgui/gui/ChooseProgramDialog.java b/src/main/java/hexgui/gui/ChooseProgramDialog.java
new file mode 100644
index 0000000..620a56e
--- /dev/null
+++ b/src/main/java/hexgui/gui/ChooseProgramDialog.java
@@ -0,0 +1,93 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import hexgui.hex.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.Vector;
+import javax.swing.*;
+import javax.swing.text.html.HTMLEditorKit;
+
+/** The actual dialog. */
+class ChooseProgramDialog extends JDialog implements ActionListener {
+ public ChooseProgramDialog(Frame owner, String title, Vector programs) {
+ super(owner, true);
+ setTitle(title);
+
+ m_programs = programs;
+
+ // create gui
+ JEditorPane info = new JEditorPane();
+ info.setEditable(false);
+ info.setEditorKit(new HTMLEditorKit());
+ info.setText("Select program from list below.");
+ add(info, BorderLayout.NORTH);
+ add(createProgramPanel(), BorderLayout.CENTER);
+ add(createButtonPanel(), BorderLayout.SOUTH);
+
+ pack();
+
+ setResizable(false);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ String cmd = e.getActionCommand();
+ if (cmd.equals("OK")) {
+
+ m_program = m_programs.get(m_list.getSelectedIndex());
+
+ // set the program
+ setVisible(false);
+
+ } else if (cmd.equals("Cancel")) {
+ setVisible(false);
+ }
+ }
+
+ public Program getProgram() {
+ return m_program;
+ }
+
+ private JPanel createProgramPanel() {
+ JPanel panel = new JPanel();
+
+ m_list = new JList(m_programs);
+ m_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ m_list.setVisibleRowCount(10);
+ m_list.setSelectedIndex(0);
+ m_list.setPreferredSize(new Dimension(200, 250));
+
+ JScrollPane sc = new JScrollPane(m_list);
+ sc.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+
+ panel.add(sc);
+
+ return panel;
+ }
+
+ private JPanel createButtonPanel() {
+ JPanel panel = new JPanel();
+
+ JButton button = new JButton(" OK ");
+ button.addActionListener(this);
+ button.setActionCommand("OK");
+ panel.add(button);
+
+ button = new JButton("Cancel");
+ button.addActionListener(this);
+ button.setActionCommand("Cancel");
+ panel.add(button);
+
+ return panel;
+ }
+
+ JList m_list;
+
+ Vector m_programs;
+ Program m_program;
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/Comment.java b/src/main/java/hexgui/gui/Comment.java
new file mode 100644
index 0000000..fae2d24
--- /dev/null
+++ b/src/main/java/hexgui/gui/Comment.java
@@ -0,0 +1,62 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+/** Displays comment for current node. */
+public class Comment extends JScrollPane implements DocumentListener {
+
+ public interface Listener {
+ public void commentChanged(String msg);
+ }
+
+ public Comment(Listener listener) {
+ m_listener = listener;
+ m_textPane = new JTextArea();
+ m_textPane.setFont(MONOSPACED_FONT);
+ m_textPane.setLineWrap(true);
+ m_textPane.setWrapStyleWord(true);
+ setViewportView(m_textPane);
+ setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ m_textPane.getDocument().addDocumentListener(this);
+ // setPreferredSize(new Dimension(200, 400));
+ }
+
+ public void setText(String text) {
+ m_textPane.setText(text);
+ m_textPane.getCaret().setDot(0);
+ }
+
+ public void changedUpdate(DocumentEvent e) {
+ notifyChanged();
+ }
+
+ public void removeUpdate(DocumentEvent e) {
+ notifyChanged();
+ }
+
+ public void insertUpdate(DocumentEvent e) {
+ notifyChanged();
+ }
+
+ private void notifyChanged() {
+ m_listener.commentChanged(m_textPane.getText());
+ }
+
+ JTextArea m_textPane;
+
+ Listener m_listener;
+
+ private static final Font MONOSPACED_FONT = Font.decode("Monospaced");
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/EditProgramDialog.java b/src/main/java/hexgui/gui/EditProgramDialog.java
new file mode 100644
index 0000000..6080811
--- /dev/null
+++ b/src/main/java/hexgui/gui/EditProgramDialog.java
@@ -0,0 +1,129 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import hexgui.util.SpringUtilities;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.text.html.HTMLEditorKit;
+
+/** Dialog for adding/editing new programs. */
+public final class EditProgramDialog extends JDialog implements ActionListener {
+
+ public EditProgramDialog(Frame owner, Program program, String title, boolean is_new) {
+ super(owner, true);
+ m_program = program;
+
+ setTitle(title);
+ init(is_new);
+ }
+
+ private void init(boolean is_new) {
+ JEditorPane info = new JEditorPane();
+ info.setEditable(false);
+ info.setEditorKit(new HTMLEditorKit());
+
+ if (!is_new) {
+ info.setText("Edit the program's fields.");
+ } else {
+ info.setText(
+ "Enter command for new Hex program
"
+ + "The command can be simply the name of the "
+ + "executable file, or the name plus any options "
+ + "you wish to set. The working directory can be left "
+ + "blank if the program does not need a special "
+ + "working directory. Enter a simple descriptive name "
+ + "to refer to this program.");
+ }
+ add(info, BorderLayout.NORTH);
+ add(createProgramPanel(m_program), BorderLayout.CENTER);
+ add(createButtonPanel(), BorderLayout.SOUTH);
+
+ if (!is_new) {
+ setPreferredSize(new Dimension(500, 180));
+ } else {
+ setPreferredSize(new Dimension(500, 280));
+ }
+ pack();
+
+ setResizable(false);
+
+ setVisible(true);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ String cmd = e.getActionCommand();
+ if (cmd.equals("OK")) {
+
+ m_program.m_name = m_name.getText();
+ m_program.m_command = m_command.getText();
+ m_program.m_working = m_working.getText();
+
+ dispose();
+
+ } else if (cmd.equals("Cancel")) {
+ dispose();
+ }
+ }
+
+ private JPanel createProgramPanel(Program program) {
+ JPanel panel = new JPanel(new SpringLayout());
+ JLabel l;
+
+ l = new JLabel("Name:", JLabel.TRAILING);
+ panel.add(l);
+
+ m_name = new JTextField(40);
+ if (program != null) m_name.setText(program.m_name);
+ l.setLabelFor(m_name);
+ panel.add(m_name);
+
+ l = new JLabel("Command:", JLabel.TRAILING);
+ panel.add(l);
+ m_command = new JTextField(40);
+ if (program != null) m_command.setText(program.m_command);
+ l.setLabelFor(m_command);
+ panel.add(m_command);
+
+ l = new JLabel("Working Directory:", JLabel.TRAILING);
+ panel.add(l);
+ m_working = new JTextField(40);
+ if (program != null) m_working.setText(program.m_working);
+ l.setLabelFor(m_working);
+ panel.add(m_working);
+
+ SpringUtilities.makeCompactGrid(
+ panel, 3, 2, // rows, cols
+ 6, 6, // initX, initY
+ 6, 6); // xPad, yPad
+
+ return panel;
+ }
+
+ private JPanel createButtonPanel() {
+ JPanel panel = new JPanel();
+
+ JButton button = new JButton(" OK ");
+ button.addActionListener(this);
+ button.setActionCommand("OK");
+ panel.add(button);
+
+ button = new JButton("Cancel");
+ button.addActionListener(this);
+ button.setActionCommand("Cancel");
+ panel.add(button);
+
+ return panel;
+ }
+
+ JTextField m_name;
+ JTextField m_command;
+ JTextField m_working;
+
+ Program m_program;
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/FileDialogs.java b/src/main/java/hexgui/gui/FileDialogs.java
new file mode 100644
index 0000000..37c4441
--- /dev/null
+++ b/src/main/java/hexgui/gui/FileDialogs.java
@@ -0,0 +1,190 @@
+// FileDialogs.java
+
+package hexgui.gui;
+
+import hexgui.sgf.GameFileFilter;
+import hexgui.util.Platform;
+import java.awt.Component;
+import java.awt.FileDialog;
+import java.awt.Frame;
+import java.io.File;
+import java.text.MessageFormat;
+import javax.swing.JFileChooser;
+
+/** File dialogs. */
+public final class FileDialogs {
+ public static File showOpen(Component parent, String title) {
+ return showFileChooser(parent, Type.FILE_OPEN, null, false, title);
+ }
+
+ public static File showOpenSgf(Component parent) {
+ return showFileChooser(parent, Type.FILE_OPEN, null, true, null);
+ }
+
+ public static File showSave(Component parent, String title, MessageDialogs messageDialogs) {
+ return showFileChooserSave(parent, null, false, title, messageDialogs);
+ }
+
+ public static File showSaveSgf(Frame parent, MessageDialogs messageDialogs) {
+ return showFileChooserSave(parent, s_lastFile, true, null, messageDialogs);
+ }
+
+ /** File selection, unknown whether for load or save. */
+ public static File showSelectFile(Component parent, String title) {
+ return showFileChooser(parent, Type.FILE_SELECT, s_lastFile, false, title);
+ }
+
+ public static void setLastFile(File file) {
+ s_lastFile = file;
+ }
+
+ private enum Type {
+ /** Dialog type for opening a file. */
+ FILE_OPEN,
+
+ /** Dialog type for saving to a file. */
+ FILE_SAVE,
+
+ /**
+ * Dialog type for selecting a file. Use this type, if a file name should be selected, but it is
+ * not known what the file name is used for and if the file already exists.
+ *
+ * @deprecated Not supported by native AWT FileDialog
+ */
+ FILE_SELECT
+ }
+
+ /**
+ * Use native AWT-dialogs. They are used on Mac OS X because JFileChooser looks too different from
+ * the native dialogs (Java 1.5), and on Windows because JFileChooser is too slow on Windows XP
+ * (startup and directory changing takes up to 10 sec; Java 1.6)
+ */
+ private static final boolean NATIVE_DIALOGS = (Platform.isMac() || Platform.isWindows());
+
+ private static File s_lastFile;
+
+ /** Make constructor unavailable; class is for namespace only. */
+ private FileDialogs() {}
+
+ /**
+ * Find first parent that is a Frame.
+ *
+ * @return null If no such parent.
+ */
+ private static Frame findParentFrame(Component component) {
+ while (component != null)
+ if (component instanceof Frame) return (Frame) component;
+ else component = component.getParent();
+ return null;
+ }
+
+ private static File showFileChooser(
+ Component parent, Type type, File lastFile, boolean setSgfFilter, String title) {
+ // Use native dialogs for some platforms. but not for type select
+ // There is no native dialog for select
+ if (NATIVE_DIALOGS && type != Type.FILE_SELECT) {
+ Frame frame = findParentFrame(parent);
+ return showFileChooserAWT(frame, type, title);
+ }
+ return showFileChooserSwing(parent, type, lastFile, setSgfFilter, title);
+ }
+
+ private static File showFileChooserSave(
+ Component parent,
+ File lastFile,
+ boolean setSgfFilter,
+ String title,
+ MessageDialogs messageDialogs) {
+ File file = showFileChooser(parent, Type.FILE_SAVE, lastFile, setSgfFilter, title);
+ if (NATIVE_DIALOGS)
+ // Overwrite warning is already part of FileDialog
+ return file;
+ while (file != null) {
+ if (file.exists()) {
+ String mainMessage = MessageFormat.format("Replace file \"{0}\"", file.getName());
+ String optionalMessage = "If you overwrite the file, the previous version will be lost.";
+ if (!messageDialogs.showQuestion(parent, mainMessage, optionalMessage, "Replace", true)) {
+ file = showFileChooser(parent, Type.FILE_SAVE, lastFile, setSgfFilter, title);
+ continue;
+ }
+ }
+ break;
+ }
+ return file;
+ }
+
+ private static File showFileChooserAWT(Frame parent, Type type, String title) {
+ FileDialog dialog = new FileDialog(parent);
+ if (title == null) {
+ switch (type) {
+ case FILE_OPEN:
+ title = "Open";
+ break;
+ case FILE_SAVE:
+ title = "Save";
+ break;
+ default:
+ assert false;
+ }
+ }
+ dialog.setTitle(title);
+ int mode = FileDialog.LOAD;
+ if (type == Type.FILE_SAVE) mode = FileDialog.SAVE;
+ dialog.setMode(mode);
+ /* Commented out, because there is no way to change the filter by the
+ user (at least not on Linux)
+ if (setSgfFilter)
+ dialog.setFilenameFilter(new FilenameFilter() {
+ public boolean accept(File dir, String name)
+ {
+ return name.toLowerCase().endsWith("sgf");
+ }
+ });
+ */
+ // dialog.setLocationRelativeTo(parent); // Java <= 1.4
+ dialog.setLocationByPlatform(true);
+ dialog.setVisible(true);
+ if (dialog.getFile() == null) return null;
+ return new File(dialog.getDirectory(), dialog.getFile());
+ }
+
+ private static File showFileChooserSwing(
+ Component parent, Type type, File lastFile, boolean setSgfFilter, String title) {
+ JFileChooser chooser;
+ if (s_lastFile == null) {
+ if (Platform.isMac())
+ // user.dir is application directory on Mac, which is bad
+ // I have not found a way to set it to user home in Info.plist
+ // so I use null here, which sets is to the user home
+ chooser = new JFileChooser((String) null);
+ else chooser = new JFileChooser(System.getProperty("user.dir"));
+ } else chooser = new JFileChooser(s_lastFile);
+ chooser.setMultiSelectionEnabled(false);
+ javax.swing.filechooser.FileFilter filter = new GameFileFilter();
+ chooser.addChoosableFileFilter(filter);
+ if (setSgfFilter) {
+ chooser.setFileFilter(filter);
+ } else chooser.setFileFilter(chooser.getAcceptAllFileFilter());
+ if (type == Type.FILE_SAVE) {
+ if (lastFile != null && lastFile.isFile() && lastFile.exists())
+ chooser.setSelectedFile(lastFile);
+ }
+ if (title != null) chooser.setDialogTitle(title);
+ int ret;
+ switch (type) {
+ case FILE_SAVE:
+ ret = chooser.showSaveDialog(parent);
+ break;
+ case FILE_OPEN:
+ ret = chooser.showOpenDialog(parent);
+ break;
+ default:
+ ret = chooser.showDialog(parent, "Select");
+ break;
+ }
+ if (ret != JFileChooser.APPROVE_OPTION) return null;
+ File file = chooser.getSelectedFile();
+ s_lastFile = file;
+ return file;
+ }
+}
diff --git a/src/main/java/hexgui/gui/GameInfoPanel.java b/src/main/java/hexgui/gui/GameInfoPanel.java
new file mode 100644
index 0000000..0dbf3c2
--- /dev/null
+++ b/src/main/java/hexgui/gui/GameInfoPanel.java
@@ -0,0 +1,102 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import hexgui.game.Clock;
+import hexgui.hex.HexColor;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+import javax.swing.*;
+
+/** Displays info about the current game. */
+public class GameInfoPanel extends JPanel {
+ public GameInfoPanel(Clock blackClock, Clock whiteClock) {
+ JPanel panel = new JPanel();
+ add(panel, BorderLayout.CENTER);
+
+ JPanel bpanel = new JPanel();
+ bpanel.setLayout(new BoxLayout(bpanel, BoxLayout.Y_AXIS));
+ URL bURL = getURL("hexgui/images/black-24x24.png");
+ JLabel blab = new JLabel(new ImageIcon(bURL));
+ blab.setAlignmentX(Component.CENTER_ALIGNMENT);
+ bpanel.add(blab);
+ bpanel.add(new GuiClock(HexColor.BLACK, blackClock));
+
+ JPanel wpanel = new JPanel();
+ wpanel.setLayout(new BoxLayout(wpanel, BoxLayout.Y_AXIS));
+ URL wURL = getURL("hexgui/images/white-24x24.png");
+ JLabel wlab = new JLabel(new ImageIcon(wURL));
+ wlab.setAlignmentX(Component.CENTER_ALIGNMENT);
+ wpanel.add(wlab);
+ wpanel.add(new GuiClock(HexColor.WHITE, whiteClock));
+
+ panel.add(bpanel);
+ panel.add(wpanel);
+
+ // setPreferredSize(new Dimension(200, 150));
+ }
+
+ private URL getURL(String filename) {
+ URL url = null;
+ if (filename != null) {
+ ClassLoader classLoader = getClass().getClassLoader();
+ url = classLoader.getResource(filename);
+ }
+ return url;
+ }
+}
+;
+
+class GuiClock extends JTextField implements Clock.Listener {
+ public GuiClock(HexColor color, Clock clock) {
+ super(COLUMNS);
+
+ m_clock = clock;
+ m_clock.addListener(this);
+
+ // Monspace font doesn't center correctly on the Mac
+ // GuiUtil.setMonospacedFont(this);
+ setEditable(false);
+ setFocusable(false);
+ setHorizontalAlignment(SwingConstants.CENTER);
+ // setMinimumSize(getPreferredSize());
+ m_color = color;
+ setText("00:00");
+ }
+
+ public final void setText(String text) {
+ super.setText(text);
+ String toolTip;
+ if (m_color == HexColor.BLACK) toolTip = "Time for Black";
+ else toolTip = "Time for White";
+ if (text.length() > COLUMNS) toolTip = toolTip + " (" + text + ")";
+ setToolTipText(toolTip);
+ }
+
+ public void clockChanged() {
+ int elapsed = m_clock.elapsed();
+ int minutes = elapsed / 60000;
+ int seconds = (elapsed % 60000) / 1000;
+ String min, sec;
+
+ min = (minutes < 10) ? "0" + minutes : "" + minutes;
+ sec = (seconds < 10) ? "0" + seconds : "" + seconds;
+ setText(min + ":" + sec);
+ }
+
+ /** Serial version to suppress compiler warning. Contains a marker comment for serialver.sf.net */
+ private static final long serialVersionUID = 0L; // SUID
+
+ private static final int COLUMNS = 5;
+
+ private final HexColor m_color;
+
+ private Clock m_clock;
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/GuiBoard.java b/src/main/java/hexgui/gui/GuiBoard.java
new file mode 100644
index 0000000..ea0cae4
--- /dev/null
+++ b/src/main/java/hexgui/gui/GuiBoard.java
@@ -0,0 +1,701 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import hexgui.game.Node;
+import hexgui.hex.*;
+import hexgui.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.math.BigInteger;
+import java.net.URL;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.Vector;
+import javax.swing.*;
+import javax.swing.border.EtchedBorder;
+
+// ----------------------------------------------------------------------------
+
+/** Gui Board. */
+public final class GuiBoard extends JPanel implements Printable {
+ /** Callback for clicks on a field. */
+ public interface Listener {
+ void panelClicked();
+
+ void fieldClicked(HexPoint point, boolean ctrl, boolean shift);
+
+ void fieldDoubleClicked(HexPoint point, boolean ctrl, boolean shift);
+ }
+
+ private static final boolean DEFAULT_FLIPPED = true;
+
+ public static final int HEXBOARD = 0;
+ public static final int YBOARD = 1;
+
+ /** Constructor. */
+ public GuiBoard(Listener listener, GuiPreferences preferences) {
+ m_image = null;
+ m_listener = listener;
+ m_preferences = preferences;
+ m_arrows = new Vector>();
+
+ initSize(
+ HEXBOARD,
+ m_preferences.getInt("gui-board-width"),
+ m_preferences.getInt("gui-board-height"));
+
+ setDrawType(m_preferences.get("gui-board-type"));
+
+ setPreferredSize(
+ new Dimension(
+ m_preferences.getInt("gui-board-pixel-width"),
+ m_preferences.getInt("gui-board-pixel-height")));
+
+ setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
+ setLayout(new BoardLayout());
+ m_boardPanel = new BoardPanel();
+ add(m_boardPanel);
+
+ MouseAdapter mouseAdapter =
+ new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ // First inform the parent that we were clicked, to
+ // handle things like keyboard focus.
+ m_listener.panelClicked();
+ GuiField f = m_drawer.getFieldContaining(e.getPoint(), m_field);
+ if (f == null) return;
+
+ int modifiers = e.getModifiers();
+ boolean ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0;
+ boolean shift = (modifiers & ActionEvent.SHIFT_MASK) != 0;
+ if (e.getClickCount() >= 2) m_listener.fieldDoubleClicked(f.getPoint(), ctrl, shift);
+ else m_listener.fieldClicked(f.getPoint(), ctrl, shift);
+ }
+ };
+ m_boardPanel.addMouseListener(mouseAdapter);
+ setCursorType("default");
+ setVisible(true);
+ }
+
+ // Set the cursor to one of: "default", "black", "white",
+ // "black-setup", "white-setup".
+ public void setCursorType(String name) {
+ String path;
+
+ if (name.equals("white")) {
+ path = "hexgui/images/cursor-white.png";
+ } else if (name.equals("black")) {
+ path = "hexgui/images/cursor-black.png";
+ } else if (name.equals("white-setup")) {
+ path = "hexgui/images/cursor-white-setup.png";
+ } else if (name.equals("black-setup")) {
+ path = "hexgui/images/cursor-black-setup.png";
+ } else {
+ path = null;
+ }
+
+ if (path == null) {
+ setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ return;
+ }
+
+ ClassLoader classLoader = getClass().getClassLoader();
+ URL url = classLoader.getResource(path);
+ if (url == null) {
+ System.out.println(
+ "setCursorType: could not load '" + "hexgui/images/cursor-white.png" + "'!");
+ return;
+ }
+ Image img = new ImageIcon(url).getImage();
+ Point hot = new Point(8, 8);
+ Toolkit t = getToolkit();
+ Cursor c = t.createCustomCursor(img, hot, name);
+ setCursor(c);
+ }
+
+ /**
+ * Sets the type of board drawer to use. If name is not one of the known values,
+ * "Diamond" is used.
+ *
+ * @param name one of ("Diamond", "Flat", "Flat2", "Go").
+ */
+ public void setDrawType(String name) {
+ if (name.equals("Y")) {
+ m_drawer = new BoardDrawerY();
+ initSize(YBOARD, m_width, m_height);
+ } else if (name.equals("Go")) {
+ if (m_mode != HEXBOARD) initSize(HEXBOARD, m_width, m_height);
+ m_drawer = new BoardDrawerGo();
+ m_preferences.put("gui-board-type", "Go");
+ } else if (name.equals("Diamond")) {
+ if (m_mode != HEXBOARD) initSize(HEXBOARD, m_width, m_height);
+ m_drawer = new BoardDrawerDiamond();
+ m_preferences.put("gui-board-type", "Diamond");
+ } else if (name.equals("Flat")) {
+ if (m_mode != HEXBOARD) initSize(HEXBOARD, m_width, m_height);
+ m_drawer = new BoardDrawerFlat();
+ m_preferences.put("gui-board-type", "Flat");
+ } else if (name.equals("Flat2")) {
+ if (m_mode != HEXBOARD) initSize(HEXBOARD, m_width, m_height);
+ m_drawer = new BoardDrawerFlat2();
+ m_preferences.put("gui-board-type", "Flat2");
+ } else {
+ System.out.println("GuiBoard: unknown draw type '" + name + "'.");
+ m_drawer = new BoardDrawerDiamond();
+ }
+ repaint();
+ }
+
+ /**
+ * Sets whether black and letters is on top or if white and numbers is on top. If string is
+ * invalid defaults to positive.
+ *
+ * @param orient either "Positive" or "Negative".
+ */
+ public void setOrientation(String orient) {
+ if (orient.equals("Positive")) m_preferences.put("gui-board-orientation", "positive");
+ else if (orient.equals("Negative")) m_preferences.put("gui-board-orientation", "negative");
+ else {
+ System.out.println("GuiBoard: unknown orientation '" + orient + "'.");
+ }
+ repaint();
+ }
+
+ public void initSize(int w, int h) {
+ initSize(m_mode, w, h);
+ }
+
+ /**
+ * Creates a board of the given dimensions. Dirty flag is set to false.
+ *
+ * @param m type of board to create (HEX or Y)
+ * @param w width of the board in cells
+ * @param h height of the board in cells
+ */
+ private void initSize(int m, int w, int h) {
+ System.out.println("GuiBoard.initSize: " + (m == HEXBOARD ? "(HEX) " : "(Y) ") + w + " " + h);
+
+ m_mode = m;
+ m_width = w;
+ m_height = h;
+ m_size = new Dimension(m_width, m_height);
+
+ m_dirty_stones = false;
+ clearArrows();
+
+ if (m_mode == HEXBOARD) {
+ m_field = new GuiField[w * h + 4];
+ for (int x = 0; x < w * h; x++) {
+ m_field[x] = new GuiField(HexPoint.get(x % w, x / w));
+ m_field[x].setAttributes(GuiField.DRAW_CELL_OUTLINE);
+ }
+ m_field[w * h + 0] = new GuiField(HexPoint.NORTH);
+ m_field[w * h + 1] = new GuiField(HexPoint.SOUTH);
+ m_field[w * h + 2] = new GuiField(HexPoint.WEST);
+ m_field[w * h + 3] = new GuiField(HexPoint.EAST);
+ } else {
+ int n = w * (w + 1) / 2;
+ m_field = new GuiField[n + 3];
+ for (int y = 0, i = 0; y < w; y++) {
+ for (int x = 0; x <= y; x++, i++) {
+ m_field[i] = new GuiField(HexPoint.get(x, y));
+ m_field[i].setAttributes(GuiField.DRAW_CELL_OUTLINE);
+ }
+ }
+ m_field[n + 0] = new GuiField(HexPoint.SOUTH);
+ m_field[n + 0].setAttributes(GuiField.DRAW_CELL_OUTLINE);
+ m_field[n + 1] = new GuiField(HexPoint.WEST);
+ m_field[n + 1].setAttributes(GuiField.DRAW_CELL_OUTLINE);
+ m_field[n + 2] = new GuiField(HexPoint.EAST);
+ m_field[n + 2].setAttributes(GuiField.DRAW_CELL_OUTLINE);
+ }
+ clearAll();
+ repaint();
+ }
+
+ /**
+ * Creates a board with the given dimensions. Convenience function.
+ *
+ * @param dim dimension of the board
+ * @see initSize(int, int)
+ */
+ public void initSize(Dimension dim) {
+ initSize(m_mode, dim.width, dim.height);
+ }
+
+ /**
+ * Gets the size of the board.
+ *
+ * @return size of the board as a Dimension.
+ */
+ public Dimension getBoardSize() {
+ return m_size;
+ }
+
+ public boolean isHexBoard() {
+ return m_mode == HEXBOARD;
+ }
+
+ public boolean isYBoard() {
+ return m_mode == YBOARD;
+ }
+
+ /** Clears all marks and stones from the board. */
+ public void clearAll() {
+ for (int x = 0; x < m_field.length; x++) m_field[x].clear();
+ if (m_mode == HEXBOARD) {
+ getField(HexPoint.NORTH).setColor(HexColor.BLACK);
+ getField(HexPoint.SOUTH).setColor(HexColor.BLACK);
+ getField(HexPoint.WEST).setColor(HexColor.WHITE);
+ getField(HexPoint.EAST).setColor(HexColor.WHITE);
+ } else {
+ getField(HexPoint.SOUTH).setColor(HexColor.EMPTY);
+ getField(HexPoint.WEST).setColor(HexColor.EMPTY);
+ getField(HexPoint.EAST).setColor(HexColor.EMPTY);
+ }
+ repaint();
+ }
+
+ /**
+ * Makes a copy of the current fields if the dirty flag is not already set, and then sets the
+ * dirty flag to true. See clearMarks().
+ */
+ public void aboutToDirtyStones() {
+ if (!m_dirty_stones) {
+ m_backup_field = new GuiField[m_field.length];
+ for (int i = 0; i < m_field.length; i++) m_backup_field[i] = new GuiField(m_field[i]);
+ }
+ m_dirty_stones = true;
+ }
+
+ public boolean areStonesDirty() {
+ return m_dirty_stones;
+ }
+
+ /** Adds an arrow. */
+ public void addArrow(HexPoint from, HexPoint to) {
+ m_arrows.add(new Pair(from, to));
+ repaint();
+ }
+
+ public void clearArrows() {
+ m_arrows.clear();
+ repaint();
+ }
+
+ /**
+ * Clears dynamic marks, leaving stones intact. If the dirty flag is set, revert the fields to the
+ * saved fields saved in markStonesDirty(). Dirty stones flag is set to false. See
+ * aboutToDirtyStones(). Empties the list of arrows.
+ */
+ public void clearMarks() {
+ if (m_dirty_stones) {
+ for (int i = 0; i < m_field.length; i++) {
+ m_field[i] = new GuiField(m_backup_field[i]);
+ }
+ }
+ m_dirty_stones = false;
+
+ clearArrows();
+
+ for (int x = 0; x < m_field.length; x++) {
+ m_field[x].clearAttributes(
+ GuiField.LAST_PLAYED | GuiField.SWAP_PLAYED | GuiField.DRAW_TEXT | GuiField.DRAW_ALPHA);
+ }
+ repaint();
+ }
+
+ /**
+ * Sets the given point to the given color. Special points are ignored (SWAP_SIDES, RESIGN, etc).
+ *
+ * @param point the point
+ * @param color the color to set it to.
+ */
+ public void setColor(HexPoint point, HexColor color) {
+ GuiField f = getField(point);
+ if (f != null) {
+ f.setColor(color);
+ repaint();
+ }
+ }
+
+ /**
+ * Gets the color of the specified point.
+ *
+ * @param point the point whose color we with to obtain.
+ * @return the color of point
+ */
+ public HexColor getColor(HexPoint point) {
+ GuiField f = getField(point);
+ return f.getColor();
+ }
+
+ /** Gets the field at the specified point. Special points are ignored (SWAP_SIDES, etc). */
+ public GuiField getField(HexPoint point) {
+ if (point == HexPoint.SWAP_SIDES
+ || point == HexPoint.SWAP_PIECES
+ || point == HexPoint.PASS
+ || point == HexPoint.RESIGN
+ || point == HexPoint.FORFEIT) {
+ return null;
+ }
+
+ for (int x = 0; x < m_field.length; x++) {
+ if (m_field[x].getPoint() == point) return m_field[x];
+ }
+ assert (false);
+ return null;
+ }
+
+ /**
+ * Marks the given point to show which move was played last, or clears the mark if point
+ * is null.
+ */
+ public void markLastPlayed(HexPoint point) {
+ assert (point != HexPoint.SWAP_SIDES && point != HexPoint.SWAP_PIECES);
+
+ if (m_last_played != null) {
+ m_last_played.clearAttributes(GuiField.LAST_PLAYED);
+ m_last_played = null;
+ }
+ if (point != null) {
+ m_last_played = getField(point);
+ if (m_last_played != null) {
+ m_last_played.setAttributes(GuiField.LAST_PLAYED);
+ }
+ }
+ repaint();
+ }
+
+ /** Clear swap marks */
+ public void clearSwapPlayed() {
+ for (int x = 0; x < m_field.length; x++) {
+ m_field[x].clearAttributes(GuiField.SWAP_PLAYED);
+ }
+ repaint();
+ }
+
+ /** Add swap mark to all pieces on the board (hopefully there is exactly one of them */
+ public void markSwapPlayed() {
+ for (int x = 0; x < m_field.length; x++) {
+ HexPoint p = m_field[x].getPoint();
+ if (p.is_cell() && m_field[x].getColor() != HexColor.EMPTY) {
+ m_field[x].setAttributes(GuiField.SWAP_PLAYED);
+ }
+ }
+ repaint();
+ }
+
+ /** Sets the given point's alpha color. */
+ public void setAlphaColor(HexPoint point, Color color) {
+ GuiField f = getField(point);
+ if (f != null) {
+ f.setAlphaColor(color);
+ repaint();
+ }
+ }
+
+ public void setAlphaColor(HexPoint point, Color color, float blend) {
+ GuiField f = getField(point);
+ if (f != null) {
+ f.setAlphaColor(color, blend);
+ repaint();
+ }
+ }
+
+ /** Returns the point's alpha color; null if it is 'swap-sides' or resign or similar. */
+ public Color getAlphaColor(HexPoint point) {
+ GuiField f = getField(point);
+ if (f != null) {
+ return f.getAlphaColor();
+ } else {
+ return null;
+ }
+ }
+
+ /** Sets the given point's text. */
+ public void setText(HexPoint point, String str) {
+ getField(point).setText(str);
+ repaint();
+ }
+
+ /** Sets whether this cell is selected. */
+ public void setSelected(HexPoint point, boolean selected) {
+ getField(point).setSelected(selected);
+ repaint();
+ }
+
+ /** Check if the board is full */
+ public boolean isBoardFull() {
+ for (int x = 0; x < m_field.length; x++) {
+ if (m_field[x].getColor() == HexColor.EMPTY) return false;
+ }
+ return true;
+ }
+
+ /** Count the number of pieces on the board */
+ public int numberOfPieces() {
+ int count = 0;
+ for (int x = 0; x < m_field.length; x++) {
+ HexPoint point = m_field[x].getPoint();
+ if (point == HexPoint.NORTH
+ || point == HexPoint.EAST
+ || point == HexPoint.SOUTH
+ || point == HexPoint.WEST) {
+ continue;
+ }
+ if (m_field[x].getColor() != HexColor.EMPTY) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /** Change the pieces' colors without moving them. This is only used in Y. */
+ public void swapColors() {
+ for (int x = 0; x < m_field.length; x++) {
+ HexPoint point = m_field[x].getPoint();
+ if (point == HexPoint.NORTH
+ || point == HexPoint.EAST
+ || point == HexPoint.SOUTH
+ || point == HexPoint.WEST) {
+ continue;
+ }
+ HexColor color = m_field[x].getColor();
+ m_field[x].setColor(color.otherColor());
+ }
+ }
+
+ /** Change the pieces' colors and move them. This is only used in Hex. */
+ public void swapPieces() {
+ // Due to the weird way the data structures are set up, it
+ // is tricky to move pieces to another location on the board.
+ // In particular, there is no O(1) way to find the HexField
+ // attached to a given HexPoint.
+ Map colors = new TreeMap();
+ for (int x = 0; x < m_field.length; x++) {
+ HexPoint point = m_field[x].getPoint();
+ if (point == HexPoint.NORTH
+ || point == HexPoint.EAST
+ || point == HexPoint.SOUTH
+ || point == HexPoint.WEST) {
+ continue;
+ }
+ colors.put(point, m_field[x].getColor());
+ }
+ for (int x = 0; x < m_field.length; x++) {
+ HexPoint point = m_field[x].getPoint();
+ if (point == HexPoint.NORTH
+ || point == HexPoint.EAST
+ || point == HexPoint.SOUTH
+ || point == HexPoint.WEST) {
+ continue;
+ }
+ HexPoint otherpoint = point.reflect();
+ m_field[x].setColor(colors.get(otherpoint).otherColor());
+ }
+ }
+
+ /** Stores the current state as a setup position in the given sgf node. */
+ public void storePosition(Node node) {
+ for (int x = 0; x < m_field.length; x++) {
+ HexPoint point = m_field[x].getPoint();
+ if (point == HexPoint.NORTH
+ || point == HexPoint.EAST
+ || point == HexPoint.SOUTH
+ || point == HexPoint.WEST) continue;
+
+ HexColor color = m_field[x].getColor();
+ if (color == HexColor.EMPTY) continue;
+
+ node.addSetup(color, point);
+ }
+ }
+
+ public void paintImmediately() {
+ assert SwingUtilities.isEventDispatchThread();
+ super.paintImmediately(0, 0, getWidth(), getHeight());
+ }
+
+ /** Displays this vc on the board. */
+ public void displayVC(VC vc) {
+ getField(vc.getFrom()).setAlphaColor(Color.blue);
+ getField(vc.getTo()).setAlphaColor(Color.blue);
+
+ Vector carrier = vc.getCarrier();
+ for (int i = 0; i < carrier.size(); i++) getField(carrier.get(i)).setAlphaColor(Color.green);
+
+ Vector stones = vc.getStones();
+ for (int i = 0; i < stones.size(); i++) getField(stones.get(i)).setAlphaColor(Color.red);
+
+ Vector key = vc.getKey();
+ for (int i = 0; i < key.size(); i++) getField(key.get(i)).setAlphaColor(Color.yellow);
+ }
+
+ // ------------------------------------------------------------
+
+ public int print(Graphics g, PageFormat format, int page) throws PrinterException {
+ if (page >= 1) {
+ return Printable.NO_SUCH_PAGE;
+ }
+ double width = getWidth();
+ double height = getHeight();
+ double pageWidth = format.getImageableWidth();
+ double pageHeight = format.getImageableHeight();
+ double scale = 1;
+ if (width >= pageWidth) scale = pageWidth / width;
+ double xSpace = (pageWidth - width * scale) / 2;
+ double ySpace = (pageHeight - height * scale) / 2;
+ Graphics2D g2d = (Graphics2D) g;
+ g2d.translate(format.getImageableX() + xSpace, format.getImageableY() + ySpace);
+ g2d.scale(scale, scale);
+ print(g2d);
+ return Printable.PAGE_EXISTS;
+ }
+
+ // ------------------------------------------------------------
+
+ /**
+ * Converts a hex string representing a bitset into a vector of HexPoints. This relies on m_field
+ * being ordered in a particular fashion.
+ *
+ * NOTE: THIS IS BROKEN SINCE HexPoint was changed in wolve, r182. USE BASE 64 INSTEAD!
+ *
+ *
FIXME: switch carriers to be printed as a list of HexPoints instead of as hex strings?
+ */
+ private Vector convertHexString(String str) {
+ Vector ret = new Vector();
+
+ for (int i = 0; i < str.length(); i++) {
+ BigInteger big = new BigInteger(StringUtils.reverse(str), 16);
+ for (int j = 0; j < m_field.length; j++) {
+ if (big.testBit(j)) ret.add(m_field[j].getPoint());
+ }
+ }
+
+ return ret;
+ }
+
+ /** Converts a base 64 string representing a bitset into a vector of HexPoints. */
+ private static final String m_base64 =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+
+ private Vector convertBase64String(String str) {
+
+ Vector ret = new Vector();
+ for (int i = 0; i < str.length(); i++) {
+ int v = m_base64.indexOf(str.charAt(i));
+ assert (v != -1);
+ for (int j = 0; j < 6 && i * 6 + j < HexPoint.MAX_POINTS; j++) {
+ if ((v & (1 << j)) != 0) ret.add(HexPoint.get(i * 6 + j));
+ }
+ }
+ return ret;
+ }
+
+ private GuiField[] flipFields(GuiField field[]) {
+ GuiField out[] = new GuiField[field.length];
+ for (int i = 0; i < field.length; i++) {
+ HexPoint p = field[i].getPoint();
+ out[i] = new GuiField(field[i]);
+ if (p == HexPoint.NORTH) out[i].setPoint(HexPoint.WEST);
+ else if (p == HexPoint.WEST) out[i].setPoint(HexPoint.NORTH);
+ else if (p == HexPoint.EAST) out[i].setPoint(HexPoint.SOUTH);
+ else if (p == HexPoint.SOUTH) out[i].setPoint(HexPoint.EAST);
+ else {
+ out[i].setPoint(HexPoint.get(p.y, p.x));
+ }
+ }
+ return out;
+ }
+
+ private class BoardPanel extends JPanel {
+ public BoardPanel() {
+ setFocusable(true);
+ }
+
+ public void paintComponent(Graphics graphics) {
+ int w = getWidth();
+ int h = getHeight();
+
+ if (m_image == null) {
+ m_image = createImage(w, h);
+ }
+
+ int bw = m_width;
+ int bh = m_height;
+ GuiField ff[] = m_field;
+ boolean alphaontop = true;
+ Vector> arrows = m_arrows;
+
+ boolean positive = true;
+ if (m_preferences.get("gui-board-orientation").equals("negative")) {
+ positive = false;
+ }
+ boolean flip;
+ if (m_preferences.get("gui-board-type").equals("Flat2")) {
+ flip = positive;
+ } else {
+ flip = !positive;
+ }
+
+ if (flip) {
+ bw = m_height;
+ bh = m_width;
+ alphaontop = false;
+ ff = flipFields(m_field);
+
+ arrows = new Vector>();
+ for (int i = 0; i < m_arrows.size(); i++) {
+ HexPoint p1 = m_arrows.get(i).first;
+ HexPoint p2 = m_arrows.get(i).second;
+ arrows.add(
+ new Pair(HexPoint.get(p1.y, p1.x), HexPoint.get(p2.y, p2.x)));
+ }
+ }
+
+ m_drawer.draw(m_image.getGraphics(), w, h, bw, bh, alphaontop, ff, arrows);
+ graphics.drawImage(m_image, 0, 0, null);
+ }
+
+ public void setBounds(int x, int y, int w, int h) {
+ super.setBounds(x, y, w, h);
+ m_image = null;
+ }
+ }
+
+ public void mousePressed(MouseEvent e) {}
+
+ public void mouseReleased(MouseEvent e) {}
+
+ public void mouseEntered(MouseEvent e) {}
+
+ public void mouseExited(MouseEvent e) {}
+
+ private int m_width, m_height;
+ private Dimension m_size;
+ private int m_mode;
+
+ private Image m_image;
+ private GuiField m_field[];
+ private Vector> m_arrows;
+
+ private boolean m_dirty_stones;
+ private GuiField m_backup_field[];
+
+ private GuiField m_last_played;
+
+ private BoardDrawerBase m_drawer;
+ private BoardPanel m_boardPanel;
+
+ private Listener m_listener;
+ private GuiPreferences m_preferences;
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/GuiField.java b/src/main/java/hexgui/gui/GuiField.java
new file mode 100644
index 0000000..0813301
--- /dev/null
+++ b/src/main/java/hexgui/gui/GuiField.java
@@ -0,0 +1,288 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import hexgui.hex.*;
+import hexgui.util.*;
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.event.*;
+import java.awt.geom.*;
+import javax.swing.*;
+
+// ----------------------------------------------------------------------------
+
+public class GuiField {
+ public static final int DRAW_CELL_OUTLINE = 1;
+ public static final int LAST_PLAYED = 2;
+ public static final int SWAP_PLAYED = 4;
+ public static final int DRAW_TEXT = 8;
+ public static final int DRAW_ALPHA = 16;
+ public static final int SELECTED = 32;
+
+ private static final Color COLOR_STONE_BLACK = Color.decode("#030303");
+ private static final Color COLOR_STONE_BLACK_BRIGHT = Color.decode("#666666");
+ private static final Color COLOR_STONE_WHITE = Color.decode("#d7d0c9");
+ private static final Color COLOR_STONE_WHITE_BRIGHT = Color.decode("#ffffff");
+
+ public GuiField(HexPoint p) {
+ this(p, HexColor.EMPTY, 0, null, null, 0);
+ }
+
+ public GuiField(HexPoint p, HexColor c, int attributes, String text, Color alpha, float blend) {
+ m_point = p;
+ m_color = c;
+ m_text = text;
+ m_alpha_color = alpha;
+ m_attributes = attributes;
+ m_alpha_blend = blend;
+ }
+
+ /** Creates a copy of the given field. */
+ public GuiField(GuiField f) {
+ this(
+ f.getPoint(),
+ f.getColor(),
+ f.getAttributes(),
+ f.getText(),
+ f.getAlphaColor(),
+ f.getAlphaBlend());
+ }
+
+ public static int getStoneMargin(int width) {
+ return width / 17 + 1;
+ }
+
+ public void clearAttributes() {
+ m_attributes = 0;
+ }
+
+ public void clearAttributes(int f) {
+ m_attributes &= ~f;
+ }
+
+ public void setAttributes(int f) {
+ m_attributes |= f;
+ }
+
+ public int getAttributes() {
+ return m_attributes;
+ }
+
+ public void setColor(HexColor c) {
+ m_color = c;
+ }
+
+ public HexColor getColor() {
+ return m_color;
+ }
+
+ public void setText(String str) {
+ m_text = str;
+ if (str == null) clearAttributes(DRAW_TEXT);
+ else setAttributes(DRAW_TEXT);
+ }
+
+ public String getText() {
+ return m_text;
+ }
+
+ public void setAlphaColor(Color c) {
+ m_alpha_color = c;
+ m_alpha_blend = 0.3f;
+ if (c == null) clearAttributes(DRAW_ALPHA);
+ else setAttributes(DRAW_ALPHA);
+ }
+
+ public void setAlphaColor(Color c, float blend) {
+ m_alpha_color = c;
+ m_alpha_blend = blend;
+ if (c == null) clearAttributes(DRAW_ALPHA);
+ else setAttributes(DRAW_ALPHA);
+ }
+
+ public Color getAlphaColor() {
+ return m_alpha_color;
+ }
+
+ public float getAlphaBlend() {
+ return m_alpha_blend;
+ }
+
+ public void setSelected(boolean f) {
+ if (f) {
+ setAttributes(SELECTED);
+ } else {
+ clearAttributes(SELECTED);
+ }
+ }
+
+ public void setPoint(HexPoint p) {
+ m_point = p;
+ }
+
+ public HexPoint getPoint() {
+ return m_point;
+ }
+
+ public void clear() {
+ setColor(HexColor.EMPTY);
+ }
+
+ private RadialGradientPaint getPaint(
+ int width, int height, Color colorNormal, Color colorBright) {
+ RadialGradientPaint paint;
+ int paintSize;
+ int size = (width < height) ? width : height;
+ int radius = Math.max(size / 3, 1);
+ Point2D.Double centerPoint = new Point2D.Double(width / 2 - size / 6, height / 2 - size / 6);
+ Point2D.Double radiusPoint = new Point2D.Double(radius, radius);
+ paint =
+ new RadialGradientPaint(
+ centerPoint, colorBright,
+ radiusPoint, colorNormal);
+ return paint;
+ }
+
+ public void draw(Graphics g, int x, int y, int w, int h) {
+ if (!g.hitClip(x, y, w, h)) return;
+
+ m_width = w;
+ m_height = h;
+
+ m_radius = (h < w) ? h / 2 : w / 2;
+ m_margin = getStoneMargin(m_radius * 2);
+
+ m_graphics = g.create(x - w / 2, y - h / 2, w, h);
+ if (m_graphics instanceof Graphics2D) {
+ m_graphics2D = (Graphics2D) m_graphics;
+ } else {
+ m_graphics2D = null;
+ }
+
+ if (m_color == HexColor.WHITE) {
+ drawStone(COLOR_STONE_WHITE, COLOR_STONE_WHITE_BRIGHT);
+ } else if (m_color == HexColor.BLACK) {
+ drawStone(COLOR_STONE_BLACK, COLOR_STONE_BLACK_BRIGHT);
+ }
+
+ if ((m_attributes & LAST_PLAYED) != 0) {
+ drawLastPlayed();
+ }
+
+ if ((m_attributes & SWAP_PLAYED) != 0) {
+ drawSwapPlayed();
+ }
+
+ // FIXME: this is done in BoardDrawer since we don't know
+ // anything about our shape and size and we want to cover the
+ // entire field. Should all drawing be done in board drawer?
+ // if ((m_attributes & DRAW_ALPHA) != 0) drawAlpha();
+
+ if ((m_attributes & DRAW_TEXT) != 0) drawText();
+ }
+
+ private void drawStone(Color normal, Color bright) {
+ if (m_graphics2D != null) {
+ RadialGradientPaint paint = getPaint(m_width, m_height, normal, bright);
+ m_graphics2D.setPaint(paint);
+ } else {
+ m_graphics.setColor(normal);
+ }
+
+ int size = m_radius - m_margin;
+ m_graphics.fillOval(m_width / 2 - size, m_height / 2 - size, size * 2, size * 2);
+
+ m_graphics.setPaintMode();
+ }
+
+ private void drawLastPlayed() {
+ m_graphics.setColor(Color.gray);
+ int size = (m_radius - m_margin) / 6;
+ m_graphics.fillOval(m_width / 2 - size, m_height / 2 - size, 2 * size, 2 * size);
+ }
+
+ /**
+ * Draw the given string centered at the coordinates (x,y) in the current font, with the given
+ * relative size.
+ */
+ private void drawString(String str, double x, double y, double size) {
+ double abssize = (m_radius - m_margin) * size;
+ Font f = m_graphics.getFont();
+ Font f2 = f.deriveFont((float) abssize);
+ FontMetrics m = m_graphics.getFontMetrics(f2);
+ double width = m.stringWidth(str);
+ double height = m.getAscent();
+
+ m_graphics.setFont(f2);
+ m_graphics.drawString(str, (int) (x - width / 2), (int) (y + 0.8 * height / 2));
+ m_graphics.setFont(f);
+ }
+
+ private void drawSwapPlayed() {
+ if (m_color == HexColor.BLACK) {
+ m_graphics.setColor(Color.white);
+ } else {
+ m_graphics.setColor(Color.black);
+ }
+ this.drawString("S", m_width / 2.0, m_height / 2.0, 1);
+ }
+
+ private void drawAlpha() {
+ if (m_alpha_color == null) return;
+ if (m_graphics2D == null) return;
+
+ m_graphics2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
+ m_graphics.setColor(m_alpha_color);
+ m_graphics.fillRect(
+ m_width / 2 - m_width / 4, m_height / 2 - m_height / 4, m_width / 2, m_height / 2);
+ }
+
+ private void drawText() {
+ String[] lines = m_text.split("@");
+ int nlines = lines.length;
+
+ double size = m_radius - m_margin;
+ double relheight = nlines > 1 ? 2.0 / nlines : 1.0;
+ double height = size * relheight;
+
+ double y = m_height / 2 + ((nlines - 1) * height) / 2;
+
+ for (int i = lines.length - 1; i >= 0; --i) {
+ String str = lines[i].trim();
+
+ Color color = Color.black;
+ if (getColor() == HexColor.BLACK) color = Color.white;
+
+ m_graphics.setColor(color);
+ this.drawString(str, m_width / 2, y, relheight);
+
+ y -= height;
+ }
+ }
+
+ private HexPoint m_point;
+ private HexColor m_color;
+ private int m_attributes;
+
+ private Color m_alpha_color;
+ private float m_alpha_blend;
+
+ private String m_text;
+
+ private int m_width;
+ private int m_height;
+ private int m_radius;
+ private int m_margin;
+
+ private Graphics m_graphics;
+ private Graphics2D m_graphics2D;
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/GuiMenuBar.java b/src/main/java/hexgui/gui/GuiMenuBar.java
new file mode 100644
index 0000000..739573a
--- /dev/null
+++ b/src/main/java/hexgui/gui/GuiMenuBar.java
@@ -0,0 +1,582 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+
+// ----------------------------------------------------------------------------
+
+/** Menu bar. */
+public final class GuiMenuBar {
+ public GuiMenuBar(ActionListener listener, GuiPreferences preferences) {
+ m_preferences = preferences;
+
+ m_menuBar = new JMenuBar();
+
+ m_listener = listener;
+ m_menuBar.add(createFileMenu());
+ m_menuBar.add(createProgramMenu());
+ m_menuBar.add(createGameMenu());
+ m_menuBar.add(createEditMenu());
+ m_menuBar.add(createViewMenu());
+ m_menuBar.add(createHelpMenu());
+
+ setProgramConnected(false);
+ }
+
+ public JMenuBar getJMenuBar() {
+ return m_menuBar;
+ }
+
+ public void setProgramConnected(boolean f) {
+ // m_connect_remote.setEnabled(!f);
+ m_connect_local.setEnabled(!f);
+ m_disconnect.setEnabled(f);
+ m_reconnect.setEnabled(f);
+ m_genmove.setEnabled(f);
+
+ if (f == false) {
+ setShellVisible(false);
+ m_shell_visible.setEnabled(false);
+ setAnalyzeVisible(false);
+ m_analyze_visible.setEnabled(false);
+ } else {
+ m_shell_visible.setEnabled(true);
+ m_analyze_visible.setEnabled(true);
+
+ setShellVisible(m_preferences.getBoolean("shell-show-on-connect"));
+ setAnalyzeVisible(m_preferences.getBoolean("analyze-show-on-connect"));
+ }
+ }
+
+ public void updateMenuStates(HexGui current) {
+ m_swap_pieces.setEnabled(current.isSwapAllowed());
+ m_swap_sides.setEnabled(current.isSwapAllowed());
+ }
+
+ // ----------------------------------------------------------------------
+
+ private JMenu createFileMenu() {
+ JMenu menu = new JMenu("File");
+ menu.setMnemonic(KeyEvent.VK_F);
+
+ JMenuItem item;
+ item = new JMenuItem("Open...");
+ item.setMnemonic(KeyEvent.VK_O);
+ item.addActionListener(m_listener);
+ item.setActionCommand("loadgame");
+ menu.add(item);
+
+ menu.addSeparator();
+
+ item = new JMenuItem("Save Game");
+ item.setMnemonic(KeyEvent.VK_S);
+ item.addActionListener(m_listener);
+ item.setActionCommand("savegame");
+ menu.add(item);
+
+ item = new JMenuItem("Save Game As...");
+ item.setMnemonic(KeyEvent.VK_A);
+ item.addActionListener(m_listener);
+ item.setActionCommand("savegameas");
+ menu.add(item);
+
+ item = new JMenuItem("Save Position As...");
+ item.addActionListener(m_listener);
+ item.setActionCommand("save-position-as");
+ menu.add(item);
+
+ menu.addSeparator();
+
+ item = new JMenuItem("Print Preview");
+ item.addActionListener(m_listener);
+ item.setActionCommand("print-preview");
+ menu.add(item);
+
+ item = new JMenuItem("Print...");
+ item.addActionListener(m_listener);
+ item.setActionCommand("print");
+ menu.add(item);
+
+ menu.addSeparator();
+
+ item = new JMenuItem("Exit");
+ item.setMnemonic(KeyEvent.VK_X);
+ item.addActionListener(m_listener);
+ item.setActionCommand("shutdown");
+ menu.add(item);
+
+ return menu;
+ }
+
+ // ----------------------------------------------------------------------
+ private JMenu createProgramMenu() {
+ JMenu menu = new JMenu("Program");
+ menu.setMnemonic(KeyEvent.VK_P);
+
+ JMenuItem item;
+
+ item = new JMenuItem("New Program...");
+ item.addActionListener(m_listener);
+ item.setActionCommand("new-program");
+ menu.add(item);
+
+ item = new JMenuItem("Edit Program...");
+ item.addActionListener(m_listener);
+ item.setActionCommand("edit-program");
+ menu.add(item);
+
+ item = new JMenuItem("Delete Program...");
+ item.addActionListener(m_listener);
+ item.setActionCommand("delete-program");
+ menu.add(item);
+
+ menu.addSeparator();
+
+ item = new JMenuItem("Connect Local Program...");
+ item.addActionListener(m_listener);
+ item.setActionCommand("connect-local-program");
+ m_connect_local = item;
+ menu.add(item);
+
+ // item = new JMenuItem("Connect Remote Program...");
+ // item.addActionListener(m_listener);
+ // item.setActionCommand("connect-program");
+ // item.setEnabled(false);
+ // m_connect_remote = item;
+ // menu.add(item);
+
+ menu.addSeparator();
+
+ item = new JMenuItem("Reconnect Program");
+ item.addActionListener(m_listener);
+ item.setActionCommand("reconnect-program");
+ m_reconnect = item;
+ menu.add(item);
+
+ item = new JMenuItem("Disconnect Program");
+ item.addActionListener(m_listener);
+ item.setActionCommand("disconnect-program");
+ m_disconnect = item;
+ menu.add(item);
+
+ return menu;
+ }
+
+ // ----------------------------------------------------------------------
+
+ private JMenu createGameMenu() {
+ JMenu menu = new JMenu("Game");
+ menu.setMnemonic(KeyEvent.VK_G);
+
+ JMenuItem item;
+ item = new JMenuItem("New");
+ item.setMnemonic(KeyEvent.VK_N);
+ item.addActionListener(m_listener);
+ item.setActionCommand("newgame");
+ menu.add(item);
+
+ JMenu submenu;
+
+ menu.addSeparator();
+
+ submenu = createClockMenu();
+ menu.add(submenu);
+
+ menu.addSeparator();
+
+ submenu = createToMoveMenu();
+ menu.add(submenu);
+
+ menu.addSeparator();
+
+ m_swap_pieces = new JMenuItem("Swap pieces");
+ m_swap_pieces.addActionListener(m_listener);
+ m_swap_pieces.setActionCommand("game_swap_pieces");
+ menu.add(m_swap_pieces);
+
+ m_swap_sides = new JMenuItem("Swap sides");
+ m_swap_sides.addActionListener(m_listener);
+ m_swap_sides.setActionCommand("game_swap_sides");
+ menu.add(m_swap_sides);
+
+ m_pass = new JMenuItem("Pass");
+ m_pass.addActionListener(m_listener);
+ m_pass.setActionCommand("game_pass");
+ menu.add(m_pass);
+
+ m_resign = new JMenuItem("Resign");
+ m_resign.addActionListener(m_listener);
+ m_resign.setActionCommand("game_resign");
+ menu.add(m_resign);
+
+ m_forfeit = new JMenuItem("Forfeit");
+ m_forfeit.addActionListener(m_listener);
+ m_forfeit.setActionCommand("game_forfeit");
+ menu.add(m_forfeit);
+
+ m_addsetup = new JMenuItem("Add setup node");
+ m_addsetup.addActionListener(m_listener);
+ m_addsetup.setActionCommand("game_addsetup");
+ menu.add(m_addsetup);
+
+ m_genmove = new JMenuItem("Generate Computer Move");
+ m_genmove.addActionListener(m_listener);
+ m_genmove.setActionCommand("genmove");
+ menu.add(m_genmove);
+
+ menu.addSeparator();
+
+ item = new JMenuItem("Delete Current Branch");
+ item.addActionListener(m_listener);
+ item.setActionCommand("game_delete_branch");
+ menu.add(item);
+
+ item = new JMenuItem("Make Main Branch");
+ item.addActionListener(m_listener);
+ item.setActionCommand("game_make_main_branch");
+ menu.add(item);
+
+ return menu;
+ }
+
+ private JMenu createClockMenu() {
+ JMenu menu = new JMenu("Clock");
+ JMenuItem item;
+
+ item = new JMenuItem("Start");
+ item.addActionListener(m_listener);
+ item.setActionCommand("game_start_clock");
+ menu.add(item);
+
+ item = new JMenuItem("Stop");
+ item.addActionListener(m_listener);
+ item.setActionCommand("game_stop_clock");
+ menu.add(item);
+
+ return menu;
+ }
+
+ private JMenu createToMoveMenu() {
+ JMenu menu = new JMenu("Color To Move");
+
+ m_colorGroup = new ButtonGroup();
+ String pref = m_preferences.get("first-move-color");
+
+ JRadioButtonMenuItem item;
+ item = new JRadioButtonMenuItem("black");
+ item.addActionListener(m_listener);
+ item.setActionCommand("set_to_move");
+ if (pref.equals("black")) item.setSelected(true);
+ m_colorGroup.add(item);
+ menu.add(item);
+
+ item = new JRadioButtonMenuItem("white");
+ item.addActionListener(m_listener);
+ item.setActionCommand("set_to_move");
+ if (pref.equals("white")) item.setSelected(true);
+ m_colorGroup.add(item);
+ menu.add(item);
+
+ return menu;
+ }
+
+ public String getToMove() {
+ Enumeration e = m_colorGroup.getElements();
+ AbstractButton b = (AbstractButton) e.nextElement();
+ while (!b.isSelected() && e.hasMoreElements()) {
+ b = (AbstractButton) e.nextElement();
+ }
+ return b.getText();
+ }
+
+ public void setToMove(String color) {
+ Enumeration e = m_colorGroup.getElements();
+ AbstractButton b = (AbstractButton) e.nextElement();
+ while (true) {
+ if (color.equalsIgnoreCase(b.getText())) {
+ b.setSelected(true);
+ } else {
+ b.setSelected(false);
+ }
+ if (!e.hasMoreElements()) break;
+ b = (AbstractButton) e.nextElement();
+ }
+ }
+
+ // ----------------------------------------------------------------------
+
+ private JMenu createEditMenu() {
+ JMenu menu = new JMenu("Edit");
+ menu.setMnemonic(KeyEvent.VK_E);
+
+ JMenu size = createBoardSizeMenu();
+ menu.add(size);
+
+ menu.addSeparator();
+
+ JMenuItem item;
+ item = new JMenuItem("Preferences...");
+ item.addActionListener(m_listener);
+ item.setActionCommand("show-preferences");
+
+ menu.add(item);
+
+ return menu;
+ }
+
+ private JMenu createBoardSizeMenu() {
+ JMenu menu = new JMenu("Board Size");
+ m_bsGroup = new ButtonGroup();
+
+ String sizes[] =
+ new String[] {
+ "19 x 19", "15 x 15", "14 x 14", "13 x 13", "11 x 11", "10 x 10", "9 x 9", "8 x 8",
+ "7 x 7", "6 x 6", "5 x 5", "4 x 4", "3 x 3"
+ };
+
+ String preferred =
+ m_preferences.get("gui-board-width") + " x " + m_preferences.get("gui-board-height");
+
+ boolean found = false;
+ JRadioButtonMenuItem item;
+ for (int i = 0; i < sizes.length; i++) {
+ item = new JRadioButtonMenuItem(sizes[i]);
+ item.addActionListener(m_listener);
+ item.setActionCommand("newgame");
+ if (preferred.equals(sizes[i])) {
+ item.setSelected(true);
+ found = true;
+ }
+ m_bsGroup.add(item);
+ menu.add(item);
+ }
+
+ if (!found) {
+ item = new JRadioButtonMenuItem(preferred);
+ item.addActionListener(m_listener);
+ item.setActionCommand("newgame");
+ item.setSelected(true);
+ m_bsGroup.add(item);
+ menu.add(item);
+ }
+
+ menu.addSeparator();
+
+ item = new JRadioButtonMenuItem("Other...");
+ item.addActionListener(m_listener);
+ item.setActionCommand("newgame");
+ item.setSelected(true);
+ m_bsGroup.add(item);
+ menu.add(item);
+
+ return menu;
+ }
+
+ public String getSelectedBoardSize() {
+ Enumeration e = m_bsGroup.getElements();
+ AbstractButton b = (AbstractButton) e.nextElement();
+ while (!b.isSelected() && e.hasMoreElements()) {
+ b = (AbstractButton) e.nextElement();
+ }
+
+ return b.getText();
+ }
+
+ // ----------------------------------------------------------------------
+
+ public boolean getToolbarVisible() {
+ return m_toolbar_visible.getState();
+ }
+
+ public boolean getShellVisible() {
+ return m_shell_visible.getState();
+ }
+
+ public void setShellVisible(boolean f) {
+ m_shell_visible.setState(f);
+ }
+
+ public boolean getAnalyzeVisible() {
+ return m_analyze_visible.getState();
+ }
+
+ public void setAnalyzeVisible(boolean f) {
+ m_analyze_visible.setState(f);
+ }
+
+ public boolean getEvalGraphVisible() {
+ return m_evalgraph_visible.getState();
+ }
+
+ public void setEvalGraphVisible(boolean f) {
+ m_evalgraph_visible.setState(f);
+ }
+
+ private JMenu createViewMenu() {
+ JMenu menu = new JMenu("View");
+ menu.setMnemonic(KeyEvent.VK_V);
+
+ m_toolbar_visible = new JCheckBoxMenuItem("Show Toolbar");
+ if (m_preferences.getBoolean("gui-toolbar-visible")) m_toolbar_visible.setState(true);
+ m_toolbar_visible.addActionListener(m_listener);
+ m_toolbar_visible.setActionCommand("gui_toolbar_visible");
+ menu.add(m_toolbar_visible);
+
+ m_shell_visible = new JCheckBoxMenuItem("Show Shell");
+ m_shell_visible.addActionListener(m_listener);
+ m_shell_visible.setActionCommand("gui_shell_visible");
+ m_shell_visible.setEnabled(false);
+ menu.add(m_shell_visible);
+
+ m_analyze_visible = new JCheckBoxMenuItem("Show Analyze");
+ m_analyze_visible.addActionListener(m_listener);
+ m_analyze_visible.setActionCommand("gui_analyze_visible");
+ m_analyze_visible.setEnabled(false);
+ menu.add(m_analyze_visible);
+
+ menu.addSeparator();
+
+ JMenuItem item = new JMenuItem("Clear Marks");
+ item.addActionListener(m_listener);
+ item.setActionCommand("gui-clear-marks");
+ menu.add(item);
+
+ menu.addSeparator();
+
+ JMenu view;
+ view = createBoardViewMenu();
+ menu.add(view);
+
+ view = createOrientationViewMenu();
+ menu.add(view);
+
+ return menu;
+ }
+
+ private JMenu createBoardViewMenu() {
+ JMenu menu = new JMenu("Board Type");
+ m_btGroup = new ButtonGroup();
+
+ String defaultType = m_preferences.get("gui-board-type");
+
+ JRadioButtonMenuItem item;
+ item = new JRadioButtonMenuItem("Diamond");
+ item.addActionListener(m_listener);
+ item.setActionCommand("gui_board_draw_type");
+ if (defaultType.equals("Diamond")) item.setSelected(true);
+ m_btGroup.add(item);
+ menu.add(item);
+
+ item = new JRadioButtonMenuItem("Flat");
+ item.addActionListener(m_listener);
+ item.setActionCommand("gui_board_draw_type");
+ if (defaultType.equals("Flat")) item.setSelected(true);
+ m_btGroup.add(item);
+ menu.add(item);
+
+ item = new JRadioButtonMenuItem("Flat2");
+ item.addActionListener(m_listener);
+ item.setActionCommand("gui_board_draw_type");
+ if (defaultType.equals("Flat2")) item.setSelected(true);
+ m_btGroup.add(item);
+ menu.add(item);
+
+ item = new JRadioButtonMenuItem("Go");
+ item.addActionListener(m_listener);
+ item.setActionCommand("gui_board_draw_type");
+ if (defaultType.equals("Go")) item.setSelected(true);
+ m_btGroup.add(item);
+ menu.add(item);
+
+ item = new JRadioButtonMenuItem("Y");
+ item.addActionListener(m_listener);
+ item.setActionCommand("gui_board_draw_type");
+ if (defaultType.equals("Go")) item.setSelected(true);
+ m_btGroup.add(item);
+ menu.add(item);
+
+ return menu;
+ }
+
+ public String getCurrentBoardDrawType() {
+ Enumeration e = m_btGroup.getElements();
+ AbstractButton b = (AbstractButton) e.nextElement();
+ while (!b.isSelected() && e.hasMoreElements()) {
+ b = (AbstractButton) e.nextElement();
+ }
+ return b.getText();
+ }
+
+ private JMenu createOrientationViewMenu() {
+ JMenu menu = new JMenu("Board Orientation");
+ m_orGroup = new ButtonGroup();
+
+ String pref = m_preferences.get("gui-board-orientation");
+
+ JRadioButtonMenuItem item;
+ item = new JRadioButtonMenuItem("Positive");
+ item.addActionListener(m_listener);
+ item.setActionCommand("gui_board_orientation");
+ if (pref.equals("positive")) item.setSelected(true);
+ m_orGroup.add(item);
+ menu.add(item);
+
+ item = new JRadioButtonMenuItem("Negative");
+ item.addActionListener(m_listener);
+ item.setActionCommand("gui_board_orientation");
+ if (pref.equals("negative")) item.setSelected(true);
+ m_orGroup.add(item);
+ menu.add(item);
+
+ return menu;
+ }
+
+ public String getCurrentBoardOrientation() {
+ Enumeration e = m_orGroup.getElements();
+ AbstractButton b = (AbstractButton) e.nextElement();
+ while (!b.isSelected() && e.hasMoreElements()) {
+ b = (AbstractButton) e.nextElement();
+ }
+ return b.getText();
+ }
+
+ // ----------------------------------------------------------------------
+
+ private JMenu createHelpMenu() {
+ JMenu menu = new JMenu("Help");
+ menu.setMnemonic(KeyEvent.VK_H);
+
+ JMenuItem item;
+ item = new JMenuItem("About HexGui...");
+ item.setMnemonic(KeyEvent.VK_A);
+ item.addActionListener(m_listener);
+ item.setActionCommand("about");
+ menu.add(item);
+
+ return menu;
+ }
+
+ private GuiPreferences m_preferences;
+ private ActionListener m_listener;
+ private JMenuBar m_menuBar;
+
+ private JCheckBoxMenuItem m_toolbar_visible;
+ private JCheckBoxMenuItem m_shell_visible;
+ private JCheckBoxMenuItem m_analyze_visible;
+ private JCheckBoxMenuItem m_evalgraph_visible;
+
+ private JMenuItem m_connect_local, m_connect_remote, m_disconnect, m_reconnect;
+ private JMenuItem m_pass, m_resign, m_forfeit, m_swap_pieces, m_swap_sides, m_addsetup, m_genmove;
+
+ private ButtonGroup m_bsGroup; // board sizes
+ private ButtonGroup m_btGroup; // board view types (diamond, flat, etc)
+ private ButtonGroup m_orGroup; // orientation: positive or negative?
+ private ButtonGroup m_colorGroup; // whose turn to move?
+}
diff --git a/src/main/java/hexgui/gui/GuiPreferences.java b/src/main/java/hexgui/gui/GuiPreferences.java
new file mode 100644
index 0000000..31bb079
--- /dev/null
+++ b/src/main/java/hexgui/gui/GuiPreferences.java
@@ -0,0 +1,78 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import java.io.*;
+import java.util.*;
+import java.util.prefs.*;
+
+// ----------------------------------------------------------------------------
+
+/** GuiPreferences */
+public final class GuiPreferences {
+ private static String[][] s_preflist =
+ new String[][] {
+ {"gui-board-type", "Flat"},
+ {"gui-board-orientation", "positive"},
+ {"gui-board-pixel-width", "750"},
+ {"gui-board-pixel-height", "500"},
+ {"gui-board-width", "11"},
+ {"gui-board-height", "11"},
+ {"draw-field-alpha", "0.3"}, // FIXME: not used yet!
+ {"gui-toolbar-visible", "true"},
+ {"shell-show-on-connect", "false"},
+ {"analyze-show-on-connect", "false"},
+ {"auto-respond", "true"},
+ {"first-move-color", "black"},
+ {"remote-host-name", "localhost"},
+ {"is-program-attached", "false"},
+ {"attached-program", "dummy-program-name"},
+ {"path-load-game", "."},
+ {"path-save-game", "."},
+ {"dummy-preference", ""}
+ };
+
+ public GuiPreferences(Class theClass) {
+ m_preferences = Preferences.userNodeForPackage(theClass);
+ }
+
+ public String get(String name) {
+ for (int i = 0; i < s_preflist.length; i++) {
+ if (name.equals(s_preflist[i][0])) {
+ return m_preferences.get(s_preflist[i][0], s_preflist[i][1]);
+ }
+ }
+ System.out.println("Unknown preference: " + name + ", returning 'unknown'.");
+ return "unknown";
+ }
+
+ public int getInt(String name) {
+ return Integer.parseInt(get(name));
+ }
+
+ public boolean getBoolean(String name) {
+ return Boolean.parseBoolean(get(name));
+ }
+
+ public void put(String name, String value) {
+ for (int i = 0; i < s_preflist.length; i++) {
+ if (name.equals(s_preflist[i][0])) {
+ m_preferences.put(s_preflist[i][0], value);
+ return;
+ }
+ }
+ System.out.println("Unknown preference: " + name + ", nothing stored.");
+ }
+
+ public void put(String name, int value) {
+ put(name, Integer.toString(value));
+ }
+
+ public void put(String name, boolean value) {
+ put(name, Boolean.toString(value));
+ }
+
+ Preferences m_preferences;
+}
diff --git a/src/main/java/hexgui/gui/GuiRunnable.java b/src/main/java/hexgui/gui/GuiRunnable.java
new file mode 100644
index 0000000..f56cc84
--- /dev/null
+++ b/src/main/java/hexgui/gui/GuiRunnable.java
@@ -0,0 +1,20 @@
+package hexgui.gui;
+
+import java.util.*;
+import javax.swing.*;
+
+/**
+ * Runnable that is guaranteed to be run in the Swing event dispatch thread. Most Swing function may
+ * only be called in the Swing event dispatch thread.
+ */
+public class GuiRunnable implements Runnable {
+ public GuiRunnable(Runnable runnable) {
+ m_runnable = runnable;
+ }
+
+ public void run() {
+ SwingUtilities.invokeLater(m_runnable);
+ }
+
+ private Runnable m_runnable;
+}
diff --git a/src/main/java/hexgui/gui/GuiToolBar.java b/src/main/java/hexgui/gui/GuiToolBar.java
new file mode 100644
index 0000000..9db9aeb
--- /dev/null
+++ b/src/main/java/hexgui/gui/GuiToolBar.java
@@ -0,0 +1,424 @@
+// ----------------------------------------------------------------------------
+// $Id$
+// ----------------------------------------------------------------------------
+
+package hexgui.gui;
+
+import hexgui.game.Node;
+import java.awt.*;
+import java.awt.event.*;
+import java.net.URL;
+import java.util.*;
+import javax.swing.*;
+
+// ----------------------------------------------------------------------------
+
+public final class GuiToolBar implements ActionListener {
+ public GuiToolBar(HexGui listener, GuiPreferences preferences) {
+ m_preferences = preferences;
+ m_listener = listener;
+
+ m_toolBar = new JToolBar();
+ createToolBar();
+
+ setVisible(m_preferences.getBoolean("gui-toolbar-visible"));
+ }
+
+ public JToolBar getJToolBar() {
+ return m_toolBar;
+ }
+
+ public void setVisible(boolean visible) {
+ m_toolBar.setVisible(visible);
+ m_preferences.put("gui-toolbar-visible", visible);
+ }
+
+ public void enableStopButton() {
+ m_stop.setEnabled(true);
+ }
+
+ public void disableStopButton() {
+ m_stop.setEnabled(false);
+ }
+
+ public void setToMove(String string) {
+ if (string.equals("black")) {
+ if (m_black_to_play != null) m_tomove.setIcon(m_black_to_play);
+ else m_tomove.setText("black");
+ } else if (string.equals("white")) {
+ if (m_white_to_play != null) m_tomove.setIcon(m_white_to_play);
+ else m_tomove.setText("white");
+ } else System.out.println("Unknown value: '" + string + "'");
+ }
+
+ /**
+ * Returns the click context--what type of move does the user wish to make?
+ *
+ * @return "black" if black setup icon is selected. "white" if white setup icon is selected.
+ * "play" otherwise.
+ */
+ public String getClickContext() {
+ if (m_setup_black.isSelected()) return "black";
+ else if (m_setup_white.isSelected()) return "white";
+ return "play";
+ }
+
+ public void deselectSetup() {
+ m_setup_black.setSelected(false);
+ m_setup_white.setSelected(false);
+ }
+
+ public void setProgramConnected(boolean f) {
+ m_play.setEnabled(f);
+ m_hint.setEnabled(f);
+ m_solve.setEnabled(f);
+ m_program_options.setEnabled(f);
+ }
+
+ public void updateButtonStates(Node node, HexGui gui) {
+ m_beginning.setEnabled(node.getParent() != null);
+ m_back10.setEnabled(node.getParent() != null);
+ m_back.setEnabled(node.getParent() != null);
+
+ m_forward.setEnabled(node.getChild() != null);
+ m_forward10.setEnabled(node.getChild() != null);
+ m_end.setEnabled(node.getChild() != null);
+
+ m_up.setEnabled(node.getPrev() != null);
+ m_down.setEnabled(node.getNext() != null);
+
+ m_swap.setEnabled(gui.isSwapAllowed());
+ }
+
+ public void lockToolbar() {
+ m_new.setEnabled(false);
+ m_load.setEnabled(false);
+ m_save.setEnabled(false);
+
+ m_setup_black.setEnabled(false);
+ m_setup_white.setEnabled(false);
+
+ m_beginning.setEnabled(false);
+ m_back10.setEnabled(false);
+ m_back.setEnabled(false);
+
+ m_forward.setEnabled(false);
+ m_forward10.setEnabled(false);
+ m_end.setEnabled(false);
+
+ m_up.setEnabled(false);
+ m_down.setEnabled(false);
+
+ m_swap.setEnabled(false);
+
+ m_play.setEnabled(false);
+
+ m_tomove.setEnabled(false);
+
+ m_hint.setEnabled(false);
+ m_solve.setEnabled(false);
+ m_program_options.setEnabled(false);
+
+ enableStopButton();
+ }
+
+ public void unlockToolbar(Node node, HexGui gui) {
+ disableStopButton();
+
+ m_play.setEnabled(true);
+
+ m_tomove.setEnabled(true);
+
+ m_setup_black.setEnabled(true);
+ m_setup_white.setEnabled(true);
+
+ m_new.setEnabled(true);
+ m_load.setEnabled(true);
+ m_save.setEnabled(true);
+
+ m_hint.setEnabled(true);
+ m_solve.setEnabled(true);
+ m_program_options.setEnabled(true);
+
+ updateButtonStates(node, gui);
+ }
+
+ // ----------------------------------------------------------------------
+
+ private void createToolBar() {
+ m_new = makeButton("hexgui/images/filenew.png", "newgame", "New Game", "New");
+ m_toolBar.add(m_new);
+
+ m_load = makeButton("hexgui/images/fileopen.png", "loadgame", "Load Game", "Load");
+ m_toolBar.add(m_load);
+
+ m_save = makeButton("hexgui/images/filesave2.png", "savegame", "Save Game", "Save");
+ m_toolBar.add(m_save);
+
+ m_toolBar.addSeparator();
+
+ m_setup_black =
+ makeToggleButton(
+ "hexgui/images/setup-black.png",
+ "setup-black",
+ "Setup Black Stones",
+ "Setup Black",
+ KeyEvent.VK_B);
+ m_toolBar.add(m_setup_black);
+
+ m_setup_white =
+ makeToggleButton(
+ "hexgui/images/setup-white.png",
+ "setup-white",
+ "Setup White Stones",
+ "Setup White",
+ KeyEvent.VK_W);
+ m_toolBar.add(m_setup_white);
+
+ m_toolBar.addSeparator();
+
+ m_beginning =
+ makeButton(
+ "hexgui/images/beginning.png",
+ "game_beginning",
+ "Game Start",
+ "Start",
+ KeyEvent.VK_HOME);
+ m_toolBar.add(m_beginning);
+
+ m_back10 =
+ makeButton(
+ "hexgui/images/backward10.png",
+ "game_backward10",
+ "Go back ten moves",
+ "Back10",
+ KeyEvent.VK_PAGE_UP);
+ m_toolBar.add(m_back10);
+
+ m_back =
+ makeButton(
+ "hexgui/images/back.png", "game_back", "Go back one move", "Back", KeyEvent.VK_LEFT);
+ m_toolBar.add(m_back);
+
+ m_forward =
+ makeButton(
+ "hexgui/images/forward.png",
+ "game_forward",
+ "Go forward one move",
+ "Forward",
+ KeyEvent.VK_RIGHT);
+ m_toolBar.add(m_forward);
+
+ m_forward10 =
+ makeButton(
+ "hexgui/images/forward10.png",
+ "game_forward10",
+ "Go forward ten moves",
+ "Forward10",
+ KeyEvent.VK_PAGE_DOWN);
+ m_toolBar.add(m_forward10);
+
+ m_end =
+ makeButton(
+ "hexgui/images/end.png", "game_end", "Go to end of game", "End", KeyEvent.VK_END);
+ m_toolBar.add(m_end);
+
+ m_toolBar.addSeparator();
+
+ m_up =
+ makeButton(
+ "hexgui/images/up.png", "game_up", "Explore previous variation", "Up", KeyEvent.VK_UP);
+ m_toolBar.add(m_up);
+
+ m_down =
+ makeButton(
+ "hexgui/images/down.png",
+ "game_down",
+ "Explore next variation",
+ "Down",
+ KeyEvent.VK_DOWN);
+ m_toolBar.add(m_down);
+
+ m_toolBar.addSeparator();
+
+ m_swap = makeButton("hexgui/images/swap.png", "game_swap_pieces", "Play swap move", "Swap");
+ m_toolBar.add(m_swap);
+ m_swap.setEnabled(false);
+
+ m_toolBar.addSeparator();
+
+ m_play =
+ makeButton(
+ "hexgui/images/play.png", "genmove", "Generate computer move", "Play", KeyEvent.VK_M);
+ m_toolBar.add(m_play);
+ m_play.setEnabled(false);
+
+ m_stop = makeButton("hexgui/images/stop.png", "stop", "Stop Action", "Stop");
+ m_toolBar.add(m_stop);
+ disableStopButton();
+
+ m_toolBar.addSeparator();
+
+ String pref = m_preferences.get("first-move-color");
+ m_tomove =
+ makeButton(
+ "hexgui/images/black-24x24.png", "toggle_tomove", "Color of player to move", pref);
+ m_tomove.setText("");
+ {
+ URL imageURL = getURL("hexgui/images/black-24x24.png");
+ m_black_to_play = new ImageIcon(imageURL, "black");
+ }
+ {
+ URL imageURL = getURL("hexgui/images/white-24x24.png");
+ m_white_to_play = new ImageIcon(imageURL, "white");
+ }
+ setToMove(pref);
+
+ m_toolBar.add(m_tomove);
+
+ m_toolBar.addSeparator();
+
+ m_hint =
+ makeButton(
+ "hexgui/images/hint-24x24.png",
+ "show_consider_set",
+ "Show provably inferior cells",
+ "Hint");
+ m_toolBar.add(m_hint);
+ m_hint.setEnabled(false);
+
+ m_solve =
+ makeButton(
+ "hexgui/images/solve.png",
+ "solve_state",
+ "Solve State with DFPN",
+ "Solve",
+ KeyEvent.VK_S);
+ m_toolBar.add(m_solve);
+ m_solve.setEnabled(false);
+
+ m_program_options =
+ makeButton(
+ "hexgui/images/program-options.png", "program_options", "Program Options", "Options");
+ m_toolBar.add(m_program_options);
+ m_program_options.setEnabled(false);
+ }
+
+ private JButton makeButton(
+ String imageFile, String actionCommand, String tooltip, String altText) {
+ return makeButton(imageFile, actionCommand, tooltip, altText, -1);
+ }
+
+ private JButton makeButton(
+ String imageFile, final String actionCommand, String tooltip, String altText, int key) {
+ final JButton button = new JButton();
+ final ActionListener listener = m_listener;
+ button.setFocusable(false);
+ button.addActionListener(m_listener);
+ button.setActionCommand(actionCommand);
+ button.setToolTipText(tooltip);
+ addIconToButton(button, imageFile, altText);
+ if (key != -1) {
+ button
+ .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
+ .put(KeyStroke.getKeyStroke(key, 0), "key");
+ Action action =
+ new AbstractAction() {
+ public void actionPerformed(ActionEvent actionEvent) {
+ if (m_listener.shortcutsEnabled()) {
+ button.doClick();
+ }
+ }
+ };
+ button.getActionMap().put("key", action);
+ }
+ return button;
+ }
+
+ private JToggleButton makeToggleButton(
+ String imageFile, String actionCommand, String tooltip, String altText, int key) {
+ final JToggleButton button = new JToggleButton();
+ button.setFocusable(false);
+ button.addActionListener(this);
+ button.setActionCommand(actionCommand);
+ button.setToolTipText(tooltip);
+ addIconToButton(button, imageFile, altText);
+ if (key != -1) {
+ button
+ .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
+ .put(KeyStroke.getKeyStroke(key, 0), "key");
+ Action action =
+ new AbstractAction() {
+ public void actionPerformed(ActionEvent actionEvent) {
+ if (m_listener.shortcutsEnabled()) {
+ button.doClick();
+ }
+ }
+ };
+ button.getActionMap().put("key", action);
+ }
+ return button;
+ }
+
+ private JToggleButton makeToggleButton(
+ String imageFile, String actionCommand, String tooltip, String altText) {
+ return makeToggleButton(imageFile, actionCommand, tooltip, altText, -1);
+ }
+
+ private void addIconToButton(AbstractButton button, String imageFile, String altText) {
+ URL imageURL = getURL(imageFile);
+ if (imageURL != null) {
+ button.setIcon(new ImageIcon(imageURL, altText));
+ } else {
+ button.setText(altText);
+ System.out.println("*** Resource not found: " + imageFile);
+ }
+ }
+
+ private URL getURL(String filename) {
+ URL url = null;
+ if (filename != null) {
+ ClassLoader classLoader = getClass().getClassLoader();
+ url = classLoader.getResource(filename);
+ }
+ return url;
+ }
+
+ // ----------------------------------------------------------------------
+
+ public void actionPerformed(ActionEvent e) {
+ String cmd = e.getActionCommand();
+ if (cmd.equals("setup-black")) {
+ if (m_setup_white.isSelected()) {
+ m_setup_white.setSelected(false);
+ }
+ m_listener.actionPerformed(e);
+ } else if (cmd.equals("setup-white")) {
+ if (m_setup_black.isSelected()) {
+ m_setup_black.setSelected(false);
+ }
+ m_listener.actionPerformed(e);
+ } else {
+ System.out.println("GuiToolBar: Unknown action command '" + cmd + "'");
+ }
+ }
+
+ // ----------------------------------------------------------------------
+
+ private GuiPreferences m_preferences;
+ private JToolBar m_toolBar;
+ private HexGui m_listener;
+
+ private JButton m_new, m_load, m_save;
+ private JToggleButton m_setup_black, m_setup_white;
+ private JButton m_beginning, m_back10, m_back;
+ private JButton m_forward, m_forward10, m_end;
+ private JButton m_up, m_down;
+ private JButton m_play, m_stop, m_swap;
+
+ private JButton m_tomove;
+ private ImageIcon m_black_to_play, m_white_to_play;
+ private JButton m_solve, m_hint, m_program_options;
+}
+
+// ----------------------------------------------------------------------------
diff --git a/src/main/java/hexgui/gui/GuiUtil.java b/src/main/java/hexgui/gui/GuiUtil.java
new file mode 100644
index 0000000..9c7a80d
--- /dev/null
+++ b/src/main/java/hexgui/gui/GuiUtil.java
@@ -0,0 +1,314 @@
+// GuiUtil.java
+
+package hexgui.gui;
+
+import hexgui.util.Platform;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.KeyboardFocusManager;
+import java.awt.RenderingHints;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.IOException;
+import java.net.URL;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JTextField;
+import javax.swing.JTextPane;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.border.Border;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyleContext;
+import javax.swing.text.StyledDocument;
+
+/** GUI utility classes and static functions. */
+public class GuiUtil {
+ /** Constant used for padding in dialogs. */
+ public static final int PAD = 5;
+
+ /** Constant used for small padding in dialogs. */
+ public static final int SMALL_PAD = 2;
+
+ public static void addStyle(JTextPane pane, String name, Color foreground, Color background) {
+ StyledDocument doc = pane.getStyledDocument();
+ StyleContext context = StyleContext.getDefaultStyleContext();
+ Style defaultStyle = context.getStyle(StyleContext.DEFAULT_STYLE);
+ Style style = doc.addStyle(name, defaultStyle);
+ StyleConstants.setForeground(style, foreground);
+ StyleConstants.setBackground(style, background);
+ }
+
+ public static void copyToClipboard(String text) {
+ StringSelection selection = new StringSelection(text);
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ ClipboardOwner owner =
+ new ClipboardOwner() {
+ public void lostOwnership(Clipboard clipboard, Transferable contents) {}
+ };
+ clipboard.setContents(selection, owner);
+ }
+
+ /**
+ * Wrapper object for JComboBox items. JComboBox can have focus and keyboard navigation problems
+ * if duplicate String objects are added. See JDK 1.5 doc for JComboBox.addItem.
+ */
+ public static Object createComboBoxItem(final String item) {
+ return new Object() {
+ public String toString() {
+ return item;
+ }
+ };
+ }
+
+ /**
+ * Create empty border with normal padding.
+ *
+ * @see #PAD
+ */
+ public static Border createEmptyBorder() {
+ return EMPTY_BORDER;
+ }
+
+ /**
+ * Create empty box with size of normal padding.
+ *
+ * @see #PAD
+ */
+ public static Box.Filler createFiller() {
+ return new Box.Filler(FILLER_DIMENSION, FILLER_DIMENSION, FILLER_DIMENSION);
+ }
+
+ /**
+ * Create empty border with small padding.
+ *
+ * @see #SMALL_PAD
+ */
+ public static Border createSmallEmptyBorder() {
+ return SMALL_EMPTY_BORDER;
+ }
+
+ /**
+ * Create empty box with size of small padding.
+ *
+ * @see #SMALL_PAD
+ */
+ public static Box.Filler createSmallFiller() {
+ return new Box.Filler(SMALL_FILLER_DIMENSION, SMALL_FILLER_DIMENSION, SMALL_FILLER_DIMENSION);
+ }
+
+ public static String getClipboardText() {
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ Transferable content = clipboard.getContents(null);
+ if (content == null || !content.isDataFlavorSupported(DataFlavor.stringFlavor)) return null;
+ try {
+ return (String) content.getTransferData(DataFlavor.stringFlavor);
+ } catch (UnsupportedFlavorException e) {
+ return null;
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Return a style sheet for message labels using HTML.
+ *
+ * @return A string with a HTML-head tag containing a style tag with formatting options or an
+ * empty string.
+ */
+ public static String getMessageCss() {
+ if (Platform.isMac())
+ return "";
+ else return "";
+ }
+
+ /**
+ * Get size of default monspaced font. Can be used for setting the initial size of some GUI
+ * elements.
+ */
+ public static int getDefaultMonoFontSize() {
+ return MONOSPACED_FONT.getSize();
+ }
+
+ public static ImageIcon getIcon(String icon, String name) {
+ String resource = "hexgui/images/" + icon + ".png";
+ URL url = GuiUtil.class.getClassLoader().getResource(resource);
+ return new ImageIcon(url, name);
+ }
+
+ /**
+ * Manually break message into multiple lines for multi-line labels. Needed for multi-line
+ * messages in option panes, because pack() on JOptionPane does not compute the option pane size
+ * correctly, if a maximum width is set and the label text is automatically broken into multiple
+ * lines. The workaround with calling invalidate() and pack() a second time does not work either
+ * in this case. See also Sun Bug ID 4545951 (still in Linux JDK 1.5.0_04-b05 or Mac 1.4.2_12)
+ */
+ public static String insertLineBreaks(String message) {
+ final int MAX_CHAR_PER_LINE = 72;
+ int length = message.length();
+ if (length < MAX_CHAR_PER_LINE) return message;
+ StringBuilder buffer = new StringBuilder();
+ int startLine = 0;
+ int lastWhiteSpace = -1;
+ for (int pos = 0; pos < length; ++pos) {
+ char c = message.charAt(pos);
+ if (pos - startLine > 72) {
+ int endLine = (lastWhiteSpace > startLine ? lastWhiteSpace : pos);
+ if (buffer.length() > 0) buffer.append("
");
+ buffer.append(message.substring(startLine, endLine));
+ startLine = endLine;
+ }
+ if (Character.isWhitespace(c)) lastWhiteSpace = pos;
+ }
+ if (buffer.length() > 0) buffer.append("
");
+ buffer.append(message.substring(startLine));
+ return buffer.toString();
+ }
+
+ /**
+ * Call SwingUtilities.invokeAndWait. Ignores possible exceptions (apart from printing a warning
+ * to System.err
+ */
+ public static void invokeAndWait(Runnable runnable) {
+ try {
+ SwingUtilities.invokeAndWait(runnable);
+ } catch (InterruptedException e) {
+ System.err.println("Thread interrupted");
+ } catch (java.lang.reflect.InvocationTargetException e) {
+ System.err.println("InvocationTargetException");
+ }
+ }
+
+ public static boolean isActiveWindow(Window window) {
+ KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ return (manager.getActiveWindow() == window);
+ }
+
+ /**
+ * Check window for normal state. Checks if window is not maximized (in either or both directions)
+ * and not iconified.
+ */
+ public static boolean isNormalSizeMode(JFrame window) {
+ int state = window.getExtendedState();
+ int mask =
+ Frame.MAXIMIZED_BOTH | Frame.MAXIMIZED_VERT | Frame.MAXIMIZED_HORIZ | Frame.ICONIFIED;
+ return ((state & mask) == 0);
+ }
+
+ public static void paintImmediately(JComponent component) {
+ component.paintImmediately(component.getVisibleRect());
+ }
+
+ public static void removeKeyBinding(JComponent component, String key) {
+ int condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
+ InputMap inputMap = component.getInputMap(condition);
+ // According to the docs, null should remove the action, but it does
+ // not seem to work with Sun Java 1.4.2, new Object() works
+ inputMap.put(KeyStroke.getKeyStroke(key), new Object());
+ }
+
+ /** Set antialias rendering hint if graphics is instance of Graphics2D. */
+ public static void setAntiAlias(Graphics graphics) {
+ if (graphics instanceof Graphics2D) {
+ Graphics2D graphics2D = (Graphics2D) graphics;
+ graphics2D.setRenderingHint(
+ RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ }
+ }
+
+ /** Set text field non-editable. Also sets it non-focusable. */
+ public static void setEditableFalse(JTextField field) {
+ field.setEditable(false);
+ field.setFocusable(false);
+ }
+
+ /** Set Go icon on frame. */
+ public static void setGoIcon(Frame frame) {
+ URL url = s_iconURL;
+ if (url != null) frame.setIconImage(new ImageIcon(url).getImage());
+ }
+
+ /**
+ * Set property to render button in bevel style on the Mac. Only has an effect if Quaqua Look and
+ * Feel is used.
+ */
+ public static void setMacBevelButton(JButton button) {
+ button.putClientProperty("Quaqua.Button.style", "bevel");
+ }
+
+ public static void setMonospacedFont(JComponent component) {
+ if (MONOSPACED_FONT != null) component.setFont(MONOSPACED_FONT);
+ }
+
+ public static void addStyle(JTextPane textPane, String name, Color foreground) {
+ addStyle(textPane, name, foreground, null, false);
+ }
+
+ public static void addStyle(
+ JTextPane textPane, String name, Color foreground, Color background, boolean bold) {
+ StyledDocument doc = textPane.getStyledDocument();
+ StyleContext context = StyleContext.getDefaultStyleContext();
+ Style def = context.getStyle(StyleContext.DEFAULT_STYLE);
+ Style style = doc.addStyle(name, def);
+ if (foreground != null) StyleConstants.setForeground(style, foreground);
+ if (background != null) StyleConstants.setBackground(style, background);
+ StyleConstants.setBold(style, bold);
+ }
+
+ public static void setStyle(JTextPane textPane, int start, int length, String name) {
+ StyledDocument doc = textPane.getStyledDocument();
+ Style style;
+ if (name == null) {
+ StyleContext context = StyleContext.getDefaultStyleContext();
+ style = context.getStyle(StyleContext.DEFAULT_STYLE);
+ } else style = doc.getStyle(name);
+ doc.setCharacterAttributes(start, length, style, true);
+ }
+
+ public static void setUnlimitedSize(JComponent component) {
+ Dimension size = new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
+ component.setMaximumSize(size);
+ }
+
+ static {
+ ClassLoader loader = ClassLoader.getSystemClassLoader();
+ // There are problems on some platforms with transparency (e.g. Linux
+ // Sun Java 1.5.0). Best solution for now is to take an icon without
+ // transparency
+ s_iconURL = loader.getResource("hexgui/images/hexgui-48x48-notrans.png");
+ }
+
+ private static final Font MONOSPACED_FONT = Font.decode("Monospaced");
+
+ private static final Border EMPTY_BORDER = BorderFactory.createEmptyBorder(PAD, PAD, PAD, PAD);
+
+ private static final Border SMALL_EMPTY_BORDER =
+ BorderFactory.createEmptyBorder(
+ SMALL_PAD, SMALL_PAD,
+ SMALL_PAD, SMALL_PAD);
+
+ private static final Dimension FILLER_DIMENSION = new Dimension(PAD, PAD);
+
+ private static final Dimension SMALL_FILLER_DIMENSION = new Dimension(SMALL_PAD, SMALL_PAD);
+
+ private static URL s_iconURL;
+}
diff --git a/src/main/java/hexgui/gui/HexGui.java b/src/main/java/hexgui/gui/HexGui.java
new file mode 100644
index 0000000..391a2ac
--- /dev/null
+++ b/src/main/java/hexgui/gui/HexGui.java
@@ -0,0 +1,2393 @@
+package hexgui.gui;
+
+import static java.text.MessageFormat.format;
+
+import hexgui.game.Clock;
+import hexgui.game.GameInfo;
+import hexgui.game.Node;
+import hexgui.hex.*;
+import hexgui.htp.AnalyzeCommand;
+import hexgui.htp.AnalyzeDefinition;
+import hexgui.htp.AnalyzeType;
+import hexgui.htp.HtpController;
+import hexgui.htp.HtpError;
+import hexgui.sgf.SgfReader;
+import hexgui.sgf.SgfWriter;
+import hexgui.util.ErrorMessage;
+import hexgui.util.Pair;
+import hexgui.util.StreamCopy;
+import hexgui.util.StringUtils;
+import hexgui.version.Version;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Semaphore;
+import javax.swing.*;
+
+// ----------------------------------------------------------------------------
+
+/** HexGui. */
+public final class HexGui extends JFrame
+ implements ActionListener,
+ GuiBoard.Listener,
+ HtpShell.Callback,
+ HtpController.GuiFxCallback,
+ AnalyzeDialog.Listener,
+ Comment.Listener {
+ public HexGui(final File file, final String command) {
+ super("HexGui");
+ setIcon();
+
+ System.out.println("HexGui v" + Version.id + "; " + Version.date + "\n");
+
+ // Catch the close action and shutdown nicely
+ setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+ addWindowListener(
+ new java.awt.event.WindowAdapter() {
+ public void windowClosing(WindowEvent winEvt) {
+ cmdShutdown();
+ }
+ });
+
+ m_selected_cells = new Vector();
+
+ m_about = new AboutDialog(this);
+
+ m_preferences = new GuiPreferences(getClass());
+
+ m_menubar = new GuiMenuBar(this, m_preferences);
+ setJMenuBar(m_menubar.getJMenuBar());
+
+ m_toolbar = new GuiToolBar(this, m_preferences);
+ getContentPane().add(m_toolbar.getJToolBar(), BorderLayout.NORTH);
+
+ m_statusbar = new StatusBar();
+ getContentPane().add(m_statusbar, BorderLayout.SOUTH);
+
+ m_guiboard = new GuiBoard(this, m_preferences);
+ getContentPane().add(m_guiboard, BorderLayout.CENTER);
+
+ m_showAnalyzeText = new ShowAnalyzeText(this, m_guiboard);
+
+ JPanel panel = new JPanel(new BorderLayout());
+ getContentPane().add(panel, BorderLayout.EAST);
+
+ m_blackClock = new Clock();
+ m_whiteClock = new Clock();
+ m_gameinfopanel = new GameInfoPanel(m_blackClock, m_whiteClock);
+ m_comment = new Comment(this);
+ panel.add(m_gameinfopanel, BorderLayout.NORTH);
+ panel.add(m_comment, BorderLayout.CENTER);
+
+ cmdNewGame();
+
+ pack();
+
+ m_locked = false;
+
+ m_semaphore = new Semaphore(1);
+ m_htp_queue = new ArrayBlockingQueue(256);
+ new Thread(new CommandHandler(this, m_htp_queue)).start();
+
+ setVisible(true);
+ // After frame is visible, further code using Swing functions must
+ // be run in the Swing event dispatch thread.
+ SwingUtilities.invokeLater(
+ new Runnable() {
+ public void run() {
+ initialize(file, command);
+ }
+ });
+ setCursorType();
+ }
+
+ // -------------------------------------------------------------------
+
+ public void actionPerformed(ActionEvent e) {
+ String cmd = e.getActionCommand();
+
+ unFocus();
+
+ //
+ // system commands
+ //
+ if (cmd.equals("shutdown")) {
+ cmdShutdown();
+ } else if (cmd.equals("new-program")) {
+ cmdNewProgram();
+ } else if (cmd.equals("edit-program")) {
+ cmdEditProgram();
+ } else if (cmd.equals("delete-program")) {
+ cmdDeleteProgram();
+ } else if (cmd.equals("connect-program")) {
+ cmdConnectRemoteProgram();
+ } else if (cmd.equals("connect-local-program")) {
+ cmdConnectLocalProgram();
+ } else if (cmd.equals("disconnect-program")) {
+ cmdDisconnectProgram();
+ } else if (cmd.equals("reconnect-program")) {
+ cmdReconnectProgram();
+ //
+ // file/help commands
+ //
+ } else if (cmd.equals("newgame")) {
+ end_setup();
+ cmdNewGame();
+ } else if (cmd.equals("savegame")) {
+ // We previously only saved when gameChanged() == true,
+ // but this is dangerous because saving would fail
+ // silently otherwise. It's better to simply save the game
+ // when the user asks for it. An alternative use for
+ // gameChanged() would be to disable the save button when
+ // we think the game hasn't changed. But we shouldn't just
+ // offer a button and then do nothing.
+ cmdSaveGame();
+ } else if (cmd.equals("savegameas")) {
+ cmdSaveGameAs();
+ } else if (cmd.equals("loadgame")) {
+ cmdLoadGame();
+ } else if (cmd.equals("save-position-as")) {
+ cmdSavePositionAs();
+ } else if (cmd.equals("print-preview")) {
+ cmdPrintPreview();
+ } else if (cmd.equals("print")) {
+ cmdPrint();
+ } else if (cmd.equals("about")) {
+ cmdAbout();
+ //
+ // gui commands
+ //
+ } else if (cmd.equals("gui_toolbar_visible")) {
+ cmdGuiToolbarVisible();
+ } else if (cmd.equals("gui_shell_visible")) {
+ cmdGuiShellVisible();
+ } else if (cmd.equals("gui_analyze_visible")) {
+ cmdGuiAnalyzeVisible();
+ } else if (cmd.equals("gui_board_draw_type")) {
+ cmdGuiBoardDrawType();
+ } else if (cmd.equals("gui_board_orientation")) {
+ cmdGuiBoardOrientation();
+ } else if (cmd.equals("show-preferences")) {
+ cmdShowPreferences();
+ } else if (cmd.equals("gui-clear-marks")) {
+ cmdClearMarks();
+ //
+ // game navigation commands
+ //
+ } else if (cmd.equals("game_beginning")) {
+ end_setup();
+ backward(-1);
+ } else if (cmd.equals("game_backward10")) {
+ end_setup();
+ backward(10);
+ } else if (cmd.equals("game_back")) {
+ end_setup();
+ backward(1);
+ } else if (cmd.equals("game_forward")) {
+ end_setup();
+ forward(1);
+ } else if (cmd.equals("game_forward10")) {
+ end_setup();
+ forward(10);
+ } else if (cmd.equals("game_end")) {
+ end_setup();
+ forward(-1);
+ } else if (cmd.equals("game_up")) {
+ end_setup();
+ up();
+ } else if (cmd.equals("game_down")) {
+ end_setup();
+ down();
+ } else if (cmd.equals("game_swap_sides")) {
+ end_setup();
+ humanMove(new Move(HexPoint.get("swap-sides"), m_tomove));
+ } else if (cmd.equals("game_swap_pieces")) {
+ end_setup();
+ humanMove(new Move(HexPoint.get("swap-pieces"), m_tomove));
+ } else if (cmd.equals("game_pass")) {
+ end_setup();
+ humanMove(new Move(HexPoint.get("pass"), m_tomove));
+ } else if (cmd.equals("game_resign")) {
+ end_setup();
+ humanMove(new Move(HexPoint.get("resign"), m_tomove));
+ } else if (cmd.equals("game_forfeit")) {
+ end_setup();
+ humanMove(new Move(HexPoint.get("forfeit"), m_tomove));
+ } else if (cmd.equals("game_addsetup")) {
+ end_setup();
+ addSetupNode();
+ } else if (cmd.equals("genmove")) {
+ end_setup();
+ htpGenMove(m_tomove);
+ } else if (cmd.equals("game_delete_branch")) {
+ end_setup();
+ cmdDeleteBranch();
+ } else if (cmd.equals("game_make_main_branch")) {
+ end_setup();
+ cmdMoveBranchTop();
+ } else if (cmd.equals("game_start_clock")) {
+ startClock();
+ } else if (cmd.equals("game_stop_clock")) {
+ stopClock();
+ } else if (cmd.equals("stop")) {
+ m_white.interrupt();
+ } else if (cmd.equals("toggle_tomove")) {
+ end_setup();
+ cmdToggleToMove();
+ } else if (cmd.equals("set_to_move")) {
+ end_setup();
+ cmdSetToMove();
+ } else if (cmd.equals("setup-black")) {
+ cmdSetupBlack();
+ } else if (cmd.equals("setup-white")) {
+ cmdSetupWhite();
+ }
+ //
+ // other
+ //
+ else if (cmd.equals("show_consider_set")) {
+ Runnable cb =
+ new Runnable() {
+ public void run() {
+ cbShowInferiorCells();
+ }
+ };
+ Runnable callback = new GuiRunnable(cb);
+ sendCommand("vc-build " + m_tomove.toString() + "\n", callback);
+ } else if (cmd.equals("solve_state")) {
+ sendCommand("param_dfpn use_guifx 1\n", null);
+ Runnable callback =
+ new GuiRunnable(
+ new Runnable() {
+ public void run() {
+ cbSolveState();
+ }
+ });
+ sendCommand("dfpn-solve-state " + m_tomove + "\n", callback);
+ } else if (cmd.equals("program_options")) {
+ AnalyzeCommand command;
+ if (m_white_name.equalsIgnoreCase("Mohex") || m_white_name.equalsIgnoreCase("HexHex")) {
+ command = new AnalyzeCommand(new AnalyzeDefinition("param/blah/param_mohex"));
+ Runnable cb =
+ new Runnable() {
+ public void run() {
+ cbEditParameters();
+ }
+ };
+ Runnable callback = new GuiRunnable(cb);
+ m_curAnalyzeCommand = command;
+ sendCommand(command.getCommand() + "\n", callback);
+ } else if (m_white_name.equalsIgnoreCase("Wolve")) {
+ command = new AnalyzeCommand(new AnalyzeDefinition("param/blah/param_wolve"));
+ Runnable cb =
+ new Runnable() {
+ public void run() {
+ cbEditParameters();
+ }
+ };
+ Runnable callback = new GuiRunnable(cb);
+ m_curAnalyzeCommand = command;
+ sendCommand(command.getCommand() + "\n", callback);
+ } else ShowError.msg(this, "Unknown program!");
+ }
+ //
+ // unknown command
+ //
+ else {
+ System.out.println("Unknown command: '" + cmd + "'.");
+ }
+ }
+
+ // ------------------------------------------------------------
+ /**
+ * Return true if keyboard shortcuts should be enabled. This should be the case unless the user is
+ * currently typing in the text area.
+ */
+ public boolean shortcutsEnabled() {
+ return !m_comment.m_textPane.isFocusOwner();
+ }
+
+ // ------------------------------------------------------------
+ private void cmdShutdown() {
+ if (gameChanged() && !askSaveGame()) return;
+
+ System.out.println("Shutting down...");
+
+ if (m_white_process != null) {
+ System.out.println("Stopping [" + m_white_name + " " + m_white_version + "] process...");
+ m_white_process.destroy();
+ }
+ System.exit(0);
+ }
+
+ private void cmdNewProgram() {
+ Program program = new Program();
+ new EditProgramDialog(this, program, "Add New Program", true);
+
+ if (program.m_name == null) // user canceled
+ return;
+
+ // add the program to the list of programs
+ m_programs.add(program);
+ Program.save(m_programs);
+ }
+
+ private void cmdEditProgram() {
+ if (m_programs.isEmpty()) {
+ ShowError.msg(this, "No programs, add a program first.");
+ return;
+ }
+
+ ChooseProgramDialog dialog =
+ new ChooseProgramDialog(this, "Choose program to edit", m_programs);
+ dialog.setVisible(true);
+ Program program = dialog.getProgram();
+ dialog.dispose();
+
+ if (program == null) return;
+
+ new EditProgramDialog(this, program, "Edit Program", false);
+
+ Program.save(m_programs);
+ }
+
+ private void cmdDeleteProgram() {
+ if (m_programs.isEmpty()) {
+ ShowError.msg(this, "No programs, add a program first.");
+ return;
+ }
+
+ ChooseProgramDialog dialog =
+ new ChooseProgramDialog(this, "Choose program to delete", m_programs);
+ dialog.setVisible(true);
+ Program program = dialog.getProgram();
+ dialog.dispose();
+
+ if (program == null) return;
+
+ if (!m_programs.remove(program))
+ System.out.println("cmdDeleteProgram: program was not in list!");
+
+ Program.save(m_programs);
+ }
+
+ private void cmdConnectLocalProgram() {
+ ChooseProgramDialog dialog =
+ new ChooseProgramDialog(this, "Choose program to connect", m_programs);
+ dialog.setVisible(true);
+ Program program = dialog.getProgram();
+ dialog.dispose();
+
+ if (program == null) // user aborted
+ return;
+
+ cmdConnectLocalProgram(program);
+ }
+
+ /**
+ * @note NOT CURRENTLY USED!
+ */
+ private void cmdConnectRemoteProgram() {
+ int port = 20000;
+ String hostname = "localhost";
+
+ String remote = m_preferences.get("remote-host-name");
+ String name = RemoteProgramDialog.show(this, remote);
+ if (name == null) // user aborted
+ return;
+
+ hostname = name;
+ System.out.print("Connecting to HTP program at [" + hostname + "] on port " + port + "...");
+ System.out.flush();
+
+ try {
+ m_white_socket = new Socket(hostname, port);
+ } catch (UnknownHostException e) {
+ ShowError.msg(this, "Unknown host: '" + e.getMessage() + "'");
+ System.out.println("\nconnection attempt aborted.");
+ return;
+ } catch (IOException e) {
+ ShowError.msg(this, "Error creating socket: '" + e.getMessage() + "'");
+ System.out.println("\nconnection attempt aborted.");
+ return;
+ }
+ System.out.println("connected.");
+
+ InputStream in;
+ OutputStream out;
+ try {
+ in = m_white_socket.getInputStream();
+ out = m_white_socket.getOutputStream();
+ } catch (IOException e) {
+ ShowError.msg(this, "Error obtaining socket stream: " + e.getMessage());
+ m_white = null;
+ return;
+ }
+ m_preferences.put("remote-host-name", hostname);
+ connectProgram(in, out);
+ }
+
+ // ------------------------------------------------------------
+
+ private void cmdConnectLocalProgram(Program program) {
+ Runtime runtime = Runtime.getRuntime();
+
+ String cmd = program.m_command;
+ System.out.println("Executing '" + program.m_name + "':");
+ System.out.println("Command = '" + cmd + "'");
+ System.out.println("Working directory = '" + program.m_working + "'");
+
+ File working = null;
+ if (!program.m_working.trim().equals("")) {
+ ShowError.msg(
+ this, "Working directory not implemented! " + "Running with no working directory.");
+
+ // working = new File(program.m_working);
+ // if (!working.isDirectory())
+ // {
+ // ShowError.msg(this, "Invalid working directory: '"
+ // + working.getName() + "'");
+ // }
+ }
+
+ try {
+ // Create command array with StringUtil::splitArguments
+ // because Runtime.exec(String) uses a default StringTokenizer
+ // which does not respect ".
+ String[] cmdArray = StringUtils.splitArguments(cmd);
+ // Make file name absolute, if working directory is not current
+ // directory. With Java 1.5, it seems that Runtime.exec succeeds
+ // if the relative path is valid from the current, but not from
+ // the given working directory, but the process is not usable
+ // (reading from its input stream immediately returns
+ // end-of-stream)
+ if (cmdArray.length > 0) {
+ File file = new File(cmdArray[0]);
+ // Only replace if executable is a path to a file, not
+ // an executable in the exec-path
+ if (file.exists()) cmdArray[0] = file.getAbsolutePath();
+ }
+
+ m_white_process = runtime.exec(cmdArray);
+ // m_white_process = runtime.exec(cmdArray, null, workingDirectory);
+ // m_white_process = runtime.exec(cmd);
+ } catch (Throwable e) {
+ ShowError.msg(this, "Error starting " + program.m_name + ": '" + e.getMessage() + "'");
+ return;
+ }
+
+ m_program = program;
+ m_preferences.put("is-program-attached", true);
+ m_preferences.put("attached-program", program.m_name);
+
+ Process proc = m_white_process;
+
+ ///////////////////////////////
+ /// FIXME: DEBUGING!!! REMOVE!
+ Thread blah = new Thread(new StreamCopy(false, proc.getErrorStream(), System.out, false));
+ blah.start();
+ ///////////////////////////////
+
+ connectProgram(proc.getInputStream(), proc.getOutputStream());
+ }
+
+ private void createAnalyzeDialog() {
+ m_analyzeDialog = new AnalyzeDialog(this, this, m_analyzeCommands, m_messageDialogs);
+ m_analyzeDialog.addWindowListener(
+ new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ m_analyzeDialog.setVisible(false);
+ m_menubar.setAnalyzeVisible(false);
+ }
+ });
+ m_analyzeDialog.setBoardSize(m_guiboard.getBoardSize().width);
+ m_analyzeDialog.setSelectedColor(m_tomove);
+ }
+
+ public void actionDisposeAnalyzeDialog() {
+ if (m_analyzeDialog != null) {
+ m_analyzeDialog.dispose();
+ m_analyzeDialog = null;
+ m_menubar.setAnalyzeVisible(false);
+ }
+ }
+
+ private void connectProgram(InputStream in, OutputStream out) {
+ m_shell = new HtpShell(this, this);
+ m_shell.addWindowListener(
+ new WindowAdapter() {
+ public void windowClosing(WindowEvent winEvt) {
+ m_menubar.setShellVisible(false);
+ }
+ });
+ m_white = new HtpController(in, out, m_shell, this);
+
+ // get name and version information; block until
+ // version is returned.
+
+ acquireSemaphore();
+ htpName();
+ htpVersion(); // releases semaphore when finished.
+ acquireSemaphore();
+ releaseSemaphore();
+
+ m_shell.setTitle("HexGui: [" + m_white_name + " " + m_white_version + "] Shell");
+
+ // get list of accepted commands; block until
+ // this is completed.
+ acquireSemaphore();
+ htpAnalyzeCommands(); // releases semaphore when finished
+ acquireSemaphore();
+ releaseSemaphore();
+
+ createAnalyzeDialog();
+
+ m_toolbar.setProgramConnected(true);
+ m_menubar.setProgramConnected(true);
+
+ m_shell.setVisible(m_preferences.getBoolean("shell-show-on-connect"));
+ m_analyzeDialog.setVisible(m_preferences.getBoolean("analyze-show-on-connect"));
+
+ htpBoardsize(m_guiboard.getBoardSize());
+
+ // Replay all moves up to the current node.
+ replayUpToNode(m_current);
+ htpShowboard();
+ }
+
+ // Replay all moves up to the given node. Do this without changing
+ // the current node.
+ private void replayUpToNode(Node node) {
+ Vector path = new Vector();
+ while (node != null) {
+ path.add(node);
+ node = node.getParent();
+ }
+ m_guiboard.clearAll();
+ htpClearBoard();
+ for (int i = path.size() - 1; i >= 0; i--) {
+ node = path.elementAt(i);
+ if (node.hasMove()) {
+ Move move = node.getMove();
+ guiPlay(move);
+ htpPlay(move);
+ }
+ if (node.hasSetup()) {
+ playSetup(node);
+ }
+ }
+ }
+
+ /**
+ * Run HTP commands to set up the current board position from scratch. This may be necessary when
+ * a setup move removes a piece, or changes the color of an existing piece, or when swap-pieces is
+ * played, since there is no valid HTP command to do so.
+ */
+ private void htpSetUpCurrentBoard() {
+ htpClearBoard();
+ Dimension size = m_guiboard.getBoardSize();
+ for (int y = 0; y < size.height; y++) {
+ for (int x = 0; x < size.width; x++) {
+ HexPoint point = HexPoint.get(x, y);
+ HexColor c = m_guiboard.getColor(point);
+ if (c == HexColor.BLACK || c == HexColor.WHITE) {
+ htpPlay(new Move(point, c));
+ }
+ }
+ }
+ }
+
+ private void cmdDisconnectProgram() {
+ if (m_white == null) return;
+
+ htpQuit();
+ try {
+ if (m_white_process != null) {
+ m_white_process.waitFor();
+ m_white_process = null;
+ }
+ if (m_white_socket != null) {
+ m_white_socket.close();
+ m_white_socket = null;
+ }
+ m_white = null;
+ m_shell.dispose();
+ m_shell = null;
+ actionDisposeAnalyzeDialog();
+ m_program = null;
+ m_menubar.setProgramConnected(false);
+ m_toolbar.setProgramConnected(false);
+ m_preferences.put("is-program-attached", false);
+ } catch (Throwable e) {
+ ShowError.msg(this, "Error: " + e.getMessage());
+ }
+ }
+
+ private void cmdReconnectProgram() {
+ Program prog = m_program;
+ cmdDisconnectProgram();
+ cmdConnectLocalProgram(prog);
+ }
+
+ // ------------------------------------------------------------
+
+ private void cmdNewGame() {
+ if (gameChanged() && !askSaveGame()) return;
+
+ String size = m_menubar.getSelectedBoardSize();
+ Dimension dim = new Dimension(-1, -1);
+ if (size.equals("Other...")) {
+ size = BoardSizeDialog.show(this, m_guiboard.getBoardSize());
+ if (size == null) return;
+ }
+
+ try {
+ StringTokenizer st = new StringTokenizer(size);
+ int w = Integer.parseInt(st.nextToken());
+ st.nextToken();
+ int h = Integer.parseInt(st.nextToken());
+ dim.setSize(w, h);
+ } catch (Throwable t) {
+ ShowError.msg(this, "Size should be in format 'w x h'.");
+ return;
+ }
+
+ if (dim.width < 1 || dim.height < 1) {
+ ShowError.msg(this, "Invalid board size.");
+ } else {
+ m_tomove = HexColor.BLACK;
+ m_toolbar.setToMove(m_tomove.toString());
+
+ m_root = new Node();
+ m_current = m_root;
+ m_gameinfo = new GameInfo();
+ m_gameinfo.setBoardSize(dim);
+ stopClock(HexColor.BLACK);
+ stopClock(HexColor.WHITE);
+ m_blackClock.setElapsed(0);
+ m_whiteClock.setElapsed(0);
+ setComment(m_current);
+
+ m_file = null;
+ resetGameChanged();
+ setFrameTitle();
+
+ m_guiboard.initSize(dim.width, dim.height);
+ m_guiboard.repaint();
+
+ m_preferences.put("gui-board-width", dim.width);
+ m_preferences.put("gui-board-height", dim.height);
+
+ m_toolbar.updateButtonStates(m_current, this);
+ m_menubar.updateMenuStates(this);
+
+ htpBoardsize(m_guiboard.getBoardSize());
+ htpShowboard();
+
+ setCursorType();
+ }
+ }
+
+ private boolean cmdSaveGame() {
+ if (m_file == null) m_file = showSaveAsDialog();
+
+ if (m_file != null) {
+ System.out.println("Saving to file: " + m_file.getName());
+ if (save(m_file)) {
+ resetGameChanged();
+ setFrameTitle();
+ m_preferences.put("path-save-game", m_file.getPath());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean cmdSaveGameAs() {
+ File file = showSaveAsDialog();
+ if (file == null) return false;
+
+ m_file = file;
+ return cmdSaveGame();
+ }
+
+ private void cmdSavePositionAs() {
+ File file = showSaveAsDialog();
+ if (file != null) savePosition(file);
+ }
+
+ private void cmdLoadGame() {
+ if (gameChanged() && !askSaveGame()) return;
+ File file = showOpenDialog();
+ if (file != null) loadGame(file);
+ }
+
+ private void cmdPrintPreview() {
+ JFrame frame = new JFrame();
+ // frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ Container con = frame.getContentPane();
+
+ PrintPreview pp = new PrintPreview(m_guiboard);
+ con.add(pp, BorderLayout.CENTER);
+
+ frame.pack();
+ frame.setVisible(true);
+ frame.toFront();
+ }
+
+ private void cmdPrint() {
+ Print.run(this, m_guiboard);
+ }
+
+ private void cmdAbout() {
+ m_about.setVisible(true);
+ }
+
+ // ------------------------------------------------------------
+
+ private void cmdGuiToolbarVisible() {
+ boolean visible = m_menubar.getToolbarVisible();
+ m_toolbar.setVisible(visible);
+ }
+
+ private void cmdGuiShellVisible() {
+ if (m_shell == null) return;
+ boolean visible = m_menubar.getShellVisible();
+ m_shell.setVisible(visible);
+ }
+
+ private void cmdGuiAnalyzeVisible() {
+ if (m_analyzeDialog == null) return;
+ boolean visible = m_menubar.getAnalyzeVisible();
+ m_analyzeDialog.setVisible(visible);
+ }
+
+ private void cmdGuiBoardDrawType() {
+ String type = m_menubar.getCurrentBoardDrawType();
+ System.out.println(type);
+ m_guiboard.setDrawType(type);
+ m_guiboard.repaint();
+ }
+
+ private void cmdGuiBoardOrientation() {
+ String type = m_menubar.getCurrentBoardOrientation();
+ System.out.println(type);
+ m_guiboard.setOrientation(type);
+ m_guiboard.repaint();
+ }
+
+ private void cmdClearMarks() {
+ m_guiboard.clearMarks();
+ m_guiboard.repaint();
+ }
+
+ private void cmdShowPreferences() {
+ new PreferencesDialog(this, m_preferences);
+ }
+
+ /**
+ * Toggle the player to move, by explicit user request. This also updates the PL property in the
+ * current node.
+ */
+ private void cmdToggleToMove() {
+ this.toggleToMove();
+ m_current.setPlayerToMove(m_tomove);
+ }
+
+ /** Toggle the player to move, without setting the PL property */
+ private void toggleToMove() {
+ m_tomove = m_tomove.otherColor();
+ m_toolbar.setToMove(m_tomove.toString());
+ m_menubar.setToMove(m_tomove.toString());
+ setCursorType();
+ }
+
+ /**
+ * Set the player to move, by explicit user request. This also updates the PL property in the
+ * current node.
+ */
+ private void cmdSetToMove() {
+ this.setToMove();
+ m_current.setPlayerToMove(m_tomove);
+ }
+
+ /** Set the player to move, without setting the PL property */
+ private void setToMove() {
+ m_tomove = HexColor.get(m_menubar.getToMove());
+ m_toolbar.setToMove(m_tomove.toString());
+ setCursorType();
+ }
+
+ private void cmdSetupBlack() {
+ setCursorType();
+ }
+
+ private void cmdSetupWhite() {
+ setCursorType();
+ }
+
+ // Update the cursor according to the current move type.
+ public void setCursorType() {
+ String clickContext = m_toolbar.getClickContext();
+ if (clickContext == "black") {
+ m_guiboard.setCursorType("black-setup");
+ } else if (clickContext == "white") {
+ m_guiboard.setCursorType("white-setup");
+ } else {
+ if (m_tomove == HexColor.BLACK) {
+ m_guiboard.setCursorType("black");
+ } else {
+ m_guiboard.setCursorType("white");
+ }
+ }
+ }
+
+ // ------------------------------------------------------------
+
+ public void actionClearAnalyzeCommand() {}
+
+ public void actionSetAnalyzeCommand(AnalyzeCommand command) {
+ actionSetAnalyzeCommand(command, false, true, true, false);
+ }
+
+ public void actionSetAnalyzeCommand(
+ AnalyzeCommand command,
+ boolean autoRun,
+ boolean clearBoard,
+ boolean oneRunOnly,
+ boolean reuseTextWindow) {
+ AnalyzeType type = command.getType();
+ if (command.needsPointArg()) {
+ Vector selected = getSelectedCells();
+ if (selected.size() < 1) {
+ m_statusbar.setMessage("Please select a cell before " + "running.");
+ return;
+ }
+ command.setPointArg(selected.get(0));
+ }
+ if (command.needsPointListArg()) {
+ Vector selected = getSelectedCells();
+ if (type == AnalyzeType.VC && selected.size() != 2) {
+ m_statusbar.setMessage("Please select a pair of cells before " + "running.");
+ return;
+ }
+ PointList blah = new PointList(selected);
+ command.setPointListArg(blah);
+ }
+ String cmd = command.replaceWildCards(m_tomove);
+ String cleaned = StringUtils.cleanWhiteSpace(cmd.trim());
+ String args[] = cleaned.split(" ");
+ String c = args[0];
+ m_curAnalyzeCommand = command;
+
+ Runnable cb = null;
+ switch (type) {
+ case GROUP:
+ cb =
+ new Runnable() {
+ public void run() {
+ cbGroupGet();
+ }
+ };
+ break;
+ case GFX:
+ cb =
+ new Runnable() {
+ public void run() {
+ cbGfx();
+ }
+ };
+ break;
+ case INFERIOR:
+ cb =
+ new Runnable() {
+ public void run() {
+ cbShowInferiorCells();
+ }
+ };
+ break;
+ case MOVE:
+ cb =
+ new Runnable() {
+ public void run() {
+ cbGenMove();
+ }
+ };
+ break;
+ case PLIST:
+ cb =
+ new Runnable() {
+ public void run() {
+ cbDisplayPointList();
+ }
+ };
+ break;
+ case PSPAIRS:
+ cb =
+ new Runnable() {
+ public void run() {
+ cbDisplayPointText();
+ }
+ };
+ break;
+ case PARAM:
+ cb =
+ new Runnable() {
+ public void run() {
+ cbEditParameters();
+ }
+ };
+ break;
+ case VC:
+ cb =
+ new Runnable() {
+ public void run() {
+ cbVCs();
+ }
+ };
+ break;
+ case STRING:
+ cb =
+ new Runnable() {
+ public void run() {
+ cbString();
+ }
+ };
+ break;
+ case VAR:
+ cb =
+ new Runnable() {
+ public void run() {
+ cbVar();
+ }
+ };
+ break;
+ }
+ // if (c.equals("dfpn-get-bounds"))
+ // cb = new Runnable() { public void run() { cbDfpnDisplayBounds();} };
+ // else if (c.equals("book-scores"))
+ // cb = new Runnable() { public void run() { cbDisplayBookScores(); } };
+ // else if (c.equals("eval-resist"))
+ // cb = new Runnable() { public void run() { cbEvalResist(); } };
+ Runnable callback = null;
+ if (cb != null) callback = new GuiRunnable(cb);
+ sendCommand(cmd + "\n", callback);
+ }
+
+ /**
+ * HtpShell Callback. By the name of the command it choose the proper callback function. Arguments
+ * are passed as given.
+ */
+ public void commandEntered(String cmd) {
+ sendCommand(cmd, null);
+ }
+
+ // ----------------------------------------------------------------------
+
+ private boolean commandNeedsToLockGUI(String cmd) {
+ if ((cmd.length() > 7 && cmd.substring(0, 7).equals("genmove"))
+ || (cmd.length() > 15 && cmd.substring(0, 15).equals("dfs-solve-state"))
+ || (cmd.length() > 16 && cmd.substring(0, 16).equals("dfpn-solve-state"))
+ || (cmd.length() > 23 && cmd.substring(0, 23).equals("dfs-solver-find-winning"))
+ || (cmd.length() > 24 && cmd.substring(0, 24).equals("dfpn-solver-find-winning")))
+ return true;
+ return false;
+ }
+
+ private void lockGUI() {
+ m_locked = true;
+ m_toolbar.lockToolbar();
+ }
+
+ private void unlockGUI() {
+ m_toolbar.unlockToolbar(m_current, this);
+ m_locked = false;
+ }
+
+ /** A (command, callback) pair. */
+ private class HtpCommand {
+ public HtpCommand() {}
+
+ public HtpCommand(String cmd, Runnable callback) {
+ this.str = cmd;
+ this.callback = callback;
+ }
+
+ public String str;
+ public Runnable callback;
+ }
+
+ /** Waits for commands to be added to the queue, then processes each in turn. */
+ private class CommandHandler implements Runnable {
+
+ public CommandHandler(Component parent, ArrayBlockingQueue queue) {
+ m_parent = parent;
+ m_queue = queue;
+ }
+
+ public void run() {
+ while (true) {
+ HtpCommand cmd = null;
+ try {
+ // block until queue contains an element
+ cmd = m_queue.take();
+ } catch (InterruptedException e) {
+ System.out.println("INTERRUPTED! HUH?");
+ }
+
+ if (m_white != null && m_white.connected()) {
+ if (commandNeedsToLockGUI(cmd.str)) lockGUI();
+
+ try {
+ m_white.sendCommand(cmd.str);
+ if (cmd.callback != null) {
+ cmd.callback.run();
+ }
+ } catch (HtpError e) {
+ System.out.println("Caught error '" + e.getMessage() + "'");
+ ShowError.msg(m_parent, e.getMessage());
+ }
+
+ if (commandNeedsToLockGUI(cmd.str)) unlockGUI();
+ } else {
+ System.out.println("Not sending to disconnected: '" + cmd.str.trim() + "'");
+ }
+ }
+ }
+
+ Component m_parent;
+ ArrayBlockingQueue m_queue;
+ }
+
+ private void sendCommand(String cmd, Runnable callback) {
+ if (m_white == null) return;
+
+ try {
+ System.out.println("sendCommand: '" + cmd.trim() + "'");
+ m_htp_queue.put(new HtpCommand(cmd, callback));
+ } catch (InterruptedException e) {
+ System.out.println("Interrupted while adding!");
+ }
+ }
+
+ // FIXME: add callback?
+ private void htpQuit() {
+ sendCommand("quit\n", null);
+ }
+
+ private void htpName() {
+ Runnable cb =
+ new Runnable() {
+ public void run() {
+ cbName();
+ }
+ };
+ sendCommand("name\n", cb);
+ }
+
+ private void htpVersion() {
+ Runnable cb =
+ new Runnable() {
+ public void run() {
+ cbVersion();
+ }
+ };
+ sendCommand("version\n", cb);
+ }
+
+ private void htpAnalyzeCommands() {
+ Runnable cb =
+ new Runnable() {
+ public void run() {
+ cbAnalyzeCommands();
+ }
+ };
+ sendCommand("hexgui-analyze_commands\n", cb);
+ }
+
+ private void htpClearBoard() {
+ sendCommand("clear_board\n", null);
+ }
+
+ private void htpShowboard() {
+ sendCommand("showboard\n", null);
+ }
+
+ /**
+ * Play a move on the attached HTP backend. This only works if move is a legal move of color black
+ * or white. There is no HTP command for setup moves that remove a piece, or that change the color
+ * of an already existing piece, and swap, pass, resign, and forfeit moves are possibly not
+ * implemented in HTP, or may not be undoable correctly. If the move is swap-pieces, just update
+ * HTP to the current board position; so gui should always be updated before calling this.
+ */
+ private void htpPlay(Move move) {
+ if (move.getPoint() == HexPoint.RESIGN
+ || move.getPoint() == HexPoint.FORFEIT
+ || move.getPoint() == HexPoint.SWAP_SIDES
+ || move.getPoint() == HexPoint.PASS) {
+ return;
+ }
+ if (move.getPoint() == HexPoint.SWAP_PIECES) {
+ htpSetUpCurrentBoard();
+ return;
+ }
+ sendCommand(
+ "play " + move.getColor().toString() + " " + move.getPoint().toString() + "\n", null);
+ }
+
+ /** GUI must already be updated prior to calling this. */
+ private void htpUndo(Move move) {
+ if (move.getPoint() == HexPoint.RESIGN
+ || move.getPoint() == HexPoint.FORFEIT
+ || move.getPoint() == HexPoint.SWAP_SIDES
+ || move.getPoint() == HexPoint.PASS) {
+ return;
+ }
+ sendCommand("undo\n", null);
+ }
+
+ private void htpGenMove(HexColor color) {
+ if (!checkBoardSizeSupported()) return;
+ m_statusbar.setMessage(format("{0} is thinking...", m_white_name));
+ Runnable callback =
+ new GuiRunnable(
+ new Runnable() {
+ public void run() {
+ cbGenMove();
+ }
+ });
+ sendCommand("genmove " + color.toString() + "\n", callback);
+ }
+
+ private void htpBoardsize(Dimension size) {
+ Runnable callback =
+ new Runnable() {
+ public void run() {
+ m_unsupportedBoardSize = !m_white.wasSuccess();
+ checkBoardSizeSupported();
+ }
+ };
+ sendCommand("boardsize " + size.width + " " + size.height + "\n", callback);
+ m_statusbar.setMessage("New game");
+ }
+
+ //
+ // Callbacks
+ //
+ public void cbName() {
+ String str = m_white.getResponse();
+ // FIXME: handle errors!
+ m_white_name = str.trim();
+ }
+
+ public void cbVersion() {
+ String str = m_white.getResponse();
+ // FIXME: handle errors!
+ m_white_version = str.trim();
+ releaseSemaphore();
+ }
+
+ private void cbAnalyzeCommands() {
+ String programAnalyzeCommands = m_white.getResponse();
+ try {
+ m_analyzeCommands = AnalyzeDefinition.read(programAnalyzeCommands);
+ } catch (ErrorMessage e) {
+ ShowError.msg(this, "Could not parse analyze commands!");
+ }
+ releaseSemaphore();
+ }
+
+ public void cbGenMove() {
+ if (!m_white.wasSuccess()) return;
+ m_guiboard.clearMarks();
+ String str = m_white.getResponse();
+ HexPoint point = HexPoint.get(str.trim());
+ if (point == null) {
+ System.out.println("Invalid move!!");
+ } else {
+ play(new Move(point, m_tomove));
+ }
+ }
+
+ public void cbDisplayPointList() {
+ if (!m_white.wasSuccess()) return;
+ String str = m_white.getResponse();
+ Vector points = StringUtils.parsePointList(str);
+ m_guiboard.clearMarks();
+ for (int i = 0; i < points.size(); i++) {
+ m_guiboard.setAlphaColor(points.get(i), Color.green);
+ }
+ m_guiboard.repaint();
+ }
+
+ private void cbDfpnDisplayBounds() {
+ if (!m_white.wasSuccess()) return;
+ String str = m_white.getResponse();
+ showDfpnBounds(str);
+ m_guiboard.repaint();
+ }
+
+ public void cbGroupGet() {
+ if (!m_white.wasSuccess()) return;
+ String str = m_white.getResponse();
+ Vector points = StringUtils.parsePointList(str);
+ m_guiboard.clearMarks();
+ if (points.size() > 0) {
+ m_guiboard.setAlphaColor(points.get(0), Color.blue);
+ for (int i = 1; i < points.size(); i++) {
+ m_guiboard.setAlphaColor(points.get(i), Color.green);
+ }
+ }
+ m_guiboard.repaint();
+ }
+
+ public void cbGfx() {
+ if (!m_white.wasSuccess()) return;
+ m_guiboard.clearMarks();
+ m_guiboard.aboutToDirtyStones();
+
+ String fx = m_white.getResponse();
+ int inf = fx.indexOf("INFLUENCE");
+ if (inf < 0) return;
+ boolean hasText = false;
+ int text = fx.indexOf("TEXT");
+ if (text < 0) text = fx.length();
+ else {
+ hasText = true;
+ }
+
+ Vector> pairs =
+ StringUtils.parseStringPairList(fx.substring(inf + 10, text));
+ for (int i = 0; i < pairs.size(); i++) {
+ HexPoint point = HexPoint.get(pairs.get(i).first);
+ String value = pairs.get(i).second;
+ float v = new Float(value).floatValue();
+ m_guiboard.setAlphaColor(point, new Color(0, v, 1 - v), 0.7f);
+ }
+ if (hasText) m_statusbar.setMessage(fx.substring(text + 5));
+ m_guiboard.repaint();
+ }
+
+ public void cbShowInferiorCells() {
+ if (!m_white.wasSuccess()) return;
+ m_guiboard.clearMarks();
+ m_guiboard.aboutToDirtyStones();
+ showInferiorCells(m_white.getResponse());
+ m_guiboard.repaint();
+ }
+
+ public void cbVCs() {
+ if (!m_white.wasSuccess()) return;
+ String str = m_white.getResponse();
+ Vector vcs = StringUtils.parseVCList(str);
+ new VCDisplayDialog(this, m_guiboard, vcs);
+ }
+
+ public void cbString() {
+ if (!m_white.wasSuccess()) return;
+ String showText = m_white.getResponse();
+ String title = m_curAnalyzeCommand.getResultTitle();
+ if (showText != null) {
+ if (showText.indexOf("\n") < 0) {
+ if (showText.trim().equals("")) showText = "(empty response)";
+ m_statusbar.setMessage(format("{0}: {1}", title, showText));
+ } else {
+ HexPoint pointArg = null;
+ m_showAnalyzeText.show(m_curAnalyzeCommand.getType(), pointArg, title, showText, false);
+ }
+ }
+ }
+
+ public void cbVar() {
+ if (!m_white.wasSuccess()) return;
+ String str = m_white.getResponse();
+ Vector points = StringUtils.parsePointList(str, " ");
+ m_guiboard.clearMarks();
+ m_guiboard.aboutToDirtyStones();
+ HexColor color = m_tomove;
+ for (int i = 0; i < points.size(); i++) {
+ m_guiboard.setColor(points.get(i), color);
+ m_guiboard.setText(points.get(i), Integer.toString(i + 1));
+ color = color.otherColor();
+ }
+ m_guiboard.repaint();
+ }
+
+ public void cbDisplayPointText() {
+ if (!m_white.wasSuccess()) return;
+ String str = m_white.getResponse();
+ Vector> pairs = StringUtils.parseStringPairList(str);
+ m_guiboard.clearMarks();
+ for (int i = 0; i < pairs.size(); i++) {
+ HexPoint point = HexPoint.get(pairs.get(i).first);
+ String value = pairs.get(i).second;
+ m_guiboard.setText(point, value);
+ }
+ m_guiboard.repaint();
+ }
+
+ public void cbDisplayBookScores() {
+ if (!m_white.wasSuccess()) return;
+ String str = m_white.getResponse();
+ Vector> pairs = StringUtils.parseStringPairList(str);
+ m_guiboard.clearMarks();
+ for (int i = 0; i < pairs.size(); i++) {
+ HexPoint point = HexPoint.get(pairs.get(i).first);
+ String value = pairs.get(i).second;
+ m_guiboard.setText(point, value);
+ if (i == 0) m_guiboard.setAlphaColor(point, Color.red);
+ else if (1 <= i && i <= 3) m_guiboard.setAlphaColor(point, Color.green);
+ }
+ m_guiboard.repaint();
+ }
+
+ public void cbEvalResist() {
+ if (!m_white.wasSuccess()) return;
+ String str = m_white.getResponse();
+ Vector> pairs = StringUtils.parseStringPairList(str);
+ String res = "";
+ String rew = "";
+ String reb = "";
+ m_guiboard.clearMarks();
+ for (int i = 0; i < pairs.size(); i++) {
+ if (pairs.get(i).first.equals("res")) {
+ res = pairs.get(i).second;
+ } else if (pairs.get(i).first.equals("rew")) {
+ rew = pairs.get(i).second;
+ } else if (pairs.get(i).first.equals("reb")) {
+ reb = pairs.get(i).second;
+ } else {
+ HexPoint point = HexPoint.get(pairs.get(i).first);
+
+ String value = pairs.get(i).second;
+ m_guiboard.setText(point, value);
+ }
+ }
+ m_guiboard.repaint();
+ m_statusbar.setMessage("Resistance: " + res + " (" + rew + " - " + reb + ")");
+ }
+
+ public void cbEditParameters() {
+ if (!m_white.wasSuccess()) return;
+ String response = m_white.getResponse();
+ ParameterDialog.editParameters(
+ m_curAnalyzeCommand.getCommand(),
+ this,
+ "Edit Parameters",
+ response,
+ m_white,
+ m_messageDialogs);
+ }
+
+ public void cbSolveState() {
+ if (!m_white.wasSuccess()) return;
+ String response = m_white.getResponse();
+ m_statusbar.setMessage(format("Winning: {0}", response));
+ }
+
+ // ==================================================
+ // gfx commands
+ // ==================================================
+ public void guifx(String fx) {
+ System.out.println("gogui-gfx:\n'" + fx + "'");
+
+ if (fx.length() > 3 && fx.substring(0, 3).equals("uct")) guifx_uct(fx.substring(3));
+ else if (fx.length() > 2 && fx.substring(0, 2).equals("ab")) guifx_ab(fx.substring(2));
+ else if (fx.length() > 4 && fx.substring(0, 4).equals("dfpn")) guifx_dfpn(fx.substring(4));
+ else if (fx.length() > 6 && fx.substring(0, 6).equals("solver")) guifx_solver(fx.substring(6));
+ }
+
+ private void guifx_uct(String fx) {
+ String[] tk = fx.trim().split(" ");
+ int i = 0;
+
+ m_guiboard.clearMarks();
+ m_guiboard.aboutToDirtyStones();
+
+ /**
+ * @todo Fix this to parse like guifx_ab() and guifx_solver().
+ */
+
+ //////////////////////////////////////
+ // display variation
+ for (; i < tk.length; ++i) {
+ String s = tk[i].trim();
+ if (s.equals("VAR")) break;
+ }
+ if (i == tk.length) return;
+ ++i; // skip "VAR";
+
+ Vector var = new Vector();
+ Vector col = new Vector();
+ for (; i < tk.length; ) {
+ String s = tk[i].trim();
+ if (s.equals("INFLUENCE")) break;
+ ++i; // skip 'B' and 'W'
+
+ col.add((s.charAt(0) == 'B') ? HexColor.BLACK : HexColor.WHITE);
+ HexPoint point = HexPoint.get(tk[i++].trim());
+ var.add(point);
+ }
+
+ m_guiboard.setColor(var.get(0), col.get(0));
+ m_guiboard.setAlphaColor(var.get(0), Color.cyan);
+ if (var.size() > 1) {
+ m_guiboard.setColor(var.get(1), col.get(1));
+ m_guiboard.setAlphaColor(var.get(1), Color.blue);
+ }
+
+ /////////////////////////////////////////
+ // display score/search counts
+
+ TreeMap