/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``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 BetaSteward_at_googlemail.com 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.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.client.deckeditor.collection.viewer;
import mage.cards.Card;
import mage.cards.CardDimensions;
import mage.cards.MageCard;
import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.cards.repository.ExpansionRepository;
import mage.client.MageFrame;
import mage.client.cards.BigCard;
import mage.client.components.HoverButton;
import mage.client.plugins.impl.Plugins;
import mage.client.util.Config;
import mage.client.util.ImageHelper;
import mage.client.util.NaturalOrderCardNumberComparator;
import mage.client.util.audio.AudioManager;
import mage.client.util.sets.ConstructedFormats;
import mage.components.ImagePanel;
import mage.components.ImagePanelStyle;
import mage.constants.Rarity;
import mage.view.CardView;
import org.apache.log4j.Logger;
import org.mage.card.arcane.GlowText;
import org.mage.card.arcane.ManaSymbols;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import mage.client.util.CardsViewUtil;
import mage.game.command.Emblem;
import mage.game.permanent.PermanentToken;
import mage.game.permanent.token.Token;
import mage.view.EmblemView;
import mage.view.PermanentView;
import org.mage.plugins.card.images.CardDownloadData;
import static org.mage.plugins.card.images.DownloadPictures.getTokenCardUrls;
/**
* Mage book with cards and page flipping.
*
* @author nantuko
*/
public class MageBook extends JComponent {
private static final long serialVersionUID = 1L;
public static final String LAYOUT_3x3 = "small";
public static final String LAYOUT_4x4 = "big";
public MageBook(BigCard bigCard) {
super();
this.bigCard = bigCard;
this.setsToDisplay = ConstructedFormats.getSetsByFormat(ConstructedFormats.getDefault());
boolean selected3x3 = MageFrame.getPreferences().get(CollectionViewerPanel.LAYOYT_CONFIG_KEY, MageBook.LAYOUT_3x3).equals(MageBook.LAYOUT_3x3);
this.conf = selected3x3 ? new _3x3Configuration() : new _4x4Configuration();
initComponents();
}
private void initComponents() {
setOpaque(false);
setSize(conf.WIDTH, conf.HEIGHT);
setPreferredSize(new Dimension(conf.WIDTH, conf.HEIGHT));
setMinimumSize(new Dimension(conf.WIDTH, conf.HEIGHT));
//setBorder(BorderFactory.createLineBorder(Color.green));
jPanelLeft = getImagePanel(LEFT_PANEL_IMAGE_PATH, ImagePanelStyle.TILED);
jPanelLeft.setPreferredSize(new Dimension(LEFT_RIGHT_PAGES_WIDTH, 0));
jPanelLeft.setLayout(null);
jPanelCenter = getImagePanel(CENTER_PANEL_IMAGE_PATH, ImagePanelStyle.SCALED);
jPanelCenter.setLayout(new BorderLayout());
jPanelRight = getImagePanel(RIGHT_PANEL_IMAGE_PATH, ImagePanelStyle.TILED);
jPanelRight.setPreferredSize(new Dimension(LEFT_RIGHT_PAGES_WIDTH, 0));
jPanelRight.setLayout(null);
jLayeredPane = new JLayeredPane();
jPanelCenter.add(jLayeredPane, BorderLayout.CENTER);
Image image = ImageHelper.loadImage(LEFT_PAGE_BUTTON_IMAGE_PATH);
pageLeft = new HoverButton(null, image, image, image, new Rectangle(64, 64));
pageLeft.setBounds(0, 0, 64, 64);
pageLeft.setVisible(false);
pageLeft.setObserver(() -> {
currentPage--;
if (currentPage == 0) {
pageLeft.setVisible(false);
}
pageRight.setVisible(true);
AudioManager.playPrevPage();
showCardsOrTokens();
});
image = ImageHelper.loadImage(RIGHT_PAGE_BUTTON_IMAGE_PATH);
pageRight = new HoverButton(null, image, image, image, new Rectangle(64, 64));
pageRight.setBounds(conf.WIDTH - 2 * LEFT_RIGHT_PAGES_WIDTH - 64, 0, 64, 64);
pageRight.setVisible(false);
pageRight.setObserver(() -> {
currentPage++;
pageLeft.setVisible(true);
pageRight.setVisible(false);
AudioManager.playNextPage();
showCardsOrTokens();
});
addSetTabs();
setLayout(new BorderLayout());
add(jPanelLeft, BorderLayout.LINE_START);
add(jPanelCenter, BorderLayout.CENTER);
add(jPanelRight, BorderLayout.LINE_END);
cardDimensions = new CardDimensions(0.45d);
}
private void addLeftRightPageButtons() {
jLayeredPane.add(pageLeft, JLayeredPane.DEFAULT_LAYER, 0);
jLayeredPane.add(pageRight, JLayeredPane.DEFAULT_LAYER, 1);
}
private void addSetTabs() {
jPanelLeft.removeAll();
jPanelRight.removeAll();
tabs.clear();
Image image = ImageHelper.loadImage(LEFT_TAB_IMAGE_PATH);
Image imageRight = ImageHelper.loadImage(RIGHT_TAB_IMAGE_PATH);
int y = 0;
int dy = 0;
if (this.setsToDisplay.size() > 1) {
dy = (conf.HEIGHT - 120) / (this.setsToDisplay.size() - 1) + 1;
}
int count = 0;
JPanel currentPanel = jPanelLeft;
HoverButton currentTab = null;
for (String set : this.setsToDisplay) {
HoverButton tab = new HoverButton(null, image, image, image, new Rectangle(39, 120));
Image setImage = ManaSymbols.getSetSymbolImage(set);
if (setImage != null) {
tab.setOverlayImage(setImage);
} else {
System.out.println("Couldn't find: " + "/plugins/images/sets/" + set + "-C.jpg");
}
tab.setSet(set);
tab.setBounds(0, y, 39, 120);
final String _set = set;
final int _index = count;
tab.setObserver(() -> {
if (!currentSet.equals(_set) || currentPage != 0 || stateChanged) {
AudioManager.playAnotherTab();
synchronized (MageBook.this) {
selectedTab = _index;
}
currentPage = 0;
currentSet = _set;
pageLeft.setVisible(false);
pageRight.setVisible(false);
addSetTabs();
showCardsOrTokens();
}
});
tabs.add(tab);
currentPanel.add(tab, JLayeredPane.DEFAULT_LAYER + count++, 0);
y += dy;
if (set.equals(currentSet)) {
currentPanel = jPanelRight;
image = imageRight;
currentTab = tab;
selectedTab = count - 1;
}
}
jPanelLeft.revalidate();
jPanelLeft.repaint();
jPanelRight.revalidate();
jPanelRight.repaint();
if (currentTab != null) {
currentTab.drawSet();
currentTab.repaint();
}
}
private void showCardsOrTokens() {
stateChanged = false;
if (showCardsOrTokens) {
showCards();
} else {
int numTokens = showTokens();
showEmblems(numTokens);
}
}
public void showCards() {
jLayeredPane.removeAll();
addLeftRightPageButtons();
List<CardInfo> cards = getCards(currentPage, currentSet);
int size = cards.size();
Rectangle rectangle = new Rectangle();
rectangle.translate(OFFSET_X, OFFSET_Y);
for (int i = 0; i < Math.min(conf.CARDS_PER_PAGE / 2, size); i++) {
Card card = cards.get(i).getMockCard();
addCard(new CardView(card), bigCard, null, rectangle);
rectangle = CardPosition.translatePosition(i, rectangle, conf);
}
// calculate the x offset of the second (right) page
int second_page_x = (conf.WIDTH - 2 * LEFT_RIGHT_PAGES_WIDTH)
- (cardDimensions.frameWidth + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X;
rectangle.setLocation(second_page_x, OFFSET_Y);
for (int i = conf.CARDS_PER_PAGE / 2; i < Math.min(conf.CARDS_PER_PAGE, size); i++) {
Card card = cards.get(i).getMockCard();
addCard(new CardView(card), bigCard, null, rectangle);
rectangle = CardPosition.translatePosition(i - conf.CARDS_PER_PAGE / 2, rectangle, conf);
}
jLayeredPane.repaint();
}
public int showTokens() {
jLayeredPane.removeAll();
addLeftRightPageButtons();
List<Token> tokens = getTokens(currentPage, currentSet);
int size = tokens.size();
if (tokens != null && tokens.size() > 0) {
Rectangle rectangle = new Rectangle();
rectangle.translate(OFFSET_X, OFFSET_Y);
for (int i = 0; i < Math.min(conf.CARDS_PER_PAGE / 2, size); i++) {
Token token = tokens.get(i);
addToken(token, bigCard, null, rectangle);
rectangle = CardPosition.translatePosition(i, rectangle, conf);
}
// calculate the x offset of the second (right) page
int second_page_x = (conf.WIDTH - 2 * LEFT_RIGHT_PAGES_WIDTH)
- (cardDimensions.frameWidth + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X;
rectangle.setLocation(second_page_x, OFFSET_Y);
for (int i = conf.CARDS_PER_PAGE / 2; i < Math.min(conf.CARDS_PER_PAGE, size); i++) {
Token token = tokens.get(i);
addToken(token, bigCard, null, rectangle);
rectangle = CardPosition.translatePosition(i - conf.CARDS_PER_PAGE / 2, rectangle, conf);
}
jLayeredPane.repaint();
}
return tokens.size();
}
public void showEmblems(int numTokens) {
List<Emblem> emblems = getEmblems(currentPage, currentSet, numTokens);
int size = emblems.size();
System.out.println ("Size of origins in " + currentSet + " = " + emblems.size());
if (emblems != null && emblems.size() > 0) {
Rectangle rectangle = new Rectangle();
rectangle.translate(OFFSET_X, OFFSET_Y);
// calculate the x offset of the second (right) page
int second_page_x = (conf.WIDTH - 2 * LEFT_RIGHT_PAGES_WIDTH)
- (cardDimensions.frameWidth + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X;
// Already have numTokens tokens presented. Appending the emblems to the end of these.
numTokens = numTokens % conf.CARDS_PER_PAGE;
if (numTokens < conf.CARDS_PER_PAGE / 2) {
for (int z = 0; z < numTokens && z < conf.CARDS_PER_PAGE / 2; z++) {
rectangle = CardPosition.translatePosition(z, rectangle, conf);
}
} else {
rectangle.setLocation(second_page_x, OFFSET_Y);
for (int z = 0; z < numTokens - conf.CARDS_PER_PAGE / 2; z++) {
rectangle = CardPosition.translatePosition(z, rectangle, conf);
}
}
int lastI = 0;
for (int i = 0; i < size && i + numTokens < conf.CARDS_PER_PAGE / 2; i++) {
Emblem emblem = emblems.get(i);
addEmblem(emblem, bigCard, null, rectangle);
rectangle = CardPosition.translatePosition(i + numTokens, rectangle, conf);
lastI++;
}
if (size + numTokens > conf.CARDS_PER_PAGE / 2) {
for (int i = lastI; i < size && i + numTokens < conf.CARDS_PER_PAGE; i++) {
Emblem emblem = emblems.get(i);
addEmblem(emblem, bigCard, null, rectangle);
rectangle = CardPosition.translatePosition(i + numTokens - conf.CARDS_PER_PAGE / 2, rectangle, conf);
}
}
jLayeredPane.repaint();
}
}
private void addCard(CardView card, BigCard bigCard, UUID gameId, Rectangle rectangle) {
if (cardDimension == null) {
cardDimension = new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight);
}
final MageCard cardImg = Plugins.instance.getMageCard(card, bigCard, cardDimension, gameId, true, true);
cardImg.setBounds(rectangle);
jLayeredPane.add(cardImg, JLayeredPane.DEFAULT_LAYER, 10);
cardImg.update(card);
cardImg.setCardBounds(rectangle.x, rectangle.y, cardDimensions.frameWidth, cardDimensions.frameHeight);
boolean implemented = card.getRarity() != Rarity.NA;
GlowText label = new GlowText();
label.setGlow(implemented ? Color.green : NOT_IMPLEMENTED, 12, 0.0f);
label.setText(implemented ? "Implemented" : "Not implemented");
int dx = implemented ? 15 : 5;
label.setBounds(rectangle.x + dx, rectangle.y + cardDimensions.frameHeight + 7, 110, 30);
jLayeredPane.add(label);
}
private void addToken(Token token, BigCard bigCard, UUID gameId, Rectangle rectangle) {
if (cardDimension == null) {
cardDimension = new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight);
}
PermanentToken newToken = new PermanentToken(token, null, token.getOriginalExpansionSetCode(), null);
PermanentView theToken = new PermanentView(newToken, null, null, null);
theToken.setInViewerOnly(true);
final MageCard cardImg = Plugins.instance.getMagePermanent(theToken, bigCard, cardDimension, gameId, true);
cardImg.setBounds(rectangle);
jLayeredPane.add(cardImg, JLayeredPane.DEFAULT_LAYER, 10);
cardImg.update(theToken);
cardImg.setCardBounds(rectangle.x, rectangle.y, cardDimensions.frameWidth, cardDimensions.frameHeight);
}
private void addEmblem(Emblem emblem, BigCard bigCard, UUID gameId, Rectangle rectangle) {
CardView cardView = new CardView(new EmblemView(emblem));
addCard(cardView, bigCard, gameId, rectangle);
}
private List<CardInfo> getCards(int page, String set) {
CardCriteria criteria = new CardCriteria();
criteria.setCodes(set);
List<CardInfo> cards = CardRepository.instance.findCards(criteria);
cards.sort(new NaturalOrderCardNumberComparator());
int start = page * conf.CARDS_PER_PAGE;
int end = page * conf.CARDS_PER_PAGE + conf.CARDS_PER_PAGE;
if (end > cards.size()) {
end = cards.size();
}
if (cards.size() > end) {
pageRight.setVisible(true);
}
return cards.subList(start, end);
}
private List<Token> getTokens(int page, String set) {
ArrayList<CardDownloadData> allTokens = getTokenCardUrls();
ArrayList<Token> tokens = new ArrayList<>();
for (CardDownloadData token : allTokens) {
if (token.getSet().equals(set)) {
try {
String className = token.getName();
className = className.replaceAll("[^a-zA-Z0-9]", "");
className = "mage.game.permanent.token." + className + "Token";
if (token.getTokenClassName() != null && token.getTokenClassName().length() > 0) {
if (token.getTokenClassName().toLowerCase().matches(".*token.*")) {
className = token.getTokenClassName();
className = "mage.game.permanent.token." + className;
} else if (token.getTokenClassName().toLowerCase().matches(".*emblem.*")) {
continue;
}
}
Class<?> c = Class.forName(className);
Constructor<?> cons = c.getConstructor();
Object newToken = cons.newInstance();
if (newToken != null && newToken instanceof mage.game.permanent.token.Token) {
((Token) newToken).setExpansionSetCodeForImage(set);
((Token) newToken).setOriginalExpansionSetCode(set);
tokens.add((Token) newToken);
}
} catch (ClassNotFoundException ex) {
// Swallow exception
} catch (NoSuchMethodException ex) {
// Swallow exception
} catch (SecurityException ex) {
// Swallow exception
} catch (InstantiationException ex) {
// Swallow exception
} catch (IllegalAccessException ex) {
// Swallow exception
} catch (IllegalArgumentException ex) {
// Swallow exception
} catch (InvocationTargetException ex) {
// Swallow exception
}
}
}
int start = page * conf.CARDS_PER_PAGE;
int end = page * conf.CARDS_PER_PAGE + conf.CARDS_PER_PAGE;
if (end > tokens.size()) {
end = tokens.size();
}
if (tokens.size() > end) {
pageRight.setVisible(true);
}
return tokens.subList(start, end);
}
private List<Emblem> getEmblems(int page, String set, int numTokens) {
ArrayList<CardDownloadData> allEmblems = getTokenCardUrls();
ArrayList<Emblem> emblems = new ArrayList<>();
for (CardDownloadData emblem : allEmblems) {
if (emblem.getSet().equals(set)) {
try {
String className = emblem.getName();
if (emblem.getTokenClassName() != null && emblem.getTokenClassName().length() > 0) {
if (emblem.getTokenClassName().toLowerCase().matches(".*emblem.*")) {
className = emblem.getTokenClassName();
className = "mage.game.command.emblems." + className;
}
} else {
continue;
}
Class<?> c = Class.forName(className);
Constructor<?> cons = c.getConstructor();
Object newEmblem = cons.newInstance();
if (newEmblem != null && newEmblem instanceof mage.game.command.Emblem) {
((Emblem) newEmblem).setExpansionSetCodeForImage(set);
emblems.add((Emblem) newEmblem);
}
} catch (ClassNotFoundException ex) {
// Swallow exception
} catch (NoSuchMethodException ex) {
// Swallow exception
} catch (SecurityException ex) {
// Swallow exception
} catch (InstantiationException ex) {
// Swallow exception
} catch (IllegalAccessException ex) {
// Swallow exception
} catch (IllegalArgumentException ex) {
// Swallow exception
} catch (InvocationTargetException ex) {
// Swallow exception
}
}
}
int start = 0;
int end = emblems.size();
if ((page + 1) * conf.CARDS_PER_PAGE < numTokens + emblems.size()) {
end = (page + 1) * conf.CARDS_PER_PAGE - numTokens;
pageRight.setVisible(true);
}
if (emblems.size() > conf.CARDS_PER_PAGE) {
pageLeft.setVisible(true);
pageRight.setVisible(true);
}
return emblems.subList(start, end);
}
private ImagePanel getImagePanel(String filename, ImagePanelStyle type) {
try {
InputStream is = this.getClass().getResourceAsStream(filename);
if (is == null) {
throw new FileNotFoundException("Couldn't find " + filename + " in resources.");
}
BufferedImage background = ImageIO.read(is);
if (background == null) {
throw new FileNotFoundException("Couldn't find " + filename + " in resources.");
}
return new ImagePanel(background, type);
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
public void updateDispayedSets(String format) {
this.setsToDisplay = ConstructedFormats.getSetsByFormat(format);
if (this.setsToDisplay.isEmpty()) {
// display all
this.setsToDisplay = ExpansionRepository.instance.getSetCodes();
}
addSetTabs();
tabs.get(0).execute();
}
public void next() {
synchronized (this) {
selectedTab++;
if (selectedTab >= tabs.size()) {
selectedTab = 0;
}
tabs.get(selectedTab).execute();
}
}
public void prev() {
synchronized (this) {
selectedTab--;
if (selectedTab < 0) {
selectedTab = tabs.size() - 1;
}
tabs.get(selectedTab).execute();
}
}
public void cardsOrTokens(boolean showCards) {
synchronized (this) {
selectedTab = 0;
showCardsOrTokens = !showCardsOrTokens;
stateChanged = true;
tabs.get(selectedTab).execute();
}
}
public void updateSize(String size) {
switch (size) {
case LAYOUT_3x3:
this.conf = new _3x3Configuration();
break;
case LAYOUT_4x4:
this.conf = new _4x4Configuration();
break;
default:
return;
}
currentPage = 0;
pageLeft.setVisible(false);
setSize(conf.WIDTH, conf.HEIGHT);
setPreferredSize(new Dimension(conf.WIDTH, conf.HEIGHT));
setMinimumSize(new Dimension(conf.WIDTH, conf.HEIGHT));
pageRight.setBounds(conf.WIDTH - 2 * LEFT_RIGHT_PAGES_WIDTH - 64, 0, 64, 64);
addSetTabs();
showCards();
}
/**
* Defines the position of the next card on the mage book
*/
private static final class CardPosition {
private CardPosition() {
}
public static Rectangle translatePosition(int index, Rectangle r, Configuration conf) {
Rectangle rect = new Rectangle(r);
rect.translate((cardDimensions.frameWidth + GAP_X) * conf.dx[index],
(cardDimensions.frameHeight + GAP_Y) * conf.dy[index]);
return rect;
}
public static final int GAP_X = 17;
public static final int GAP_Y = 45;
}
abstract static class Configuration {
public int CARDS_PER_PAGE;
public int CARD_ROWS;
public int CARD_COLUMNS;
public int WIDTH;
public int HEIGHT;
public int[] dx;
public int[] dy;
}
class _3x3Configuration extends Configuration {
_3x3Configuration() {
this.WIDTH = 950;
this.HEIGHT = 650;
CARD_ROWS = 3;
CARD_COLUMNS = 3;
this.CARDS_PER_PAGE = 18;
this.dx = new int[]{1, 1, -2, 1, 1, -2, 1, 1, 2, 1, -2, 1, 1, -2, 1, 1};
this.dy = new int[]{0, 0, 1, 0, 0, 1, 0, 0, -2, 0, 1, 0, 0, 1, 0, 0};
}
}
class _4x4Configuration extends Configuration {
_4x4Configuration() {
this.WIDTH = 1250;
this.HEIGHT = 850;
CARD_ROWS = 4;
CARD_COLUMNS = 4;
this.CARDS_PER_PAGE = 32;
this.dx = new int[]{1, 1, 1, -3, 1, 1, 1, -3, 1, 1, 1, -3, 1, 1, 1, -3};
this.dy = new int[]{0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1};
}
}
private JPanel jPanelLeft;
private ImagePanel jPanelCenter;
private JPanel jPanelRight;
private JLayeredPane jLayeredPane;
private final BigCard bigCard;
private HoverButton pageLeft;
private HoverButton pageRight;
private int currentPage = 0;
private String currentSet = "RTR";
private static CardDimensions cardDimensions = new CardDimensions(1.2d);
private static final Logger log = Logger.getLogger(MageBook.class);
private Dimension cardDimension;
private java.util.List<String> setsToDisplay = new ArrayList<>();
private final java.util.List<HoverButton> tabs = new ArrayList<>();
private int selectedTab;
private boolean showCardsOrTokens = true;
private boolean stateChanged = false;
private static final String CENTER_PANEL_IMAGE_PATH = "/book_bg.jpg";
private static final String RIGHT_PANEL_IMAGE_PATH = "/book_right.jpg";
private static final String LEFT_PANEL_IMAGE_PATH = "/book_left.jpg";
private static final String LEFT_PAGE_BUTTON_IMAGE_PATH = "/book_pager_left.png";
private static final String RIGHT_PAGE_BUTTON_IMAGE_PATH = "/book_pager_right.png";
private static final String LEFT_TAB_IMAGE_PATH = "/tab_left.png";
private static final String RIGHT_TAB_IMAGE_PATH = "/tab_right.png";
private static final int OFFSET_X = 25;
private static final int OFFSET_Y = 20;
private static final int LEFT_RIGHT_PAGES_WIDTH = 40;
private static final Color NOT_IMPLEMENTED = new Color(220, 220, 220, 150);
private Configuration conf;
}