/*
* Copyright (C) 2014 Shashank Tulsyan
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package neembuu.release1.ui.linkcontainer;
import java.util.ArrayList;
import java.util.Collection;
import javax.swing.GroupLayout;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import neembuu.release1.api.ui.linkpanel.ExpandableUI;
import neembuu.release1.api.ui.HeightProperty;
import neembuu.release1.api.ui.ExpandableUIContainer;
import neembuu.release1.ui.MainPanel;
/**
*
* @author Shashank Tulsyan
*/
public final class LinksContainer implements ExpandableUIContainer {
private final ArrayList<ExpandableUI> expandableUIs = new ArrayList<ExpandableUI>(){
@Override public boolean add(ExpandableUI e) {
linkContainerHeightProperty.notifyChange();
return super.add(e);}
@Override public boolean addAll(int index, Collection<? extends ExpandableUI> c) {
linkContainerHeightProperty.notifyChange();
return super.addAll(index, c);}
@Override public boolean remove(Object o) {
linkContainerHeightProperty.notifyChange();
return super.remove(o); }
};
private final MainPanel mp;
private final JPanel linksPanel;
private final LCHeightProperty linkContainerHeightProperty = new LCHeightProperty(this);
public LinksContainer(MainPanel mp, JPanel linksPanel) {
this.mp = mp;
this.linksPanel = linksPanel;
}
//@ThreadSafe
public void addUI(ExpandableUI uI, int index){
synchronized(expandableUIs){
if(index< 0){
expandableUIs.add(uI);
}else {
expandableUIs.add(index,uI);
}
}
uI.heightProperty().addListener(listener_of_height_of_individual_linkuis);
updateLayout(null);
listener_of_height_of_individual_linkuis.changed(uI.heightProperty(), 0, uI.heightProperty().getValue());
}
/**
* Delegating remove operation to updateLayout because it runs
* in the Swing Event Dispatch Thread, which will be the right way
* to do things.
* @param toRemove element to remove
*/
private void updateLayout(final JComponent toRemove){
//doing horizontal alignment
final ExpandableUI euis[]=getExpandableUIsCopy();
SwingUtilities.invokeLater(new Runnable() {
@Override public void run() {
updateLayout(euis,toRemove);
}
});
}
private void updateLayout(ExpandableUI[]euis,final JComponent toRemove){
if(toRemove!=null)linksPanel.remove(toRemove);
GroupLayout linksPanelLayout = (GroupLayout)linksPanel.getLayout();
GroupLayout.ParallelGroup parallelGroup = linksPanelLayout.createParallelGroup();
for (ExpandableUI eui : euis) {
parallelGroup.addComponent(
eui.getJComponent(), javax.swing.GroupLayout.DEFAULT_SIZE, 100, Short.MAX_VALUE);
}
linksPanelLayout.setHorizontalGroup(linksPanelLayout.createSequentialGroup()
.addGap(left, left, left)
.addGroup(parallelGroup)
.addGap(right, right, right));
adjustHeightOfLinksSection(1,euis);
}
private final int left = 25;
private final int right = 40;
final int bottom = 10;
private void adjustHeightOfLinksSection(double f,ExpandableUI euis[]){
GroupLayout linksPanelLayout = (GroupLayout)linksPanel.getLayout();
GroupLayout.SequentialGroup sequentialGroup = linksPanelLayout.createSequentialGroup();
for (ExpandableUI eui : euis) {
sequentialGroup
.addComponent(eui.getJComponent(), javax.swing.GroupLayout.DEFAULT_SIZE, eui.heightProperty().getValue(), eui.heightProperty().getValue())
.addGap(bottom, bottom, bottom);
}
linksPanelLayout.setVerticalGroup(linksPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(sequentialGroup));
}
@Override
public void removeUI(ExpandableUI uI) {
synchronized (expandableUIs){
expandableUIs.remove(uI);
}
uI.heightProperty().removeListener(listener_of_height_of_individual_linkuis);
updateLayout(uI.getJComponent());
listener_of_height_of_individual_linkuis.changed(null, 0, 0);
}
/**
* To avoid race condition, and using sychronization is slightly undesirably
* as holding locks is risky deadlocks. I avoid using synchronization,
* or holding lock over multiple statements and function calls.
* Copy on access feels safer.
* @return Array copy of ExpandableUIs
*/
ExpandableUI[]getExpandableUIsCopy(){
synchronized (expandableUIs){
return expandableUIs.toArray(new ExpandableUI[expandableUIs.size()]);
}
}
@Override public HeightProperty heightProperty() { return linkContainerHeightProperty; }
private final HeightProperty.Listener listener_of_height_of_individual_linkuis = new HeightProperty.Listener() {
@Override public void changed(HeightProperty h, int oldValue, int newValue) {
updateLayout(null); // to layout link container
linkContainerHeightProperty.notifyChange(); // to layout main frame
}};
}