/**
*
* @author greg (at) myrobotlab.org
*
* This file is part of MyRobotLab (http://myrobotlab.org).
*
* MyRobotLab 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 2 of the License, or
* (at your option) any later version (subject to the "Classpath" exception
* as provided in the LICENSE.txt file that accompanied this code).
*
* MyRobotLab is distributed in the hope that it will be useful or fun,
* 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.
*
* All libraries in thirdParty bundle are subject to their own license
* requirements - please refer to http://myrobotlab.org/libraries for
* details.
*
* Enjoy !
*
* */
package org.myrobotlab.control;
import java.awt.Component;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.List;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.basic.BasicArrowButton;
import org.myrobotlab.logging.LoggerFactory;
import org.myrobotlab.service.GUIService;
import org.myrobotlab.service.Runtime;
import org.myrobotlab.service.Servo;
import org.myrobotlab.service.interfaces.ServoController;
import org.slf4j.Logger;
/**
* Servo GUIService - displays details of Servo state Lesson learned ! Servos to
* properly function need to be attached to a controller This gui previously
* sent messages to the controller. To simplify things its important to send
* messages only to the bound Servo - and let it attach to the controller versus
* sending messages directly to the controller. 1 display - 1 service - keep it
* simple
*
*/
public class ServoGUI extends ServiceGUI implements ActionListener {
private class SliderListener implements ChangeListener {
@Override
public void stateChanged(javax.swing.event.ChangeEvent e) {
boundPos.setText(String.format("%d", slider.getValue()));
if (myService != null) {
myService.send(boundServiceName, "moveTo", Integer.valueOf(slider.getValue()));
} else {
log.error("can not send message myService is null");
}
}
}
public final static Logger log = LoggerFactory.getLogger(ServoGUI.class.getCanonicalName());
static final long serialVersionUID = 1L;
JLabel boundPos = null;
JButton attachButton = new JButton("attach");
JButton updateLimitsButton = new JButton("update limits");
JSlider slider = new JSlider(0, 180, 90);
BasicArrowButton right = new BasicArrowButton(BasicArrowButton.EAST);
BasicArrowButton left = new BasicArrowButton(BasicArrowButton.WEST);
JComboBox<String> controller = new JComboBox<String>();
// JComboBox<Integer> pin = new JComboBox<Integer>();
JComboBox<Integer> pinList = new JComboBox<Integer>();
// DefaultComboBoxModel<String> controllerModel = new DefaultComboBoxModel<String>();
DefaultComboBoxModel<Integer> pinModel = new DefaultComboBoxModel<Integer>();
JTextField posMin = new JTextField("0");
JTextField posMax = new JTextField("180");
Servo myServo = null;
SliderListener sliderListener = new SliderListener();
public ServoGUI(final String boundServiceName, final GUIService myService, final JTabbedPane tabs) {
super(boundServiceName, myService, tabs);
myServo = (Servo) Runtime.getService(boundServiceName);
pinModel.addElement(null);
for (int i = 0; i < 54; i++) {
pinModel.addElement(i);
}
// determine not worth querying the controller to its pin list
}
// GUIService's action processing section - data from user
@Override
public void actionPerformed(final ActionEvent event) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Object o = event.getSource();
if (o == controller) {
String controllerName = (String) controller.getSelectedItem();
log.debug(String.format("controller event %s", controllerName));
if (controllerName != null && controllerName.length() > 0) {
// NOT WORTH IT - JUST BUILD 48 PINS !!!
// ServoController sc = (ServoController)
// Runtime.getService(controllerName);
// NOT WORTH THE TROUBLE !!!!
// @SuppressWarnings("unchecked")
// ArrayList<Pin> pinList = (ArrayList<Pin>)
// myService.sendBlocking(controllerName, "getPinList");
// log.info("{}", pinList.size());
// FIXME - get Local services relative to the servo
// pinModel.removeAllElements();
// pinModel.addElement(null);
// for (int i = 0; i < pinList.size(); ++i) {
// pinModel.addElement(pinList.get(i).pin);
// }
// pin.invalidate();
}
}
if (o == attachButton) {
if (attachButton.getText().equals("attach")) {
send("attach", controller.getSelectedItem(), (int)pinList.getSelectedItem(), (Integer)slider.getValue());
} else {
send("detach", controller.getSelectedItem());
}
return;
}
if (o == updateLimitsButton) {
send("setMinMax", Integer.parseInt(posMin.getText()), Integer.parseInt(posMax.getText()));
return;
}
if (o == right) {
slider.setValue(slider.getValue() + 1);
return;
}
if (o == left) {
slider.setValue(slider.getValue() - 1);
return;
}
}
});
}
@Override
public void attachGUI() {
subscribe("publishState", "getState", Servo.class);
// subscribe("controllerSet", "controllerSet");
// subscribe("pinSet", "pinSet");
// subscribe("attached", "attached");
// subscribe("detached", "detached");
myService.send(boundServiceName, "publishState");
}
@Override
public void detachGUI() {
unsubscribe("publishState", "getState", Servo.class);
// unsubscribe("controllerSet", "controllerSet");
// unsubscribe("pinSet", "pinSet");
// subscribe("attached", "attached");
// subscribe("detached", "detached");
}
synchronized public void getState(final Servo servo) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
removeListeners();
refreshControllers();
ServoController sc = servo.getController();
if (sc != null) {
controller.setSelectedItem(sc.getName());
Integer servoPin = servo.getPin();
if (servoPin != null)
pinList.setSelectedItem(servoPin);
}
if (servo.isControllerSet()) {
attachButton.setText("detach");
controller.setEnabled(false);
pinList.setEnabled(false);
} else {
attachButton.setText("attach");
controller.setEnabled(true);
pinList.setEnabled(true);
}
if (servo.getPos() == null) {
boundPos.setText("");
} else {
int pos = servo.getPos();
boundPos.setText(Integer.toString(pos));
slider.setValue(pos);
}
// In the inverted case, these are reversed
int min = Math.min(servo.getMinInput().intValue(), servo.getMaxInput().intValue());
int max = Math.max(servo.getMinInput().intValue(), servo.getMaxInput().intValue());
slider.setMinimum(min);
slider.setMaximum(max);
posMin.setText(servo.getMin().toString());
posMax.setText(servo.getMax().toString());
restoreListeners();
}
});
}
@Override
public void init() {
// build input begin ------------------
JPanel input = new JPanel();
input.setLayout(new GridBagLayout());
// row 1
gc.gridx = 0;
gc.gridy = 0;
input.add(slider, gc);
slider.addChangeListener(sliderListener);
gc.gridwidth = 2;
gc.gridx = 1;
++gc.gridy;
input.add(left, gc);
++gc.gridx;
input.add(right, gc);
++gc.gridx;
gc.gridx = 0;
++gc.gridy;
JPanel control = new JPanel();
input.setLayout(new GridBagLayout());
gc.gridx = 0;
gc.gridy = 0;
control.add(attachButton, gc);
++gc.gridx;
control.add(controller, gc);
++gc.gridx;
control.add(new JLabel("pin"), gc);
++gc.gridx;
control.add(pinList, gc);
display.add(control);
display.add(input);
gc.gridx = 0;
++gc.gridy;
JPanel limits = new JPanel();
limits.add(updateLimitsButton);
limits.add(new JLabel("min "));
limits.add(posMin);
limits.add(new JLabel(" max "));
limits.add(posMax);
limits.add(new JLabel(" "));
boundPos = new JLabel("90");
limits.add(boundPos);
display.add(limits, gc);
updateLimitsButton.addActionListener(this);
left.addActionListener(this);
right.addActionListener(this);
controller.addActionListener(this);
attachButton.addActionListener(this);
pinList.addActionListener(this);
// http://stackoverflow.com/questions/6205433/jcombobox-focus-and-mouse-click-events-not-working
// jComboBox1.getEditor().getEditorComponent().addMouseListener(...);
// have to add mouse listener to the MetalComboButton embedded in the
// JComboBox
//* No longer needed
// Component[] comps = controller.getComponents();
//for (int i = 0; i < comps.length; i++) {
//comps[i].addMouseListener(this); // JComboBox composite listener -
// have to get all the sub
// components
/*
* comps[i].addMouseListener(new MouseAdapter() { public void
* mouseClicked(MouseEvent me) { System.out.println("clicked"); }
* });
*/
// }
// controller.getEditor().getEditorComponent().addMouseListener(this);
pinList.setModel(pinModel);
refreshControllers();
}
public void getPinList() {
List<Integer> mbl = myServo.pinList;
for (int i = 0; i < mbl.size(); i++) {
pinList.addItem(mbl.get(i));
}
}
// a controller has been set
/*
* public void displayController(final ServoController sc, final ServoGUI
* mygui) { SwingUtilities.invokeLater(new Runnable() { public void run() {
* controller.removeActionListener(mygui); pinModel.removeAllElements(); //
* FIXME - get Local services relative to the servo
* pinModel.addElement(null);
*
* ArrayList<Pin> pinList = sc.getPinList(); for (int i = 0; i <
* pinList.size(); ++i) { pinModel.addElement(pinList.get(i).pin); }
*
* pin.invalidate(); } });
*
* }
*/
public void refreshControllers() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
myServo.refreshControllers();
controller.removeAllItems();
List<String> c = myServo.controllers;
for (int i = 0; i < c.size(); ++i) {
controller.addItem(c.get(i));
}
controller.setSelectedItem(myServo.controllerName);
}
});
}
public void removeListeners() {
controller.removeActionListener(this);
pinList.removeActionListener(this);
slider.removeChangeListener(sliderListener);
}
public void restoreListeners() {
controller.addActionListener(this);
pinList.addActionListener(this);
slider.addChangeListener(sliderListener);
}
}