// Copyright 2011 Palantir Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.palantir.ptoss.cinch.example.dynamic;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import com.google.common.collect.Lists;
import com.palantir.ptoss.cinch.core.Bindings;
import com.palantir.ptoss.cinch.core.CallOnUpdate;
import com.palantir.ptoss.cinch.core.DefaultBindableModel;
import com.palantir.ptoss.cinch.example.Examples;
import com.palantir.ptoss.cinch.swing.Bound;
/**
* A contrived example of how to use Cinch to bind a dynamic set of controls. The UI shows a slider
* between 1 and 10 that controls how many checkboxes should be shown.
*/
public class DynamicControls {
public static class BooleanModel extends DefaultBindableModel {
boolean state = false;
public boolean isState() {
return state;
}
public void setState(boolean state) {
this.state = state;
update();
}
}
public static class DynamicModel extends DefaultBindableModel {
// The number of dynamic controls
int count;
// A collection of BindableModels for our dynamic controls
final List<BooleanModel> models = Lists.newArrayList();
public DynamicModel() {
setCount(5);
}
public int getCount() {
return count;
}
public void setCount(int count) {
if (count < 1) {
count = 1;
}
if (count > 10) {
count = 10;
}
if (this.count == count) {
return;
}
this.count = count;
models.clear();
for (int i = 0; i < count; i++) {
models.add(new BooleanModel());
}
update();
}
public List<BooleanModel> getModels() {
return models;
}
}
// In this contrived example we're simply wrapping up a JCheckbox but this could be something
// arbitrarily complex
private static class BooleanComponent {
final BooleanModel model;
@Bound(to = "state")
final JCheckBox box = new JCheckBox("State");
final Bindings bindings = new Bindings();
public BooleanComponent(BooleanModel model) {
this.model = model;
this.bindings.bind(this);
}
public JComponent getDisplayComponent() {
return box;
}
public void dispose() {
bindings.release(model);
}
}
private final DynamicModel model = new DynamicModel();
private final JPanel panel = new JPanel();
@Bound(to = "count")
private final JSlider slider = new JSlider(1, 10);
private final List<BooleanComponent> checkboxComponents = Lists.newArrayList();
private final JPanel checkboxPanel = new JPanel();
private final Bindings bindings = Bindings.standard();;
public DynamicControls() {
initializeInterface();
bindings.bind(this);
}
private void initializeInterface() {
JPanel toPanel = new JPanel(new BorderLayout());
toPanel.add(new JLabel("Count"), BorderLayout.WEST);
slider.setPaintLabels(true);
slider.setLabelTable(slider.createStandardLabels(1));
slider.setSnapToTicks(true);
toPanel.add(slider, BorderLayout.CENTER);
panel.setLayout(new BorderLayout());
panel.add(toPanel, BorderLayout.NORTH);
checkboxPanel.setLayout(new BoxLayout(checkboxPanel, BoxLayout.Y_AXIS));
checkboxPanel.setPreferredSize(new Dimension(200, 300));
panel.add(checkboxPanel, BorderLayout.CENTER);
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
}
@SuppressWarnings("unused")
@CallOnUpdate
private void synchCheckboxes() {
// It's important to remove transient listeners to long-lived models
for (BooleanComponent component : checkboxComponents) {
component.dispose();
}
checkboxPanel.removeAll();
checkboxComponents.clear();
for (BooleanModel booleanModel : model.getModels()) {
BooleanComponent booleanComponent = new BooleanComponent(booleanModel);
checkboxComponents.add(booleanComponent);
checkboxPanel.add(booleanComponent.getDisplayComponent());
}
checkboxPanel.revalidate();
checkboxPanel.repaint();
}
public JComponent getDisplayComponent() {
return panel;
}
public static void main(String[] args) throws InterruptedException, InvocationTargetException {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
Examples.initializeLogging();
DynamicControls example = new DynamicControls();
JFrame frame = Examples.getFrameFor("Cinch Dynamic Controls Example", example.panel);
frame.pack();
frame.setVisible(true);
}
});
}
}