Package kakuro.gui.editor

Source Code of kakuro.gui.editor.SkeletonPanel$MySkeleton

package kakuro.gui.editor;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;

import javax.swing.JPanel;
import kakuro.server.ISkeletonTable;
import kakuro.table.ITable;
import kakuro.table.Position;
import kakuro.table.TableException;

/** Skeleton szerkesztő panel. Nem négyzet alakú, azt a szerkesztő ablak biztosítja megfelelő layout-tal! */
public class SkeletonPanel extends JPanel {
  /** Szerkesztő ablak */
  private SkeletonEditor _editor = null;
  /** oszlopok száma */
  private int _x = 4;
  /** sorok száma */
  private int _y = 4;
  /** nehézségi szint */
  private int _difficulty = 0;
  /** Fekete mezőket tartalmazó map */
  private HashMap<Position, Boolean> _blacks = new HashMap<Position, Boolean>();
  /** Összes cella, a grafikus megjelenítésért felelős SkellyField-ek */
  private HashMap<Position, SkellyField> _fields = new HashMap<Position, SkellyField>();
  /** fel van-e töltve a tábla számokkal is? */
  private boolean showValues = false;
  /** Reagál-e a tábla az egéreseményekre. Ha false, akkor preview-ként funkcionál */
  private boolean _readOnly = false;
  /** Utolsóként betöltött tábla-modell. Innen kapja a számjegyeket a szerkesztő. */
  private ITable _lastTable = null;
  /** Problémás mezők száma (túl hosszú szavak a gond). */
  private int problematicCounter = 0;
  /** Gyorsításra szolgáló Map, a kirajzolásra használt fontokat tároljuk itt. */
  private static final HashMap<Integer, Font> _fontMap = new HashMap<Integer, Font>();
 
  /** Előre legeneráljuk a használt fontokat, mert ez elég időigényes tábla átméretezése közben. */
  static {
    Font font = new Font("Monospaced", Font.BOLD, 12);
    _fontMap.put(12, font);
    for (int i=13; i<48; i++) _fontMap.put(i, font.deriveFont((float)i));
  }
 
  /** Alap konstruktor
   *
   * @param editor szerkesztő ablak
   * @param readOnly csak olvasható (true: preview ablakként működik)
   * */
  public SkeletonPanel(SkeletonEditor editor, boolean readOnly) {
    _editor = editor;
    _readOnly = readOnly;
    setOpaque(false);
  }
 
  /** Hibamentes-e a skeleton - akkor hibamentes, ha nincs benne 9-nél hosszabb szó. */
  public boolean isCorrect() {
    System.out.println("problematicCounter: "+problematicCounter);
      return problematicCounter==0;
  }
 
  /** Minimum méret
   *
   * @return fixen 100, 100
   * */
  public Dimension getMinimumSize() {
    return new Dimension(100, 100);
  }
 
  /** Preferált méret, fix érték, a layout manager úgyis beméretezi majd helyesen.
   *
   * @return fix 500, 500
   */
  public Dimension getPreferredSize() {
    return new Dimension(500, 500);
  }
 
  /** Skeleton betöltése a panelbe.
   *
   * @param skeleton fekete-fehér tábla
   * */
  public void load(ISkeletonTable skeleton) {
    _x = skeleton.getColumnCount();
    _y = skeleton.getRowCount();
    _difficulty = skeleton.getDifficulty();
    _blacks.clear();
    _fields.clear();
    for (int i=0; i<_x; i++)
      for (int j=0; j<_y; j++)
        if (skeleton.getType(new Position(i, j))==ISkeletonTable.CELL_BLACK)
          _blacks.put(new Position(i, j), true);
    redraw();
  }
 
  /** Panel újraépítése a nulláról, összes gyereket újragyártja a {@link #_blacks} tábla alapján,
   * panelt újraméretezi, hosszú szavakat leellenőrzi, layout-ot újraépíti. */
  protected void redraw() {
    removeAll();
    setPreferredSize(new Dimension(_x * 80, _y * 80));
    setMinimumSize(new Dimension(_x * 40, _y * 40));
    GridLayout layout = new GridLayout(_y, _x, 1, 1);
    setLayout(layout);
   
    for (int j = 0; j < _y; j++) {
      for (int i = 0; i < _x; i++) {
        Position pos = new Position(i, j);
        SkellyField f = new SkellyField(pos, _blacks.containsKey(pos));
        add(f);
        _fields.put(pos, f);
      }
    }
    for (int j = 0; j < _y; j++) {
      for (int i = 0; i < _x; i++) {
        Position pos = new Position(i, j);
        checkLongs(pos);
      }
    }
    validate();
    repaint();
  }
 
  /** Az adott pozíció sorára és oszlopára leellenőrzi, hogy vannak-e túl hosszú szavak.
   *
   * @param p kiindulási pozíció
   * */
  protected void checkLongs(Position p) {
        for (int i=0; i<_x; i++) {
              for (int j=0; j<_y; j++) {
                    if (i==p.x || j==p.y) checkLongs2(new Position(i, j));
              }
        }
  }
 
  /** A kapott pozíciótól jobbra-balra-lefele-felfele megkeresi az első fekete cellákat, és leellenőrzi, hogy
   * túl hosszúak-e ezek a szavak. Ha túl hosszú, akkor a paraméterként kapott pozíciót problémásnak jelöli.
   *
   * @param pos kiindulási pozíció
   * */
  protected void checkLongs2(Position pos) {
        if (_blacks.containsKey(pos)) {
              _fields.get(pos).setProblematic(false);
              return;
        }
        Position p;
        int horizontalCount = 1;
        for (int i=pos.x-1; i>=0; i--) {
              p = new Position(i, pos.y);
              if (_blacks.containsKey(p)) break;
              horizontalCount++;
        }
        for (int i=pos.x+1; i<_x; i++) {
              p = new Position(i, pos.y);
              if (_blacks.containsKey(p)) break;
              horizontalCount++;
        }
        int verticalCount = 1;
        for (int i=pos.y-1; i>=0; i--) {
              p = new Position(pos.x, i);
              if (_blacks.containsKey(p)) break;
              verticalCount++;
        }
        for (int i=pos.y+1; i<_y; i++) {
              p = new Position(pos.x, i);
              if (_blacks.containsKey(p)) break;
              verticalCount++;
        }
        if (horizontalCount>9 || verticalCount>9) {
              _fields.get(pos).setProblematic(true);
        } else {
              _fields.get(pos).setProblematic(false);
        }
  }
 
  /** Belső osztály, egy skeleton cella megjelenítése a feladata. Egéreseményeket is kezeli. */
  private class SkellyField extends JPanel {
    /** Fekete a cella? */
    public boolean isBlack = false;
    /** Fehér cellában szám, fekete cellában első összeg */
    int value1 = 0;
    /** fekete cellában második összeg */
    int value2 = 0;
    /** használt font */
    Font font = null;
    /** cella helye */
    Position _position = null;
    /** problémás a cella? */
    boolean problematic = false;
   
    /** Alap konstruktor. Ha nem readonly a panel, akkor beregisztrálja az egéresemény-kezelőket is.
     *
     * @param p cella helye
     * @param black fekete a cella?
     * */
    public SkellyField(Position p, boolean black) {
      super();
      isBlack = black;
      setPreferredSize(new Dimension(80, 80));
      setMinimumSize(new Dimension(40, 40));
      _position = p;
      refreshStatus();
      refresh();
      if (!_readOnly && p.x!=0 && p.y!=0) addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent e) {
          super.mousePressed(e);
          isBlack ^= true;
          refreshStatus();
          checkLongs(_position);
          refresh();
        }
        public void mouseEntered(MouseEvent e) {
          super.mouseEntered(e);
          if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK)==MouseEvent.BUTTON1_DOWN_MASK) {
            isBlack ^= true;
            refreshStatus();
            checkLongs(_position);
            refresh();
          }
        }
      });
    }
   
    /** Szinkronizálja a cella saját fekete státuszát a panel fekete cellákat tartalmazó
     * {@link SkeletonPanel#_blacks} Map tartalmával. A saját státusza az irányadó! */
    protected void refreshStatus() {
      if (!isBlack && _blacks.containsKey(_position)) {
        _blacks.remove(_position);
      }
      if (isBlack && !_blacks.containsKey(_position)) {
        _blacks.put(_position, true);
      }
    }
   
    /** Cellát (nem) problémásnak jelöli meg, a kapott paramétertől függően.
     *
     * @param p problémás?
     * */
    public void setProblematic(boolean p) {
          if (problematic && !p) {
                problematic = p;
                refresh();
                problematicCounter--;
          } else if (!problematic && p) {
                problematic = p;
                refresh();
                problematicCounter++;
          }
    }
   
    /** Hátteret újrarajzolja */
    protected void refresh() {
      if (isBlack) setBackground(Color.BLACK);
      else {
            if (!problematic) setBackground(Color.WHITE);
            else setBackground(Color.YELLOW);
      }
    }
   
    /** Számértékek, összegek beállítása
     *
     *  @param i első összeg, vagy a fehér mező értéke
     *  @param j második összeg
     *  */
    public void setValues(int i, int j) {
      value1 = i;
      value2 = j;
    }
   
    /** Felüldefiniált paint, az ős paint-je után rárajzolja a panelre a számértékeket is.
     * A számok méretét a cella méretéből próbálja kiszámolni.
     *
     * @param g grafika
     * */
    public void paint(Graphics g) {
      super.paint(g);
      if (!showValues) return;
      Graphics2D g2d = (Graphics2D)g;
      if (font==null) {
        int h = getHeight()/4;
        if (h<12) h=12;
        synchronized (_fontMap) {
          if (!_fontMap.containsKey(h)) {
            _fontMap.put(h, g2d.getFont().deriveFont(Font.BOLD, h));
          }
          font = _fontMap.get(h);
        }
      }
      setFont(font);
      setForeground(isBlack?Color.WHITE:Color.BLACK);
      if (value1>0) {
        if (!isBlack) g2d.drawString(""+value1, getWidth()*5/11, getHeight()*6/11);
        else g2d.drawString(""+value1, getWidth()*3/4, getHeight()*1/3);
      }
      if (value2>0) {
        g2d.drawString(""+value2, getWidth()*1/5, getHeight()*3/4);
      }
    }
  }
 
  /** Skeleton lekérése, minden esetben legyárt egy újat a {@link SkeletonPanel#_blacks} alapján! */
  public ISkeletonTable getSkeleton() {
    return new MySkeleton(_x, _y, _blacks, _difficulty);
  }
 
  /** Belső osztály, egy Skeletont ad meg. */
  public static class MySkeleton implements ISkeletonTable {
    /** Oszlopok száma */
    int xx;
    /** Sorok száma */
    int yy;
    /** Nehézségi szint */
    int diff;
    /** Feketéket tartalmazza csak! */
    HashMap<Position, Boolean> map;
   
    /** Alap konstruktor
     *
     * @param x oszlopok száma
     * @param y sorok száma
     * @param blacks feketéket tartalmazó map, a value értéke lényegtelen!
     * @param difficulty nehézségi szint: {@link ITable#DIFFICULTY_EASY},{@link ITable#DIFFICULTY_MEDIUM},{@link ITable#DIFFICULTY_HARD}
     * */
    public MySkeleton(int x, int y, HashMap<Position, Boolean> blacks, int difficulty) {
      xx = x;
      yy = y;
      map = new HashMap<Position, Boolean>(blacks);
      diff = difficulty;
    }
   
    /** Oszlopok száma
     *
     * @return oszlopok
     * */
    public int getColumnCount() {
      return xx;
    }
   
    /** Nehézségi szint lekérése.
     *
     * @return szint: {@link ITable#DIFFICULTY_EASY},{@link ITable#DIFFICULTY_MEDIUM},{@link ITable#DIFFICULTY_HARD}
     * */
    public int getDifficulty() {
      return diff;
    }
   
    /** Sorok száma
     *
     * @return sorok
     * */
    public int getRowCount() {
      return yy;
    }
   
    /** Adott pozíción található cella típusa
     *
     * @param position hely
     * @return cella típusa: {@link ISkeletonTable#CELL_BLACK}, {@link ISkeletonTable#CELL_WHITE}
     * */
    public int getType(Position position) {
      return (map.containsKey(position)?ISkeletonTable.CELL_BLACK:ISkeletonTable.CELL_WHITE);
    }
    public int getId() {
          return -1;
    }
  }
 
  /** Számértékeket betölt a kapott táblából, és ki is rajzolja őket.
   *
   * @param table kapott kitöltött tábla
   * */
  void showValues(ITable table) throws TableException {
    _lastTable = table;
    ISkeletonTable skeleton = getSkeleton();
    if (table.getColumnCount()!=skeleton.getColumnCount() || table.getRowCount()!=skeleton.getRowCount())
      throw new IndexOutOfBoundsException("Table size mismatch");
    showValues = true;
    for (int j=0; j<_y; j++) {
      for (int i=0; i<_x; i++) {
        Position p = new Position(i, j);
        SkellyField field = _fields.get(p);
        switch (table.getType(p)) {
          case ITable.BLACK_NONE:  field.setValues(0, 0)break;
          case ITable.BLACK_BOTH: field.setValues(table.getSum(p, ITable.SUM_HORIZONTAL), table.getSum(p, ITable.SUM_VERTICAL))break;
          case ITable.BLACK_HORIZONTAL:  field.setValues(table.getSum(p, ITable.SUM_HORIZONTAL), 0)break;
          case ITable.BLACK_VERTICAL:  field.setValues(0, table.getSum(p, ITable.SUM_VERTICAL))break;
          case ITable.WHITE:  field.setValues(table.readCell(p, ITable.VALUE_TRUE), 0)break;
        }
      }
    } 
    validate();
    repaint();
  }
 
  /** Utolsóként kapott kitöltött tábla lekérése.
   *
   * @return utolsó tábla
   * */
  ITable getLastTable() {
    return _lastTable;
  }
}
TOP

Related Classes of kakuro.gui.editor.SkeletonPanel$MySkeleton

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.