/**
*
*/
package it.yup.ui;
import it.yup.util.MetaVector;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
/**
* @author luca
*
*/
public class UIAccordion extends UIPanel {
private Hashtable accordionItems = new Hashtable(5);
private int sepColor = 0xBBBBBB;
private int sepSize = 2;
private int labelColor = 0xAAAAAA;
private int labelGradientColor = -1;
/*
* true if at least one label must be opened
*/
private boolean oneOpen = false;
/*
* The index of the openedItem
*/
private UIItem openedItem = null;
/*
* The images used for submenus
*/
public Image closeImage = UIMenu.menuImage;
public Image openImage = UICanvas.getUIImage("/icons/downimage.png");
/*
* A vector that contains the labels
*/
private Vector itemLabels = new Vector();
private int labelSelectedColor = -1;
private int labelGradientSelectedColor = -1;
private class AccordionItem {
private UIVLayout wrappedItem;
private Vector subPanel;
AccordionItem(UIVLayout wrappedItem, Vector subPanel) {
this(wrappedItem);
this.wrappedItem = wrappedItem;
}
public AccordionItem(UIVLayout wrappedItem) {
this.wrappedItem = wrappedItem;
}
/*
* Return the label that contains the img in the item
*/
public UILabel getImgLabel() {
return (UILabel) ((UIHLayout) this.wrappedItem.layoutItems[0]).layoutItems[0];
}
}
/**
*
*/
public UIAccordion() {
super();
this.setItems(new MetaVector(5));
}
private void setSubPanel(UIItem item, Vector subPanel) {
AccordionItem ai = (AccordionItem) this.accordionItems.get(item);
ai.subPanel = subPanel;
Enumeration en = subPanel.elements();
while (en.hasMoreElements()) {
UIItem ithEl = (UIItem) en.nextElement();
ithEl.setFocusable(true);
ithEl.setContainer(this);
}
}
public int getHeight(Graphics g) {
// if maxHeight = -1 I want to behave like a UIPanel
// if maxHeight = o I want to behave like an object with a fixed size
if (maxHeight == 0) {
int newHeight = 0;
Enumeration en = this.getItems().elements();
while (en.hasMoreElements()) {
UIItem ithItem = (UIItem) en.nextElement();
newHeight += ithItem.getHeight(g);
}
// in case I am within an UIMenu this is mandatory
int maxTempHeight = (UICanvas.getInstance().getClipHeight() * 2) / 3;
if (newHeight > maxTempHeight) newHeight = maxTempHeight;
this.height = newHeight;
return this.height;
}
return super.getHeight(g);
}
public void addSpareItem(UIItem item) {
super.addItem(item);
}
public void insertSpareItem(UIItem it, int idx) {
super.insertItemAt(it, idx);
}
public void addItem(UIItem item) {
UIVLayout wrappedItem = wrapItem(item);
super.addItem(wrappedItem);
this.itemLabels.addElement(item);
this.accordionItems.put(item, new AccordionItem(wrappedItem));
}
public void addItem(UIItem item, Vector subPanel) {
this.addItem(item);
this.setSubPanel(item, subPanel);
}
public void insertItem(UIItem it, int idx) {
UIVLayout wrappedItem = wrapItem(it);
super.insertItemAt(wrappedItem, idx);
this.itemLabels.insertElementAt(it, idx);
this.accordionItems.put(it, new AccordionItem(wrappedItem));
}
public void insertItem(UIItem it, int idx, Vector subPanel) {
this.insertItem(it, idx);
this.setSubPanel(it, subPanel);
}
// public Vector getItems() {
// return super.getItems();
// Vector tempItems = new Vector(1 + this.subPanels.size());
// Enumeration en = this.subPanels.keys();
// while (en.hasMoreElements()) {
// tempItems.addElement(en.nextElement());
// }
// return tempItems;
// }
public int removeItem(UIItem it) {
AccordionItem ai = (AccordionItem) this.accordionItems.get(it);
if (this.openedItem == it) close(it);
this.accordionItems.remove(it);
this.itemLabels.removeElement(it);
if (this.openedItem == it) this.openedItem = null;
return super.removeItem(ai.wrappedItem);
}
/**
* Remove all elements
*/
public void removeAllItems() {
super.removeAllItems();
this.accordionItems.clear();
this.itemLabels.removeAllElements();
this.openedItem = null;
}
public int getPanelIndex(UIItem label, UIItem item) {
Vector v = getSubpanel(label);
return v.indexOf(item);
}
public Vector getSubpanel(UIItem label) {
AccordionItem accordionItem = ((AccordionItem) this.accordionItems
.get(label));
return accordionItem != null ? accordionItem.subPanel : null;
}
public int getPanelSize(UIItem label) {
Vector v = getSubpanel(label);
if (v == null) return 0;
return v.size();
}
public UIItem getPanelItem(UIItem label, int index) {
Vector v = getSubpanel(label);
return (UIItem) v.elementAt(index);
}
/*
* Returns true if a repaint is needed
*/
public void removePanelItem(UIItem label, UIItem item) {
Vector v = getSubpanel(label);
if (openedItem == label) {
int idx = this.getItems().indexOf(item);
if (selectedIdx >= idx && idx >= 0) selectedIdx--;
item.setSelected(false);
}
v.removeElement(item);
if (this.getScreen() != null) this.getScreen().removePaintedItem(item);
if (label == this.openedItem && v.size() == 0) this.close(label);
}
public void insertPanelItem(UIItem label, UIItem item, int idx) {
Vector v = getSubpanel(label);
v.insertElementAt(item, idx);
item.setContainer(this);
if (openedItem == label) {
if (selectedIdx >= this.getItems().indexOf(item)) selectedIdx++;
}
}
private UIVLayout wrapItem(UIItem item) {
int vlSize = (this.sepSize > 0 ? 2 : 1);
// I need a graphics to compute the height: i use mine otherwise
// the painted one
UIScreen currentScreen = this.getScreen();
currentScreen = (currentScreen == null ? (UIScreen) (UICanvas
.getInstance().getScreenList().elementAt(0)) : currentScreen);
Graphics g = currentScreen.getGraphics();
UIVLayout ivl = new UIVLayout(vlSize, item.getHeight(g)
+ (this.sepSize >= 0 ? sepSize : 0));
ivl.setGroup(false);
UIHLayout ihl = new UIHLayout(2);
ihl.setGroup(false);
ivl.insert(ihl, 0, item.getHeight(g), UILayout.CONSTRAINT_PIXELS);
if (sepSize > 0) {
UISeparator sep = new UISeparator(sepSize);
sep.setFg_color(sepColor);
ivl.insert(sep, 1, sepSize, UILayout.CONSTRAINT_PIXELS);
}
UILabel menuImage = new UILabel(closeImage, "");
ihl.insert(menuImage, 0,
closeImage != null ? closeImage.getWidth() : 0,
UILayout.CONSTRAINT_PIXELS);
item.setFocusable(true);
ihl.insert(item, 1, 100, UILayout.CONSTRAINT_PERCENTUAL);
setItemsColor(menuImage, item);
return ivl;
}
private void setItemsColor(UIItem menuImage, UIItem item) {
if (labelColor > 0) {
menuImage.setBg_color(labelColor);
item.setBg_color(labelColor);
}
if (labelGradientColor > 0) {
menuImage.setGradientColor(labelGradientColor);
item.setGradientColor(labelGradientColor);
}
if (labelSelectedColor > 0) {
menuImage.setSelectedColor(labelSelectedColor);
item.setSelectedColor(labelSelectedColor);
}
if (labelGradientSelectedColor > 0) {
menuImage.setGradientSelectedColor(labelGradientSelectedColor);
item.setGradientSelectedColor(labelGradientSelectedColor);
}
}
public UIItem getSelectedItem() {
// If I am inside an UIMenu i will not forward the key press to the
// selected item i will keep it for myself in order to open labels
UIItem superItem = super.getSelectedItem();
if (this.getContainer() instanceof UIMenu
&& this.getContainer() instanceof UIScreen == false) {
if (this.accordionItems.containsKey(superItem)) return this;
}
return superItem;
}
public boolean keyPressed(int key) {
int ga = UICanvas.getInstance().getGameAction(key);
if (ga == Canvas.FIRE) {
UIItem selItem = super.getSelectedItem();
// it is an item to (un)expand
if (this.accordionItems.containsKey(selItem)) {
if (this.selectedIdx >= 0
&& selectedIdx < this.getItems().size()
&& ((UIItem) this.getItems().elementAt(selectedIdx))
.keyPressed(key) == false) {
// this is needed since we cannot know if anything below has been
// repainted
clickLabel(selItem);
this.askRepaint();
return true;
}
return true;
} else {
return false;
}
}
boolean keepFocus = super.keyPressed(key);
// if (keepFocus == false && this.openedItem != null)
// this.setSelectedItem((UIItem) this.openedItem.getContainer());
return keepFocus;
}
public void clickLabel(UIItem selItem) {
boolean needOpen = (selItem != openedItem);
// if it closed open it otherwise close it
if (this.openedItem != null && (needOpen || oneOpen == false)) {
close(openedItem);
}
if (needOpen) {
open(selItem);
}
}
public void openLabel(UIItem selItem) {
boolean needOpen = (selItem != openedItem);
if (needOpen == false) return;
clickLabel(selItem);
}
public void closeLabel(UIItem selItem) {
boolean needClose = (selItem == openedItem);
if (needClose == false) return;
clickLabel(selItem);
}
public UIItem getOpenedLabel() {
return openedItem;
}
private void close(UIItem openedItem) {
AccordionItem ai = (AccordionItem) this.accordionItems.get(openedItem);
if (ai == null) return;
Vector oldPanel = ai.subPanel;
this.setSelectedIndex(-1);
int removeIndex = this.getItems().indexOf(oldPanel);
this.getItems().removeElement(oldPanel);
// must set dirty the items that are moved
invalidateItems(removeIndex);
ai.getImgLabel().setImg(this.closeImage);
this.setSelectedItem(ai.wrappedItem);
this.openedItem = null;
// so that the panel is "entirely redrawn" if needed
this.setFirstVisible(0);
}
private void invalidateItems(int removeIndex) {
this.dirty = true;
Enumeration en = this.getItems().elements();
int count = 0;
while (en.hasMoreElements()) {
UIItem ithItem = (UIItem) en.nextElement();
if (count >= removeIndex) {
ithItem.setDirty(true);
}
count++;
}
}
private void open(UIItem itemToOpen) {
AccordionItem ai = (AccordionItem) this.accordionItems.get(itemToOpen);
Vector newPanel = ai.subPanel;
if (newPanel.size() > 0) {
this.openedItem = itemToOpen;
this.setSelectedIndex(-1);
ai.getImgLabel().setImg(this.openImage);
int insertIndex = this.getItems().indexOf(ai.wrappedItem) + 1;
// must set dirty the items that are moved
this.getItems().insertElementAt(newPanel, insertIndex);
invalidateItems(insertIndex);
}
// even if the label is not opened i select it
this.setSelectedItem(ai.wrappedItem);
}
public void setBg_color(int bg_color) {
Enumeration en = this.accordionItems.elements();
while (en.hasMoreElements()) {
AccordionItem ithItem = (AccordionItem) en.nextElement();
Enumeration en2 = ithItem.subPanel.elements();
while (en2.hasMoreElements()) {
UIItem ithUIItem = (UIItem) en2.nextElement();
ithUIItem.setBg_color(bg_color);
}
}
}
public void setSepColor(int sepColor) {
this.sepColor = sepColor;
}
public int getSepColor() {
return sepColor;
}
public void setSepSize(int sepSize) {
this.sepSize = sepSize;
}
public int getSepSize() {
return sepSize;
}
public UIItem[] getItemLabels() {
UIItem[] labels = new UIItem[this.itemLabels.size()];
this.itemLabels.copyInto(labels);
return labels;
}
public Enumeration getSubPanelElements(UIItem item) {
// TODO Auto-generated method stub
Vector v = getSubpanel(item);
if (v == null) return null;
return ((Vector) v).elements();
}
/**
* @param oneOpen the oneOpen to set
*/
public void setOneOpen(boolean oneOpen) {
this.oneOpen = oneOpen;
}
/**
* @return the oneOpen
*/
public boolean isOneOpen() {
return oneOpen;
}
public void clearPanel(UILabel label) {
if (openedItem == label) {
this.getSelectedItem().setSelected(false);
this.close(label);
}
Vector v = this.getSubpanel(label);
if (this.getScreen() != null) {
UIScreen cs = this.getScreen();
Enumeration en = v.elements();
while (en.hasMoreElements()) {
Object object = (Object) en.nextElement();
cs.removePaintedItem((UIItem) object);
}
}
v.removeAllElements();
}
public void move(int firstIndex, int secondIndex) {
try {
UIItem oldSelectedItem = selectedIdx >= 0 ? (UIItem) this
.getItems().elementAt(selectedIdx) : null;
oldSelectedItem.setSelected(false);
UIItem oldOpenedItem = openedItem;
if (openedItem != null) {
this.close(openedItem);
}
UIItem firstItem = (UIItem) this.itemLabels.elementAt(firstIndex);
this.itemLabels.removeElement(firstItem);
this.itemLabels.insertElementAt(firstItem, secondIndex);
//UIItem secondItem = (UIItem) this.getItems().elementAt(secondIndex);
firstItem = (UIItem) this.getItems().elementAt(firstIndex);
this.getItems().removeElement(firstItem);
this.getItems().insertElementAt(firstItem, secondIndex);
if (oldOpenedItem != null) {
this.open(oldOpenedItem);
}
this.setSelectedItem(firstItem);
} catch (Exception e) {
// #mdebug
//@ System.out.println("in swapping elements");
//@ e.printStackTrace();
// #enddebug
}
}
public void swap(int firstIndex, int secondIndex) {
try {
if (firstIndex > secondIndex) {
int tempIndex = firstIndex;
firstIndex = secondIndex;
secondIndex = tempIndex;
}
UIItem oldSelectedItem = selectedIdx >= 0 ? (UIItem) this
.getItems().elementAt(selectedIdx) : null;
UIItem oldOpenedItem = openedItem;
if (openedItem != null) {
this.close(openedItem);
}
UIItem secondItem = (UIItem) this.itemLabels.elementAt(secondIndex);
UIItem firstItem = (UIItem) this.itemLabels.elementAt(firstIndex);
this.itemLabels.removeElement(secondItem);
this.itemLabels.insertElementAt(secondItem, firstIndex);
this.itemLabels.removeElement(firstItem);
this.itemLabels.insertElementAt(firstItem, secondIndex);
secondItem = (UIItem) this.getItems().elementAt(secondIndex);
firstItem = (UIItem) this.getItems().elementAt(firstIndex);
this.getItems().removeElement(secondItem);
this.getItems().insertElementAt(secondItem, firstIndex);
this.getItems().removeElement(firstItem);
this.getItems().insertElementAt(firstItem, secondIndex);
if (oldOpenedItem != null) {
this.open(oldOpenedItem);
}
if ((oldSelectedItem == firstItem || oldSelectedItem == secondItem)
&& this.getItems().contains(oldSelectedItem)) this
.setSelectedItem(oldSelectedItem);
} catch (Exception e) {
// #mdebug
//@ System.out.println("in swapping elements");
//@ e.printStackTrace();
// #enddebug
}
}
public int getLabelGradientColor() {
return labelGradientColor;
}
public int getLabelColor() {
return labelColor;
}
public void setLabelColor(int labelColor) {
this.labelColor = labelColor;
updateItemsColor();
}
public void setLabelGradientColor(int labelGradientColor) {
this.labelGradientColor = labelGradientColor;
updateItemsColor();
}
public void setLabelGradientSelectedColor(int labelGradientSelectedColor) {
this.labelGradientSelectedColor = labelGradientSelectedColor;
updateItemsColor();
}
public void setLabelSelectedColor(int labelSelectedColor) {
this.labelSelectedColor = labelSelectedColor;
updateItemsColor();
}
private void updateItemsColor() {
Enumeration en = accordionItems.elements();
while (en.hasMoreElements()) {
AccordionItem ithItem = (AccordionItem) en.nextElement();
UIVLayout ivl = ithItem.wrappedItem;
UIHLayout ihl = (UIHLayout) ivl.layoutItems[0];
setItemsColor(ihl.layoutItems[0], ihl.layoutItems[1]);
}
}
}