/** Write shape to disk. */
    public void saveShape() {
      int colEnd = 0;
      int rowEnd = 0;
      Dimension dim = grid.getDimension();
      int colStart = dim.width;
      int rowStart = dim.height;

      String lineSeperator = System.getProperty("line.separator");
      StringBuffer text =
          new StringBuffer(
              "!Generator: Game of Life (http://www.bitstorm.org/gameoflife/)"
                  + lineSeperator
                  + "!Variation: 23/3"
                  + lineSeperator
                  + "!"
                  + lineSeperator);

      for (int row = 0; row < dim.height; row++) {
        for (int col = 0; col < dim.width; col++) {
          if (grid.getCell(col, row)) {
            if (row < rowStart) rowStart = row;
            if (col < colStart) colStart = col;
            if (row > rowEnd) rowEnd = row;
            if (col > colEnd) colEnd = col;
          }
        }
      }

      for (int row = rowStart; row <= rowEnd; row++) {
        for (int col = colStart; col <= colEnd; col++) {
          text.append(grid.getCell(col, row) ? 'O' : '-');
        }
        text.append(lineSeperator);
      }
      EasyFile file;
      try {
        file = new EasyFile(appletFrame, "Save Game of Life file");
        file.setFileName(filename);
        file.setFileExtension(FILE_EXTENSION);
        file.writeText(text.toString());
      } catch (FileNotFoundException e) {
        new AlertBox(appletFrame, "File error", "Couldn't open this file.\n" + e.getMessage());
      } catch (IOException e) {
        new AlertBox(appletFrame, "File error", "Couldn't write to this file.\n" + e.getMessage());
      }
    }
    /**
     * "Draw" the shape on the grid. (Okay, it's not really drawing). The lines of text represent
     * the cells of the shape.
     *
     * @param name name of shape
     * @param text lines of text
     */
    public Shape makeShape(String name, String text) {
      int col = 0;
      int row = 0;
      boolean cell;
      // Cope with different line endings ("\r\n", "\r", "\n")
      int[][] cellArray;
      Vector cells = new Vector();

      if (text.length() == 0) return null;

      grid.clear();

      Enumeration enums = new LineEnumerator(text);
      while (enums.hasMoreElements()) {
        String line = (String) enums.nextElement();
        if (line.startsWith("#") || line.startsWith("!")) continue;

        char[] ca = line.toCharArray();
        for (col = 0; col < ca.length; col++) {
          switch (ca[col]) {
            case '*':
            case 'O':
            case 'o':
            case 'X':
            case 'x':
            case '1':
              cell = true;
              break;
            default:
              cell = false;
              break;
          }
          if (cell) cells.addElement(new int[] {col, row});
        }
        row++;
      }

      cellArray = new int[cells.size()][];
      for (int i = 0; i < cells.size(); i++) cellArray[i] = (int[]) cells.get(i);
      return new Shape(name, cellArray);
    }
 /**
  * Set a shape and optionally resizes window.
  *
  * @param shape Shape to set
  */
 public void setShape(Shape shape) {
   int width, height;
   Dimension shapeDim = shape.getDimension();
   Dimension gridDim = grid.getDimension();
   if (shapeDim.width > gridDim.width || shapeDim.height > gridDim.height) {
     // Window has to be made larger
     Toolkit toolkit = getToolkit();
     Dimension screenDim = toolkit.getScreenSize();
     Dimension frameDim = appletFrame.getSize();
     int cellSize = getCellSize();
     // Calculate new window size
     width = frameDim.width + cellSize * (shapeDim.width - gridDim.width);
     height = frameDim.height + cellSize * (shapeDim.height - gridDim.height);
     // Does it fit on the screen?
     if (width > screenDim.width || height > screenDim.height) {
       // With current cellSize, it doesn't fit on the screen
       // GameOfLifeControls.SIZE_SMALL corresponds with GameOfLifeControls.SMALL
       int newCellSize = GameOfLifeControls.SIZE_SMALL;
       width = frameDim.width + newCellSize * shapeDim.width - cellSize * gridDim.width;
       height = frameDim.height + newCellSize * shapeDim.height - cellSize * gridDim.height;
       // a little kludge to prevent de window from resizing twice
       // setNewCellSize only has effect at the next resize
       gameOfLifeCanvas.setAfterWindowResize(shape, newCellSize);
       // The UI has to be adjusted, too
       controls.setZoom(GameOfLifeControls.SMALL);
     } else {
       // Now resize the window (and optionally set the new cellSize)
       gameOfLifeCanvas.setAfterWindowResize(shape, cellSize);
     }
     if (width < 400) width = 400;
     appletFrame.setSize(width, height);
     return;
   }
   try {
     gameOfLifeCanvas.setShape(shape);
   } catch (ShapeException e) {
     // ignore
   }
 }