// -*- mode:java; encoding:utf-8 -*-
// vim:set fileencoding=utf-8:
// @homepage@

package example;

import java.awt.*;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Objects;
import java.util.stream.IntStream;
import javax.swing.*;
import javax.swing.text.DefaultCaret;

public class MainPanel extends JPanel {
  private final JCheckBox check = new JCheckBox("on EDT", true);
  private final JButton start = new JButton("Start");
  private final JButton stop = new JButton("Stop");
  private final JTextArea textArea0 = new JTextArea();
  private final JTextArea textArea1 = new JTextArea();
  private final JTextArea textArea2 = new JTextArea();
  // TEST: Timer timer = new Timer(500, e -> test(LocalDateTime.now(ZoneId.systemDefault()).toString()));
  // TEST: Thread thread;
  private transient SwingWorker<String, String> worker;

  public MainPanel() {
    super(new BorderLayout());

    ((DefaultCaret) textArea0.getCaret()).setUpdatePolicy(DefaultCaret.UPDATE_WHEN_ON_EDT); // default
    ((DefaultCaret) textArea1.getCaret()).setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
    ((DefaultCaret) textArea2.getCaret()).setUpdatePolicy(DefaultCaret.NEVER_UPDATE);

    JPanel p = new JPanel(new GridLayout(1, 0));
    p.add(makeTitledPanel("UPDATE_WHEN_ON_EDT", new JScrollPane(textArea0)));
    p.add(makeTitledPanel("ALWAYS_UPDATE", new JScrollPane(textArea1)));
    p.add(makeTitledPanel("NEVER_UPDATE", new JScrollPane(textArea2)));

    IntStream.range(0, 10).mapToObj(Integer::toString).forEach(this::test);

    start.addActionListener(e -> startTest());
    stop.setEnabled(false);
    stop.addActionListener(e -> {
      // TEST: timer.stop();
      // TEST: thread = null;
      if (Objects.nonNull(worker)) {
        worker.cancel(true);
        worker = null;
      }
    });

    Box box = Box.createHorizontalBox();
    box.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    box.add(Box.createHorizontalGlue());
    box.add(check);
    box.add(Box.createHorizontalStrut(5));
    box.add(start);
    box.add(Box.createHorizontalStrut(5));
    box.add(stop);

    add(p);
    add(box, BorderLayout.SOUTH);
    setPreferredSize(new Dimension(320, 240));
  }

  private class BackgroundTask extends SwingWorker<String, String> {
    @Override public String doInBackground() {
      while (true) {
        try {
          Thread.sleep(500);
        } catch (InterruptedException ex) {
          return "Interrupted";
        }
        if (check.isSelected()) {
          publish(LocalDateTime.now(ZoneId.systemDefault()).toString()); // On EDT
        } else {
          test(LocalDateTime.now(ZoneId.systemDefault()).toString()); // Not on EDT
        }
      }
    }
  }

  private static Component makeTitledPanel(String title, Component c) {
    JPanel p = new JPanel(new BorderLayout());
    p.setBorder(BorderFactory.createTitledBorder(title));
    p.add(c);
    return p;
  }

  private static void insertText(JTextArea textArea, String s) {
    textArea.append(s + "\n");
  }

  protected final void test(String s) {
    insertText(textArea0, s);
    insertText(textArea1, s);
    insertText(textArea2, s);
  }

  private void startTest() {
    // // TEST:
    // if (!timer.isRunning()) {
    //   timer.start();
    // }
    // // TEST:
    // if (Objects.isNull(thread)) {
    //   thread = new Thread(() -> {
    //     while (thread != null) {
    //       test(LocalDateTime.now(ZoneId.systemDefault()).toString());
    //       try {
    //         Thread.sleep(1000);
    //       } catch (InterruptedException ex) {
    //         test("Interrupted");
    //       }
    //     }
    //   });
    //   thread.start();
    // }
    if (Objects.isNull(worker)) {
      worker = new BackgroundTask() {
        @Override public String doInBackground() {
          while (true) {
            try {
              Thread.sleep(500);
            } catch (InterruptedException ex) {
              return "Interrupted";
            }
            if (check.isSelected()) {
              publish(LocalDateTime.now(ZoneId.systemDefault()).toString()); // On EDT
            } else {
              test(LocalDateTime.now(ZoneId.systemDefault()).toString()); // Not on EDT
            }
          }
        }

        @Override protected void process(List<String> chunks) {
          for (String message: chunks) {
            test(message);
          }
        }

        @Override public void done() {
          check.setEnabled(true);
          start.setEnabled(true);
          stop.setEnabled(false);
        }
      };
      check.setEnabled(false);
      start.setEnabled(false);
      stop.setEnabled(true);
      worker.execute();
    }
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(MainPanel::createAndShowGui);
  }

  private static void createAndShowGui() {
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
      ex.printStackTrace();
      Toolkit.getDefaultToolkit().beep();
    }
    JFrame frame = new JFrame("@title@");
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(new MainPanel());
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}

@@ -883,21 +883,22 @@
 er;%0A%0A  p
-ublic
+rivate
  MainPan
@@ -2345,91 +2345,15 @@
 d() 
-%7B%0A      while (true) %7B%0A        try %7B%0A          Thread.sleep(500);%0A        %7D catch (
+throws 
 Inte
@@ -2360,36 +2360,32 @@
 rruptedException
- ex)
  %7B%0A          ret
@@ -2381,43 +2381,59 @@
     
-    return %22Interrupted%22;%0A        %7D
+while (!isCancelled()) %7B%0A        Thread.sleep(500);
 %0A   
@@ -2661,24 +2661,50 @@
   %7D%0A      %7D%0A
+      return %22Cancelled%22;%0A
     %7D%0A  %7D%0A%0A 
@@ -3702,24 +3702,24 @@
 (worker)) %7B%0A
+
       worker
@@ -3748,504 +3748,8 @@
 ) %7B%0A
-        @Override public String doInBackground() %7B%0A          while (true) %7B%0A            try %7B%0A              Thread.sleep(500);%0A            %7D catch (InterruptedException ex) %7B%0A              return %22Interrupted%22;%0A            %7D%0A            if (check.isSelected()) %7B%0A              publish(LocalDateTime.now(ZoneId.systemDefault()).toString()); // On EDT%0A            %7D else %7B%0A              test(LocalDateTime.now(ZoneId.systemDefault()).toString()); // Not on EDT%0A            %7D%0A          %7D%0A        %7D%0A%0A
     

add an end condition to this loop