/*
This file is part of leafdigital leafChat.
leafChat 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 3 of the License, or
(at your option) any later version.
leafChat is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with leafChat. If not, see <http://www.gnu.org/licenses/>.
Copyright 2012 Samuel Marshall.
*/
package com.leafdigital.ui;
import java.awt.*;
import java.util.*;
import java.util.List;
import javax.swing.JComponent;
import util.PlatformUtils;
import com.leafdigital.ui.api.*;
import leafchat.core.api.BugException;
/**
* Implements ButtonPanel
*/
public class ButtonPanelImp extends JComponent
{
/** Spacing between buttons */
private int spacing=0;
/** Border at edge of grid */
private int border=0;
/** Held components */
private InternalWidget[] slots=new InternalWidget[3];
/** Constructor */
ButtonPanelImp()
{
setLayout(null);
}
@Override
public void setBounds(int x, int y, int width, int height)
{
super.setBounds(x, y, width, height);
updateLayout();
}
@Override
public Dimension getPreferredSize()
{
InternalWidget iw=(InternalWidget)externalInterface;
int width=iw.getPreferredWidth();
return new Dimension(width,iw.getPreferredHeight(width));
}
/** Move all components to their correct place in new layout */
private void updateLayout()
{
UISingleton.checkSwing();
// Align buttons right in the available space
int x=getWidth()-border-((InternalWidget)externalInterface).getPreferredWidth();
int[] order= getButtonOrder();
for(int i=0;i<order.length;i++)
{
if(order[i]==-1)
{
x+=2*spacing;
continue;
}
InternalWidget iw=slots[order[i]];
if(iw==null) continue;
int thisWidth=iw.getPreferredWidth();
iw.getJComponent().setBounds(x,border,thisWidth,iw.getPreferredHeight(thisWidth));
x+=thisWidth+spacing;
}
repaint();
}
/**
* Obtains the necessary order for buttons (array of the YES/NO/CANCEL
* constants) depending on platform.
* @return Array of those three constants in the order to display buttons
*/
private int[] getButtonOrder()
{
return PlatformUtils.isWindows()
? new int[] {ButtonPanel.YES,ButtonPanel.NO,ButtonPanel.CANCEL}
: new int[] {ButtonPanel.NO,-1,ButtonPanel.CANCEL,ButtonPanel.YES};
}
/**
* @return Interface giving limited public access
*/
ButtonPanel getInterface()
{
return externalInterface;
}
/** Interface available to public */
private ButtonPanel externalInterface=new ButtonPanelInterface();
/** Interface available to public */
class ButtonPanelInterface extends BasicWidget implements ButtonPanel,InternalWidget
{
@Override
public int getContentType() { return CONTENT_NAMEDSLOTS; }
@Override
public void set(final int iSlot,Widget w)
{
final InternalWidget iw=(InternalWidget)w;
iw.setParent(this);
UISingleton.runInSwing(new Runnable()
{
@Override
public void run()
{
if(slots[iSlot]!=null)
{
ButtonPanelImp.this.remove(slots[iSlot].getJComponent());
slots[iSlot]=null;
}
if(iw!=null)
{
add(iw.getJComponent());
slots[iSlot]=iw;
}
updateLayout();
}
});
}
@Override
public Widget[] getWidgets()
{
List<Widget> all = new LinkedList<Widget>();
for(InternalWidget w : slots)
{
if(w != null)
{
all.add(w);
}
}
return all.toArray(new Widget[all.size()]);
}
@Override
public void remove(Widget w)
{
final InternalWidget iw=(InternalWidget)w;
UISingleton.runInSwing(new Runnable()
{
@Override
public void run()
{
for(int i=0;i<slots.length;i++)
{
if(slots[i]==iw)
{
slots[i]=null;
ButtonPanelImp.this.remove(iw.getJComponent());
}
}
updateLayout();
}
});
}
@Override
public void removeAll()
{
UISingleton.runInSwing(new Runnable()
{
@Override
public void run()
{
for(int i=0;i<slots.length;i++)
{
if(slots[i]!=null)
{
InternalWidget iw=slots[i];
slots[i]=null;
ButtonPanelImp.this.remove(iw.getJComponent());
}
}
updateLayout();
}
});
}
@Override
public JComponent getJComponent()
{
return ButtonPanelImp.this;
}
@Override
public int getPreferredWidth()
{
int width=0;
int[] order=getButtonOrder();
boolean somethingYet=false;
for(int i=0;i<order.length;i++)
{
if(order[i]==-1)
{
if(somethingYet) // Only do a spacer after something...
{
boolean somethingAfter=false;
for(int j=i+1;j<order.length;j++)
{
if(slots[order[j]]!=null)
{
somethingAfter=true;
break;
}
}
if(somethingAfter) // And before something
width+=spacing;
}
}
else
{
InternalWidget iw=slots[order[i]];
if(iw!=null)
{
if(i!=0) width+=spacing;
width+=iw.getPreferredWidth();
}
}
}
return width+2*border;
}
@Override
public int getPreferredHeight(int width)
{
if(width==0) return 0;
int height=0;
for(int i=0;i<slots.length;i++)
{
if(slots[i]!=null)
{
height=Math.max(height,slots[i].getPreferredHeight(slots[i].getPreferredWidth()));
}
}
return height+2*border;
}
@Override
public void setSpacing(final int spacing)
{
UISingleton.runInSwing(new Runnable()
{
@Override
public void run()
{
ButtonPanelImp.this.spacing=spacing;
updateLayout();
}
});
}
@Override
public void setBorder(final int border)
{
UISingleton.runInSwing(new Runnable()
{
@Override
public void run()
{
ButtonPanelImp.this.border=border;
updateLayout();
}
});
}
@Override
public void addXMLChild(String slotName, Widget child)
{
int slot;
if(slotName.equals("yes")) slot=YES;
else if(slotName.equals("no")) slot=NO;
else if(slotName.equals("cancel")) slot=CANCEL;
else throw new BugException(
"Slot name invalid, expecting 'yes', 'no', or 'cancel': "+slotName);
set(slot,child);
}
@Override
public void redoLayout()
{
updateLayout();
super.redoLayout();
}
};
}