Package games.stendhal.client.gui.login

Source Code of games.stendhal.client.gui.login.CharacterDialog$CreateCharacterAction

/* $Id: CharacterDialog.java,v 1.13 2011/02/19 13:56:30 kiheru Exp $ */
/***************************************************************************
*                   (C) Copyright 2003-2010 - Stendhal                    *
***************************************************************************
***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/
package games.stendhal.client.gui.login;

import games.stendhal.client.StendhalClient;
import games.stendhal.client.stendhal;
import games.stendhal.client.entity.IEntity;
import games.stendhal.client.entity.Player;
import games.stendhal.client.gui.j2d.entity.EntityView;
import games.stendhal.client.gui.j2d.entity.EntityViewFactory;
import games.stendhal.client.gui.layout.SBoxLayout;
import games.stendhal.client.gui.layout.SLayout;

import java.awt.Container;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import marauroa.client.BannedAddressException;
import marauroa.client.TimeoutException;
import marauroa.common.game.CharacterResult;
import marauroa.common.game.RPObject;
import marauroa.common.net.InvalidVersionException;

import org.apache.log4j.Logger;

/**
* A dialog for selecting from the available characters of a user account.
*/
public final class CharacterDialog extends JDialog implements Runnable {
  private static final long serialVersionUID = -8827654641088132946L;

  private static Logger logger = Logger.getLogger(CharacterDialog.class);

  /** Maximum dialog width in pixels */
  private static final int DIALOG_WIDTH = 640;
  /** Maximum dialog height in pixels */
  private static final int DIALOG_HEIGHT = 480;
  /** Maximum number of character buttons per row */
  private static final int MAX_COLUMNS = 4;
  /** Width of a player image in pixels */
  private static final int IMAGE_WIDTH = 32;
  /** Height of a player image in pixels */
  private static final int IMAGE_HEIGHT = 48;
  /**
   * Maximum number of characters / account. A soft limit since this
   * is client side.
   */
  private static final int MAX_CHARACTERS = 16;
 
 
  /** Area containing buttons for each character */
  private final JComponent characterPanel;
 
  private JFrame owner;
 
  /**
   * Create a new <code>CharacterDialog</code>.
   *
   * @param characters map of available characters, and <code>RPObjects</code>
   *   representing them
   * @param owner the parent window
   */
  public CharacterDialog(final Map<String, RPObject> characters, JFrame owner) {
    super(owner);
    this.owner = owner;
    setTitle("Choose character");
   
    this.addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent e) {
        onClose();
      }
    });
   
    int pad = SBoxLayout.COMMON_PADDING;
    setLayout(new SBoxLayout(SBoxLayout.VERTICAL, pad));
    Container content = getContentPane();
    if (content instanceof JComponent) {
      ((JComponent) content).setBorder(BorderFactory.createEmptyBorder(pad, pad, pad, pad));
    }
   
    // Create the character area
    characterPanel = new JPanel();
    characterPanel.setBorder(null);
    // Do not add empty places if the first row is not full
    int columns = Math.min(MAX_COLUMNS, characters.keySet().size());
    GridLayout grid = new GridLayout(0, columns);
    characterPanel.setLayout(grid);
    JScrollPane scroll = new JScrollPane(characterPanel);
    add(scroll, SBoxLayout.constraint(SLayout.EXPAND_X));
   
    addCharacters(characters);
   
    // Create area for additional buttons
    JComponent buttonBar = SBoxLayout.createContainer(SBoxLayout.HORIZONTAL, SBoxLayout.COMMON_PADDING);
    add(buttonBar, SBoxLayout.constraint(SLayout.EXPAND_X));
   
    // Align the buttons right
    SBoxLayout.addSpring(buttonBar);
   
    // Action buttons. Should these be of uniform size?
    JButton newCharButton = new JButton("New Character");
    newCharButton.addActionListener(new CreateCharacterAction(this));
    // Disable creating unreasonable amounts of characters. Enough is enough.
    if (characters.keySet().size() >= MAX_CHARACTERS) {
      newCharButton.setEnabled(false);
    }
    buttonBar.add(newCharButton);
   
    JButton exitButton = new JButton("Cancel");
    exitButton.addActionListener(new ActionListener() {
      public void actionPerformed(final ActionEvent evt) {
        onClose();
      }
    });
    buttonBar.add(exitButton);
   
    pack();
    setSize(Math.min(getWidth(), DIALOG_WIDTH), Math.min(getHeight(), DIALOG_HEIGHT));
    if (owner != null) {
      owner.setEnabled(false);
      this.setLocationRelativeTo(owner);
    }
   
    Thread thread = new Thread(this, "KeepAlive on character dialog");
    thread.setDaemon(true);
    thread.start();

    setResizable(false);
    setVisible(true);
  }
 
  /**
   * Add the available characters.
   *
   * @param characters
   */
  private void addCharacters(final Map<String, RPObject> characters) {
    for (Entry<String, RPObject> character : characters.entrySet()) {
      JButton button = createCharacterButton(character.getKey(), character.getValue());
      characterPanel.add(button);
    }
  }
 
  /**
   * Create a button for a character.
   *
   * @param name Name of the character
   * @param character Object representing the character
   *
   * @return a button for the character
   */
  private JButton createCharacterButton(final String name, final RPObject character) {
    // Abusing EntityView code to get the image of the player.
    // Avoid doing sound stuff. That is not available at this stage of
    // running the client.
    IEntity player = new Player() {
      @Override
      protected void onPosition(double x, double y) {
      }
      @Override
      protected void addSounds(String groupName, String categoryName, String... soundNames) {
      }
    };
    // Zero the coordinates, otherwise the EntityView will try to draw
    // itself to some weird place
    character.put("x", 0);
    character.put("y", 0);
    // ignore ghostmode for showing the image
    character.remove("ghostmode");
    // ignore player killer skull
    character.remove("last_player_kill_time");
    player.initialize(character);
   
    EntityView view = EntityViewFactory.create(player);
    // this if-block is there to be compatible with Stendhal 0.84 that is missing information
    Icon icon = null;
    if (view != null) {
      Image image = createCharacterImage(view);
      icon = new ImageIcon(image);
    }
   
    // Construct a label for the player button with the information we
    // want to show. Needs to be html as that's the only way JButton
    // can handle multi line labels.
    StringBuilder label = new StringBuilder("<html>");
    label.append(name);
   
    // this if-block is here for compatibility with stendhal server 0.84
    if (character.has("name")) {
      label.append("<br>Level: ");
      String level = "0";
      if (character.has("level")) {
        level = character.get("level");
      }
      label.append(level);
    }
    label.append("</html>");
   
    JButton playerButton = new JButton(label.toString(), icon);
    // Reduce the margins. The buttons are large enough as they are.
    playerButton.setMargin(new Insets(1, 1, 1, 1));
   
    playerButton.addActionListener(new ActionListener() {
      public void actionPerformed(final ActionEvent evt) {
        chooseCharacter(name);
      }
    });
   
    return playerButton;
  }
 
  /**
   * Create a character image from the view.
   * 
   * @param view view of the player
   * @return A front view image of the player
   */
  private Image createCharacterImage(EntityView view) {
    Image image = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage(IMAGE_WIDTH, IMAGE_HEIGHT, Transparency.BITMASK);
    Graphics2D g2d = (Graphics2D) image.getGraphics();
   
    // Adjust the coordinates so that the actual player image gets
    // drawn to the image area
    g2d.translate(0, IMAGE_HEIGHT % 32);
    view.draw(g2d);
    g2d.dispose();
   
    return image;
  }
 
  /**
   * Called when the window is closed or the exit button is pressed.
   */
  private void onClose() {
    if (owner == null) {
      System.exit(0);
    }
    owner.setEnabled(true);
    this.setVisible(false);
    dispose();
  }
 
  /**
   * Called when a character is selected.
   *
   * @param character player selected by the user
   */
  private void chooseCharacter(final String character) {
    try {
      StendhalClient.get().chooseCharacter(character);
      setVisible(false);
      if (owner != null) {
        owner.dispose();
      }
      stendhal.setDoLogin();
      dispose();
    } catch (TimeoutException e) {
      logger.error(e, e);
      handleError("Your connection timed out, please login again.", "Choose Character");
    } catch (InvalidVersionException e) {
      logger.error(e, e);
      handleError("Your version of Stendhal is incompatible with the server.", "Choose Character");
    } catch (BannedAddressException e) {
      logger.error(e, e);
      handleError("Please login again.", "Choose Character");
    }
  }

  /**
   * Displays the error message, removes the progress bar and
   * either enabled the login dialog in interactive mode or exits
   * the client in non interactive mode.
   *
   * @param errorMessage error message
   * @param errorTitle   title of error dialog box
   */
  private void handleError(String errorMessage, String errorTitle) {
    JOptionPane.showMessageDialog(
        this, errorMessage, errorTitle, JOptionPane.ERROR_MESSAGE);

    if (owner != null) {
      setVisible(false);
      owner.setEnabled(true);
      dispose();
    } else {
      // Hack for non interactive login
      System.exit(1);
    }
  }

  static class CreateCharacterAction implements ActionListener {
    private CharacterDialog parent;
    public CreateCharacterAction(CharacterDialog parent) {
      this.parent = parent;
    }

    public void actionPerformed(final ActionEvent evt) {
      String name = JOptionPane.showInputDialog(parent,
          "Please enter the name of your character (only letters allowed):",
          "Create Character",
          JOptionPane.QUESTION_MESSAGE);

      if (name == null) {
        return;
      }

      try {
        // TODO: error handling, exceptions and return of false
        CharacterResult result = StendhalClient.get().createCharacter(name.toLowerCase(Locale.ENGLISH), new RPObject());
        if (result.getResult().failed()) {
          JOptionPane.showMessageDialog(parent, result.getResult().getText());
        } else {
          parent.setVisible(false);
        }
      } catch (TimeoutException e) {
        logger.error(e, e);
        parent.handleError("Your connection timed out, please login again.", "Choose Character");
      } catch (InvalidVersionException e) {
        logger.error(e, e);
        parent.handleError("Your version of Stendhal is incompatible with the server.", "Choose Character");
      } catch (BannedAddressException e) {
        logger.error(e, e);
        parent.handleError("Please login again.", "Choose Character");
      }
    }
  }

  public void run() {
    while (isVisible()) {
      StendhalClient.get().sendKeepAlive();
      try {
        Thread.sleep(5*60*1000);
      } catch (InterruptedException e) {
        break;
      }
    }
  }
}
TOP

Related Classes of games.stendhal.client.gui.login.CharacterDialog$CreateCharacterAction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.