/**
 * @version 1.22 2004-08-01
 * @author Cay Horstmann
 */

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

/**
   Program ilustrujący błędy, które wywołać
   może w komponentach biblioteki Swing
   wątek wykonywany równocześnie
   z wątkiem obsługi zdarzeń.
*/
public class SwingThreadTest
{  
   public static void main(String[] args)
   {  
      SwingThreadFrame frame = new SwingThreadFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setVisible(true);
   }
}

/**
   Ramka zawierająca dwa przyciski powodujące
   modyfikację listy rozwijanej przez osobny wątek.
   W przypadku przycisku "Good" modyfikacja odbywa się
   za pośrednictwem kolejki zdarzeń, natomiast wybranie przycisku "Bad" 
   powoduje bezpośrednią modyfikację.

*/
class SwingThreadFrame extends JFrame
{  
   public SwingThreadFrame()
   {  
      setTitle("SwingThreadTest");

      final JComboBox combo = new JComboBox();
      combo.insertItemAt(new Integer(Integer.MAX_VALUE), 0);
      combo.setPrototypeDisplayValue(combo.getItemAt(0));
      combo.setSelectedIndex(0);

      JPanel panel = new JPanel();

      JButton goodButton = new JButton("Good");
      goodButton.addActionListener(new ActionListener()
         {  
            public void actionPerformed(ActionEvent event)
            {  
               new Thread(new GoodWorkerRunnable(combo)).start();
            }
         });
      panel.add(goodButton);
      JButton badButton = new JButton("Bad");
      badButton.addActionListener(new ActionListener()
         {  
            public void actionPerformed(ActionEvent event)
            {  
               new Thread(new BadWorkerRunnable(combo)).start();
            }
         });
      panel.add(badButton);
      panel.add(combo);
      add(panel);
      pack();
   }
}

/**
   Zadanie modyfikuje listę rozwijaną, dodając bądź usuwając
   losowo jej pozycje. Może powodować to błędy, ponieważ 
   dostęp do listy nie jest synchronizowany, a wątek obsługi zdarzeń
   odświeża prezentację listy.
*/  
class BadWorkerRunnable implements Runnable
{  
   public BadWorkerRunnable(JComboBox aCombo)
   {  
      combo = aCombo;
      generator = new Random();
   }

   public void run()
   {  
      try
      {
         while (true)
         {  
            combo.showPopup();
            int i = Math.abs(generator.nextInt());
            if (i % 2 == 0)
               combo.insertItemAt(new Integer(i), 0);
            else if (combo.getItemCount() > 0)
               combo.removeItemAt(i % combo.getItemCount());
            Thread.sleep(1);
         }
      }
      catch (InterruptedException e) {}
   }

   private JComboBox combo;
   private Random generator;
}

/**
   Zadanie to modyfikuje listę rozwijaną, dodając bądź usuwając
   losowo jej pozycje. Bezpieczne wykonanie tych 
   operacji zapewnione jest poprzez przekazanie ich do wątku
   obsługi zdarzeń.
*/  
class GoodWorkerRunnable implements Runnable
{  
   public GoodWorkerRunnable(JComboBox aCombo)
   {  
      combo = aCombo;
      generator = new Random();
   }

   public void run()
   {  
      try
      {
         while (true)
         {  
            EventQueue.invokeLater(new 
               Runnable()
               {  
                  public void run()
                  {  
                     combo.showPopup();
                     int i = Math.abs(generator.nextInt());
                     if (i % 2 == 0)
                        combo.insertItemAt(new Integer(i), 0);
                     else if (combo.getItemCount() > 0)
                        combo.removeItemAt(i % combo.getItemCount());
                  }
               });
            Thread.sleep(1); 
         }
      }
      catch (InterruptedException e) {} 
   }

   private JComboBox combo;
   private Random generator;
}








