package view;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.ListModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import engine.Board;
import engine.SchemeSet;
/**
* This class implements ListModel to provide
* icons (ImageIcon) from schemes.
*/
public class SchemeSetView implements ListModel {
private ArrayList<ListDataListener> listenersListData;
private SchemeSet schemeSet = null;
private int iconSize = 0;
private boolean background = false;
private boolean solvingInfo = false;
private ImageIcon[] cache = null;
// *****************************************************************
// Management
/**
* Constructs a new view with given parameters.
*
* @param iconSize - size of the icons
* @param background - if the icons have board's background
* @param solvingInfo - if the info about moves and solved state are shown
*/
public SchemeSetView(int iconSize,boolean background,boolean solvingInfo) {
this.iconSize = iconSize;
this.background = background;
this.solvingInfo = solvingInfo;
listenersListData = new ArrayList<ListDataListener>(1);
}
/**
* Sets a new scheme set as icons source and it's parameters.
*
* @param schemeSet - a new scheme set
*/
public void setSchemeSet(SchemeSet schemeSet) {
this.schemeSet = schemeSet;
updateCache();
}
/**
* Updates all icons in cache so they will be recreated.
*/
public void updateCache() {
ListDataEvent event;
if (schemeSet != null) {
cache = new ImageIcon[schemeSet.size()];
event = new ListDataEvent(
this,ListDataEvent.CONTENTS_CHANGED,0,schemeSet.size());
} else {
cache = new ImageIcon[0];
event = new ListDataEvent(
this,ListDataEvent.CONTENTS_CHANGED,-1,-1);
}
for (ListDataListener listener: listenersListData) {
listener.contentsChanged(event);
}
}
/**
* Updates specified icon in cache so it will be recreated.
*
* @param index - index of the icon to recreate
*/
public void updateCache(int index) {
if (index >= 0 && index < cache.length) {
cache[index] = null;
ListDataEvent event = new ListDataEvent(
this,ListDataEvent.CONTENTS_CHANGED,index,index);
for (ListDataListener listener: listenersListData) {
listener.contentsChanged(event);
}
}
}
@Override
public int getSize() {
if (schemeSet != null)
return schemeSet.size(); else
return 0;
}
@Override
public synchronized void addListDataListener(ListDataListener l) {
listenersListData.add(l);
}
@Override
public synchronized void removeListDataListener(ListDataListener l) {
listenersListData.remove(l);
}
// *****************************************************************
// Creating icons
private static final Color COLOR_SOLVED = new Color(0,192,0,128);
private static final Color COLOR_NOT_SOLVED = new Color(0,0,255,128);
@Override
public Object getElementAt(int index) {
if (index >= 0 && index < cache.length) {
if (cache[index] == null) {
// Icon construction
Board board = schemeSet.get(index).start;
int boardSize;
if (board.width >= board.height) boardSize = board.width+2; else boardSize = board.height+2;
int fieldSize = (iconSize+boardSize-1)/boardSize;
BufferedImage imgBoard = new BufferedImage(boardSize*fieldSize,boardSize*fieldSize,BufferedImage.TYPE_INT_ARGB);
Graphics2D gBoard = imgBoard.createGraphics();
int backgroundIndex = -1;
if (background) backgroundIndex = index;
BoardPainter.drawBoard(gBoard,imgBoard.getWidth(),imgBoard.getHeight(),
backgroundIndex,board,
board.width*fieldSize/2,board.height*fieldSize/2,fieldSize,
0.0,0.0,-1,-1,-1,-1);
gBoard.dispose();
BufferedImage imgIcon = ImageManager.getScaledImage(
imgBoard,iconSize,iconSize);
if (solvingInfo) {
Graphics2D gIcon = imgIcon.createGraphics();
boolean solved = schemeSet.get(index).isSolved();
gIcon.setFont(new Font("Helvetica",Font.BOLD,18));
gIcon.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
gIcon.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
int movesCount = schemeSet.get(index).moves.size();
String movesInfo = Integer.toString(movesCount) + " ruch";
if (movesCount != 1)
if (movesCount%100/10 != 1 && movesCount%10 >= 2 && movesCount%10 <= 4)
movesInfo += "y"; else movesInfo += "ów";
AffineTransform transform = gIcon.getTransform();
transform.translate(
(double)(imgIcon.getWidth()-gIcon.getFontMetrics().stringWidth(movesInfo))/2,
(double)imgIcon.getHeight()-4);
gIcon.setTransform(transform);
Shape movesInfoOutline = new TextLayout(movesInfo,gIcon.getFont(),gIcon.getFontRenderContext()).getOutline(null);
gIcon.setColor(Color.WHITE);
gIcon.fill(movesInfoOutline);
if (solved)
gIcon.setColor(COLOR_SOLVED); else
gIcon.setColor(COLOR_NOT_SOLVED);
gIcon.draw(movesInfoOutline);
gIcon.dispose();
}
cache[index] = new ImageIcon(imgIcon);
}
return cache[index];
} else return null;
}
}