2626import java .util .ArrayList ;
2727import javax .swing .*;
2828import javax .swing .border .EmptyBorder ;
29+ import javax .swing .text .DefaultEditorKit ;
2930import java .awt .*;
31+ import java .awt .event .ActionEvent ;
3032import java .awt .event .ActionListener ;
33+ import java .awt .event .WindowAdapter ;
34+ import java .awt .event .WindowEvent ;
3135import java .awt .geom .AffineTransform ;
3236import java .awt .geom .Rectangle2D ;
3337
@@ -40,6 +44,11 @@ public class SerialPlotter extends AbstractMonitor {
4044 private Serial serial ;
4145 private int serialRate , xCount ;
4246
47+ private JLabel noLineEndingAlert ;
48+ private JTextField textField ;
49+ private JButton sendButton ;
50+ private JComboBox <String > lineEndings ;
51+
4352 private ArrayList <Graph > graphs ;
4453 private final static int BUFFER_CAPACITY = 500 ;
4554
@@ -254,10 +263,113 @@ protected void onCreateWindow(Container mainPane) {
254263 pane .add (serialRates );
255264
256265 mainPane .add (pane , BorderLayout .SOUTH );
266+
267+ textField = new JTextField (40 );
268+ // textField is selected every time the window is focused
269+ addWindowFocusListener (new WindowAdapter () {
270+ @ Override
271+ public void windowGainedFocus (WindowEvent e ) {
272+ textField .requestFocusInWindow ();
273+ }
274+ });
275+
276+ // Add cut/copy/paste contextual menu to the text input field.
277+ JPopupMenu menu = new JPopupMenu ();
278+
279+ Action cut = new DefaultEditorKit .CutAction ();
280+ cut .putValue (Action .NAME , tr ("Cut" ));
281+ menu .add (cut );
282+
283+ Action copy = new DefaultEditorKit .CopyAction ();
284+ copy .putValue (Action .NAME , tr ("Copy" ));
285+ menu .add (copy );
286+
287+ Action paste = new DefaultEditorKit .PasteAction ();
288+ paste .putValue (Action .NAME , tr ("Paste" ));
289+ menu .add (paste );
290+
291+ textField .setComponentPopupMenu (menu );
292+
293+ sendButton = new JButton (tr ("Send" ));
294+
295+ JPanel lowerPane = new JPanel ();
296+ lowerPane .setLayout (new BoxLayout (lowerPane , BoxLayout .X_AXIS ));
297+ lowerPane .setBorder (new EmptyBorder (4 , 4 , 4 , 4 ));
298+
299+ noLineEndingAlert = new JLabel (I18n .format (tr ("You've pressed {0} but nothing was sent. Should you select a line ending?" ), tr ("Send" )));
300+ noLineEndingAlert .setToolTipText (noLineEndingAlert .getText ());
301+ noLineEndingAlert .setForeground (pane .getBackground ());
302+ Dimension minimumSize = new Dimension (noLineEndingAlert .getMinimumSize ());
303+ minimumSize .setSize (minimumSize .getWidth () / 3 , minimumSize .getHeight ());
304+ noLineEndingAlert .setMinimumSize (minimumSize );
305+
306+
307+ lineEndings = new JComboBox <String >(new String []{tr ("No line ending" ), tr ("Newline" ), tr ("Carriage return" ), tr ("Both NL & CR" )});
308+ lineEndings .addActionListener ((ActionEvent event ) -> {
309+ PreferencesData .setInteger ("serial.line_ending" , lineEndings .getSelectedIndex ());
310+ noLineEndingAlert .setForeground (pane .getBackground ());
311+ });
312+ lineEndings .setMaximumSize (lineEndings .getMinimumSize ());
313+
314+ lowerPane .add (textField );
315+ lowerPane .add (Box .createRigidArea (new Dimension (4 , 0 )));
316+ lowerPane .add (sendButton );
317+
318+ pane .add (lowerPane );
319+ pane .add (noLineEndingAlert );
320+ pane .add (Box .createRigidArea (new Dimension (8 , 0 )));
321+ pane .add (lineEndings );
322+
323+ applyPreferences ();
324+
325+ onSendCommand ((ActionEvent event ) -> {
326+ send (textField .getText ());
327+ textField .setText ("" );
328+ });
329+
330+ }
331+
332+ private void send (String string ) {
333+ String s = string ;
334+ if (serial != null ) {
335+ switch (lineEndings .getSelectedIndex ()) {
336+ case 1 :
337+ s += "\n " ;
338+ break ;
339+ case 2 :
340+ s += "\r " ;
341+ break ;
342+ case 3 :
343+ s += "\r \n " ;
344+ break ;
345+ default :
346+ break ;
347+ }
348+ if ("" .equals (s ) && lineEndings .getSelectedIndex () == 0 && !PreferencesData .has ("runtime.line.ending.alert.notified" )) {
349+ noLineEndingAlert .setForeground (Color .RED );
350+ PreferencesData .set ("runtime.line.ending.alert.notified" , "true" );
351+ }
352+ serial .write (s );
353+ }
354+ }
355+
356+ public void onSendCommand (ActionListener listener ) {
357+ textField .addActionListener (listener );
358+ sendButton .addActionListener (listener );
359+ }
360+
361+ public void appyPreferences () {
362+ // Apply line endings.
363+ if (PreferencesData .get ("serial.line_ending" ) != null ) {
364+ lineEndings .setSelectedIndex (PreferencesData .getInteger ("serial.line_ending" ));
365+ }
257366 }
258367
259368 protected void onEnableWindow (boolean enable ) {
260369 serialRates .setEnabled (enable );
370+ textField .setEnabled (enable );
371+ sendButton .setEnabled (enable );
372+ lineEndings .setEnabled (enable );
261373 }
262374
263375 private void onSerialRateChange (ActionListener listener ) {
0 commit comments