Skip to content

Commit 9424d2d

Browse files
authored
Merge pull request #272 from bobjacobsen/eventID-selector-improvements
Add context menu to event ID selector
2 parents c54cfa3 + 2b23a24 commit 9424d2d

File tree

4 files changed

+431
-1
lines changed

4 files changed

+431
-1
lines changed

sample.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@
2828
<blob size="10" mode="readwrite">
2929
<name>Blob to see if works in group element</name>
3030
</blob>
31+
<float size="2">
32+
<name>Float to see if works in group element</name>
33+
</float>
34+
<int size="4">
35+
<name>Int of size 4 so that each group is 32 long</name>
36+
</int>
3137
</group>
3238
<int size="2">
3339
<name>Sample integer variable</name>

src/org/openlcb/cdi/swing/CdiPanel.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2246,6 +2246,18 @@ public void actionPerformed(java.awt.event.ActionEvent e) {
22462246
});
22472247
addButtonToEventidMoreFunctions(bAS);
22482248

2249+
eventidMoreMenu.add(
2250+
EventIdTextField.makeWellKnownEventMenu(textField)
2251+
);
2252+
2253+
eventidMoreMenu.add(
2254+
EventIdTextField.makeClockEventMenuItem(textField)
2255+
);
2256+
2257+
eventidMoreMenu.add(
2258+
EventIdTextField.makeDccAccessoryEventMenuItem(textField)
2259+
);
2260+
22492261
p3.add(Box.createHorizontalStrut(5));
22502262
addCopyPasteButtons(p3, textField);
22512263
p3.add(Box.createHorizontalStrut(5));

src/org/openlcb/swing/EventIdTextField.java

Lines changed: 249 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,46 @@
22

33
package org.openlcb.swing;
44

5+
import java.awt.FlowLayout;
6+
import java.awt.Toolkit;
7+
import java.awt.datatransfer.Clipboard;
8+
import java.awt.datatransfer.ClipboardOwner;
59
import java.awt.datatransfer.DataFlavor;
610
import java.awt.datatransfer.StringSelection;
711
import java.awt.datatransfer.Transferable;
812
import java.awt.datatransfer.UnsupportedFlavorException;
13+
import java.awt.event.ActionEvent;
14+
import java.awt.event.ActionListener;
15+
import java.awt.event.InputEvent;
16+
import java.awt.event.MouseAdapter;
17+
import java.awt.event.MouseEvent;
18+
import java.awt.event.WindowAdapter;
19+
import java.awt.event.WindowEvent;
20+
921
import java.io.IOException;
1022
import java.util.logging.Level;
1123
import java.util.logging.Logger;
1224

25+
import javax.swing.JButton;
1326
import javax.swing.JComponent;
27+
import javax.swing.JComboBox;
28+
import javax.swing.JDialog;
1429
import javax.swing.JFormattedTextField;
30+
import javax.swing.JFrame;
31+
import javax.swing.JMenu;
32+
import javax.swing.JMenuItem;
33+
import javax.swing.JOptionPane;
34+
import javax.swing.JPanel;
35+
import javax.swing.JPopupMenu;
36+
import javax.swing.JTextField;
37+
import javax.swing.SwingUtilities;
1538
import javax.swing.TransferHandler;
39+
import javax.swing.text.DefaultEditorKit;
1640
import javax.swing.text.JTextComponent;
1741
import javax.swing.text.MaskFormatter;
1842

43+
import org.openlcb.EventID;
44+
1945
/**
2046
* Text field for entry of forced-valid EventID string.
2147
*
@@ -39,14 +65,236 @@ public static JFormattedTextField getEventIdTextField() {
3965
retval.setValue("DD.DD.DD.DD.DD.DD.DD.DD");
4066
retval.setPreferredSize(retval.getPreferredSize());
4167
retval.setValue("00.00.00.00.00.00.00.00");
68+
4269
retval.setToolTipText("EventID as eight-byte dotted-hex string, "
43-
+ "e.g. 01.02.0A.AB.34.56.78.00");
70+
+ "e.g. 01.02.0A.AB.34.56.78.00 "
71+
+ "You can drag&drop or ctrl-click for more options");
72+
4473
retval.setDragEnabled(true);
4574
retval.setTransferHandler(new CustomTransferHandler());
4675

76+
configurePopUp(retval);
77+
4778
return retval;
4879
}
4980

81+
private static void configurePopUp(JFormattedTextField textfield) {
82+
83+
// JMRI's apps.Apps.java line 330 adds cut/copy/paste to all JTextComponents
84+
// (Also serves as example of cut/copy/paste code)
85+
86+
JPopupMenu popup = createPopupMenu(textfield);
87+
//textfield.add(popup);
88+
textfield.setComponentPopupMenu(popup);
89+
textfield.setInheritsPopupMenu(false);
90+
}
91+
92+
private static void checkAndShowPopup(JFormattedTextField textfield, MouseEvent event) {
93+
if ( event.isPopupTrigger() ) {
94+
// user requested the popup menu
95+
JPopupMenu popup = createPopupMenu(textfield);
96+
popup.show(textfield, event.getX(), event.getY());
97+
}
98+
}
99+
100+
private static JPopupMenu createPopupMenu(JFormattedTextField textfield) {
101+
JPopupMenu popup = new JPopupMenu();
102+
103+
// add the usual copy and paste operators
104+
JMenuItem menuItem = new JMenuItem("Copy");
105+
popup.add(menuItem);
106+
menuItem.addActionListener(new ActionListener() {
107+
@Override
108+
public void actionPerformed(ActionEvent e) {
109+
String s = textfield.getText();
110+
SwingUtilities.invokeLater(new Runnable() {
111+
@Override
112+
public void run() {
113+
textfield.selectAll();
114+
}
115+
});
116+
StringSelection eventToCopy = new StringSelection(s);
117+
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
118+
clipboard.setContents(eventToCopy, new ClipboardOwner() {
119+
@Override
120+
public void lostOwnership(Clipboard clipboard, Transferable transferable) {
121+
}
122+
});
123+
}
124+
});
125+
126+
menuItem = new JMenuItem("Paste");
127+
popup.add(menuItem);
128+
menuItem.addActionListener(new ActionListener() {
129+
@Override
130+
public void actionPerformed(ActionEvent e) {
131+
Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
132+
DataFlavor dataFlavor = DataFlavor.stringFlavor;
133+
134+
Object text = null;
135+
try {
136+
text = systemClipboard.getData(dataFlavor);
137+
} catch (UnsupportedFlavorException | IOException e1) {
138+
return;
139+
}
140+
String pasteValue = (String) text;
141+
if (pasteValue != null) {
142+
textfield.setText(pasteValue);
143+
}
144+
}
145+
});
146+
147+
// create a submenu for well-known events
148+
popup.add(makeWellKnownEventMenu(textfield));
149+
150+
// Add the time events
151+
popup.add( makeClockEventMenuItem(textfield));
152+
153+
// Add the accessory decoder events
154+
popup.add(makeDccAccessoryEventMenuItem(textfield));
155+
156+
// popup.add("Extended DCC accessory decoder events ...");
157+
// popup.add("DCC turnout feedback events ...");
158+
// popup.add("DCC system sensor feedback events ...");
159+
160+
return popup;
161+
}
162+
163+
public static JMenu makeWellKnownEventMenu(JFormattedTextField textfield) {
164+
JMenu wkeMenu = new JMenu("Insert well-known event");
165+
wkeMenu.add(new EventIdInserter(
166+
"Emergency off (de-energize)", "01.00.00.00.05.00.FF.FF", textfield));
167+
wkeMenu.add(new EventIdInserter(
168+
"Clear emergency off (energize)", "01.00.00.00.00.00.FF.FE", textfield));
169+
170+
wkeMenu.add(new EventIdInserter(
171+
"Emergency stop of all operations", "01.00.00.00.05.00.FF.FD", textfield));
172+
wkeMenu.add(new EventIdInserter(
173+
"Clear emergency stop of all operations","01.00.00.00.00.00.FF.FC", textfield));
174+
175+
wkeMenu.add(new EventIdInserter(
176+
"Start Default Fast Clock", "01.01.00.00.01.00.F0.02", textfield));
177+
wkeMenu.add(new EventIdInserter(
178+
"Stop Default Fast Clock", "01.01.00.00.01.00.F0.01", textfield));
179+
180+
return wkeMenu;
181+
}
182+
183+
public static JMenuItem makeClockEventMenuItem(JFormattedTextField textfield) {
184+
JMenuItem menuItem = new JMenuItem("Insert Clock event...");
185+
menuItem.addActionListener(new ActionListener() {
186+
@Override
187+
public void actionPerformed(ActionEvent e) {
188+
JDialog dialog = new JDialog();
189+
dialog.setTitle("Select Clock Settings");
190+
191+
JPanel innerPanel = new JPanel(new FlowLayout());
192+
JComboBox<String> clockBox = new JComboBox<String>(
193+
new String[]{
194+
"Default Fast Clock",
195+
"Default Real-Time Clock",
196+
"Alternate Clock 1",
197+
"Alternate Clock 2"
198+
});
199+
innerPanel.add(clockBox);
200+
util.com.toedter.calendar.JHourMinuteChooser chooser = new util.com.toedter.calendar.JHourMinuteChooser();
201+
innerPanel.add(chooser);
202+
JButton setButton = new JButton("Set");
203+
innerPanel.add(setButton);
204+
setButton.addActionListener(new ActionListener() {
205+
@Override
206+
public void actionPerformed(ActionEvent e) {
207+
String prefix = "01.01.00.00.01.0"+clockBox.getSelectedIndex();
208+
int minute = Integer.parseInt(chooser.getMinute());
209+
int hour = Integer.parseInt(chooser.getHour());
210+
if (! chooser.getMeridian().equals("AM")) hour = hour+12;
211+
textfield.setText(prefix+String.format(".%02X.%02X", hour, minute));
212+
dialog.dispatchEvent(new WindowEvent(dialog, WindowEvent.WINDOW_CLOSING));
213+
}
214+
});
215+
216+
dialog.add(innerPanel);
217+
dialog.setModal(true);
218+
dialog.pack();
219+
dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
220+
221+
dialog.setVisible(true);
222+
}
223+
});
224+
return menuItem;
225+
}
226+
227+
public static JMenuItem makeDccAccessoryEventMenuItem(JFormattedTextField textfield) {
228+
JMenuItem menuItem = new JMenuItem("Insert DCC accessory decoder events ...");
229+
menuItem.addActionListener(new ActionListener() {
230+
@Override
231+
public void actionPerformed(ActionEvent e) {
232+
JDialog dialog = new JDialog();
233+
dialog.setTitle("Select DCC Accessory Decoder");
234+
235+
JPanel innerPanel = new JPanel(new FlowLayout());
236+
237+
JTextField number = new JTextField(12);
238+
number.setText("1");
239+
innerPanel.add(number);
240+
241+
JComboBox<String> onOffBox = new JComboBox<String>(
242+
new String[]{
243+
"Reversed/Inactive/Off",
244+
"Normal/Active/On"
245+
});
246+
innerPanel.add(onOffBox);
247+
248+
JButton setButton = new JButton("Set");
249+
innerPanel.add(setButton);
250+
setButton.addActionListener(new ActionListener() {
251+
@Override
252+
public void actionPerformed(ActionEvent e) {
253+
int from = Integer.parseInt(number.getText().trim());
254+
255+
// See JMRI OlcnAddress line 89 for Event ID coding
256+
int DD = (from-1) & 0x3;
257+
int aaaaaa = (( (from-1) >> 2)+1 ) & 0x3F;
258+
int AAA = ( (from) >> 8) & 0x7;
259+
long event = 0x0101020000FF0000L | (AAA << 9) | (aaaaaa << 3) | (DD << 1);
260+
event |= onOffBox.getSelectedIndex();
261+
262+
EventID id = new EventID(String.format("%016X", event));
263+
textfield.setText(id.toShortString());
264+
dialog.dispatchEvent(new WindowEvent(dialog, WindowEvent.WINDOW_CLOSING));
265+
}
266+
});
267+
268+
dialog.add(innerPanel);
269+
dialog.setModal(true);
270+
dialog.pack();
271+
dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
272+
273+
dialog.setVisible(true);
274+
}
275+
});
276+
return menuItem;
277+
}
278+
279+
private static class EventIdInserter extends JMenuItem {
280+
public EventIdInserter(String name, String value, JFormattedTextField target) {
281+
super(name);
282+
this.value = value;
283+
this.target = target;
284+
285+
addActionListener(new ActionListener() {
286+
@Override
287+
public void actionPerformed(ActionEvent e) {
288+
target.setText(value);
289+
}
290+
});
291+
}
292+
final String value;
293+
final JFormattedTextField target;
294+
295+
}
296+
297+
50298
private static MaskFormatter createFormatter(String s) {
51299
MaskFormatter formatter = null;
52300
try {

0 commit comments

Comments
 (0)