Clover coverage report - JFCUnit Test Coverage
Coverage timestamp: Mon Dec 20 2004 23:38:10 MST
file stats: LOC: 564   Methods: 21
NCLOC: 305   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
JFCEventManager.java 89.1% 93.5% 90.5% 91.9%
coverage coverage
 1   
 package junit.extensions.jfcunit.eventdata;
 2   
 
 3   
 import junit.extensions.jfcunit.JFCTestCase;
 4   
 
 5   
 import java.awt.AWTEvent;
 6   
 import java.awt.Toolkit;
 7   
 import java.awt.event.AWTEventListener;
 8   
 import java.awt.event.InputEvent;
 9   
 import java.awt.event.MouseEvent;
 10   
 
 11   
 import java.util.ArrayList;
 12   
 import java.util.EventListener;
 13   
 import java.util.Iterator;
 14   
 
 15   
 import javax.swing.UIManager;
 16   
 import javax.swing.event.EventListenerList;
 17   
 
 18   
 
 19   
 /**
 20   
  * This class provides a recording capabilities for AWTEvents.
 21   
  * {@link java.awt.AWTEvent}s are translated into their coresponding
 22   
  * Event Data types. An application may register a listener against
 23   
  * this class, to receive the event data.
 24   
  *
 25   
  * This class temporarily holds events until either a different
 26   
  * event type is received or a timer expires on the event.
 27   
  *
 28   
  * @author Kevin Wilson
 29   
  */
 30   
 public final class JFCEventManager implements AWTEventListener,
 31   
     EventDataConstants {
 32   
     /**
 33   
      * Event Mapping Property.
 34   
      */
 35   
     public static final String EVENT_MAPPING_PROPERTY = "junit.extensions.jfcUnit.eventMapping";
 36   
 
 37   
     /**
 38   
     * Used to turn on debug info.
 39   
      */
 40   
     public static final String EVENT_DEBUG = "JFCEventManager.debug";
 41   
 
 42   
     static {
 43  4
         if (UIManager.get(EVENT_MAPPING_PROPERTY) == null) {
 44  4
             ArrayList mapping = new ArrayList();
 45  4
             mapping.add(
 46   
                 new String[] {
 47   
                     "junit.extensions.jfcunit.eventdata.JComboBoxMouseEventData",
 48   
                     "javax.swing.JList"
 49   
                 });
 50  4
             mapping.add(
 51   
                 new String[] {
 52   
                     "junit.extensions.jfcunit.eventdata.JListMouseEventData",
 53   
                     "javax.swing.JList"
 54   
                 });
 55  4
             mapping.add(
 56   
                 new String[] {
 57   
                     "junit.extensions.jfcunit.eventdata.JTableMouseEventData",
 58   
                     "javax.swing.JTable"
 59   
                 });
 60  4
             mapping.add(
 61   
                 new String[] {
 62   
                     "junit.extensions.jfcunit.eventdata.JTableHeaderMouseEventData",
 63   
                     "javax.swing.table.JTableHeader"
 64   
                 });
 65  4
             mapping.add(
 66   
                 new String[] {
 67   
                     "junit.extensions.jfcunit.eventdata.JTreeMouseEventData",
 68   
                     "javax.swing.JTree"
 69   
                 });
 70  4
             mapping.add(
 71   
                 new String[] {
 72   
                     "junit.extensions.jfcunit.eventdata.JTabbedPaneMouseEventData",
 73   
                     "javax.swing.JTabbedPane"
 74   
                 });
 75  4
             mapping.add(
 76   
                 new String[] {
 77   
                     "junit.extensions.jfcunit.eventdata.JTextComponentMouseEventData",
 78   
                     "javax.swing.text.JTextComponent"
 79   
                 });
 80  4
             mapping.add(
 81   
                 new String[] {
 82   
                     "junit.extensions.jfcunit.eventdata.MouseWheelEventData",
 83   
                     "*"
 84   
                 });
 85  4
             mapping.add(
 86   
                 new String[] {
 87   
                     "junit.extensions.jfcunit.eventdata.JMenuMouseEventData",
 88   
                     "*"
 89   
                 });
 90  4
             mapping.add(
 91   
                 new String[] {
 92   
                     "junit.extensions.jfcunit.eventdata.MouseEventData", "*"
 93   
                 });
 94  4
             mapping.add(
 95   
                 new String[] {
 96   
                     "junit.extensions.jfcunit.eventdata.StringEventData", "*"
 97   
                 });
 98  4
             mapping.add(
 99   
                 new String[] {
 100   
                     "junit.extensions.jfcunit.eventdata.KeyEventData", "*"
 101   
                 });
 102   
 
 103  4
             UIManager.put(EVENT_MAPPING_PROPERTY, mapping);
 104   
         }
 105   
     }
 106   
 
 107   
     /**
 108   
      * This is a singleton class. There should never be more than
 109   
      * one recording session.
 110   
      */
 111   
     private static JFCEventManager s_singleton = null;
 112   
 
 113   
     /**
 114   
      * Debug flag set by UIManager property JFCEventManager.debug="true".
 115   
      */
 116   
     private static boolean s_debug = true;
 117   
 
 118   
     /**
 119   
      * AWTEvent inputs.
 120   
      */
 121   
     public static final int DEBUG_INPUT = 1;
 122   
 
 123   
     /**
 124   
      * EventData outputs.
 125   
      */
 126   
     public static final int DEBUG_OUTPUT = 2;
 127   
 
 128   
     /**
 129   
      * EventData creations.
 130   
      */
 131   
     public static final int DEBUG_CREATE = 4;
 132   
 
 133   
     /**
 134   
      * All debugging types.
 135   
      */
 136   
     public static final int DEBUG_ALL = 7;
 137   
 
 138   
     /**
 139   
      * Debugging type to be used.
 140   
      */
 141   
     private static int s_debugType = DEBUG_ALL;
 142   
 
 143   
     /**
 144   
      * Pending event held for consolidation.
 145   
      */
 146   
     private AbstractEventData m_pendingEvent = null;
 147   
 
 148   
     /**
 149   
      * Listener list.
 150   
      */
 151   
     private EventListenerList m_listenerList = new EventListenerList();
 152   
 
 153   
     /**
 154   
      * Timer {@link Thread} used to send the pending event.
 155   
      */
 156   
     private Thread m_timerThread;
 157   
 
 158   
     /**
 159   
      * Recording state.
 160   
      */
 161   
     private boolean m_recording = false;
 162   
 
 163   
     /**
 164   
      * Hold time for the timer thread before
 165   
      * firing the  pending event.
 166   
      */
 167   
     private long m_holdTime;
 168   
 
 169   
     /**
 170   
      * Time when the last event was recorded.
 171   
      */
 172   
     private volatile long m_lastEventTime = 0;
 173   
 
 174   
     /**
 175   
      * Private constructor.
 176   
      * The method <code>getEventManager()</code> should be used instead.
 177   
      *
 178   
      * @param holdTime duration to hold a pending event.
 179   
      */
 180  4
     private JFCEventManager(final long holdTime) {
 181  4
         setHoldTime(holdTime);
 182   
     }
 183   
 
 184   
     /**
 185   
      * Enable/Disable debug tracing of events.
 186   
      *
 187   
      * @param aValue true if debugging is to be
 188   
      * turned on.
 189   
      */
 190  1
     public static void setDebug(final boolean aValue) {
 191  1
         s_debug = aValue;
 192   
 
 193  1
         if (s_debug) {
 194  1
             UIManager.put(EVENT_DEBUG, "true");
 195   
         } else {
 196  0
             UIManager.put(EVENT_DEBUG, "false");
 197   
         }
 198   
     }
 199   
 
 200   
     /**
 201   
      * Get the state of debugging.
 202   
      *
 203   
      * @return true if debugging is enabled.
 204   
      */
 205  43
     public static boolean getDebug() {
 206  43
         Boolean value = null;
 207  43
         Object  prop = UIManager.get(EVENT_DEBUG);
 208   
 
 209  43
         if (prop instanceof Boolean) {
 210  42
             value = (Boolean) prop;
 211  1
         } else if (prop instanceof String) {
 212  1
             value = Boolean.valueOf((String) prop);
 213   
         }
 214   
 
 215  43
         if (value == null) {
 216  0
             s_debug = false;
 217   
         } else {
 218  43
             s_debug = value.booleanValue();
 219   
         }
 220   
 
 221  43
         return s_debug;
 222   
     }
 223   
 
 224   
     /**
 225   
      * Set the debugging type.
 226   
      *
 227   
      * @param type DEBUG_INPUT, DEBUG_OUTPUT and/or DEBUG_CREATE
 228   
      */
 229  120
     public static void setDebugType(final int type) {
 230  120
         s_debugType = type;
 231   
     }
 232   
 
 233   
     /**
 234   
      * Get the debugging type.
 235   
      *
 236   
      * @return sum of current debugging types.
 237   
      */
 238  0
     public static int getDebugType() {
 239  0
         return s_debugType;
 240   
     }
 241   
 
 242   
     /**
 243   
      * Returns a singleton instance of this class. This
 244   
      * method should be used instead of the constructor.
 245   
      * to attempt to consolidate events.
 246   
      *
 247   
      * @return JFCEventManager singleton instance.
 248   
      */
 249  730
     public static JFCEventManager getEventManager() {
 250  730
         return JFCEventManager.getEventManager(DEFAULT_HOLDTIME);
 251   
     }
 252   
 
 253   
     /**
 254   
      * Returns a singleton instance of this class. This
 255   
      * method should be used instead of the constructor.
 256   
      *
 257   
      * @param holdTime druration a event should be held
 258   
      *                  to attempt to consolidate events.
 259   
      *
 260   
      * @return JFCEventManager singleton instance.
 261   
      */
 262  730
     public static JFCEventManager getEventManager(final long holdTime) {
 263  730
         if (s_singleton == null) {
 264  4
             s_singleton = new JFCEventManager(holdTime);
 265   
         }
 266   
 
 267  730
         return s_singleton;
 268   
     }
 269   
 
 270   
     /**
 271   
      * Set the recording state.
 272   
      *
 273   
      * @param recording true if enabled. Otherwise false.
 274   
      */
 275  190
     public static void setRecording(final boolean recording) {
 276  190
         getEventManager().setRecordingImpl(recording);
 277   
     }
 278   
 
 279   
     /**
 280   
      * Set the maximum hold time for a event.
 281   
      *
 282   
      * @param holdTime maximum duration in millis to
 283   
      *  hold a event.
 284   
      */
 285  4
     public void setHoldTime(final long holdTime) {
 286  4
         m_holdTime = holdTime;
 287   
     }
 288   
 
 289   
     /**
 290   
      * Get the maximum hold time for a event.
 291   
      *
 292   
      * @return long maximum hold time.
 293   
      */
 294  160
     public long getHoldTime() {
 295  160
         return m_holdTime;
 296   
     }
 297   
 
 298   
     /**
 299   
      * Get the current recording state.
 300   
      *
 301   
      * @return boolean recording state. True if recording is
 302   
      * enabled.
 303   
      * Otherwise, false.
 304   
      */
 305  0
     public boolean getRecording() {
 306  0
         return m_recording;
 307   
     }
 308   
 
 309   
     /**
 310   
      * Add a listener.
 311   
      *
 312   
      * @param jl Listener to be added.
 313   
      */
 314  43
     public void addJFCEventDataListener(final JFCEventDataListener jl) {
 315  43
         m_listenerList.add(JFCEventDataListener.class, jl);
 316   
     }
 317   
 
 318   
     /**
 319   
      * Converts the event to a drag event if necessary.
 320   
      *
 321   
      * @param ae Event to be processed.
 322   
      * @return true if converted to drag event.
 323   
      */
 324  163
     public boolean convertDrag(final AWTEvent ae) {
 325  163
         if (!(m_pendingEvent instanceof AbstractMouseEventData)
 326   
                 || !(ae instanceof MouseEvent)) {
 327  107
             return false;
 328   
         }
 329   
 
 330  56
         MouseEvent me = (MouseEvent) ae;
 331   
 
 332  56
         if (me.getID() != MouseEvent.MOUSE_DRAGGED) {
 333  29
             return false;
 334   
         }
 335   
 
 336  27
         m_pendingEvent = new DragEventData((JFCTestCase) null,
 337   
                 (AbstractMouseEventData) m_pendingEvent);
 338   
 
 339  27
         return true;
 340   
     }
 341   
 
 342   
     /**
 343   
      * Create a event for the data given.
 344   
      *
 345   
      * @param ae Event to be processed.
 346   
      * @return true if the event is created.
 347   
      */
 348  460
     public AbstractEventData createEvent(final AWTEvent ae) {
 349  460
         Object    source = ae.getSource();
 350   
 
 351  460
         ArrayList mapping = (ArrayList) UIManager.get(EVENT_MAPPING_PROPERTY);
 352  460
         Iterator  iter    = mapping.iterator();
 353   
 
 354  460
         while (iter.hasNext()) {
 355  4153
             String[] map    = (String[]) iter.next();
 356  4153
             Class    target = null;
 357   
 
 358  4153
             try {
 359  4153
                 if (!map[1].equals("*")) {
 360  2867
                     target = Class.forName(map[1]);
 361   
                 } else {
 362  1286
                     target = Object.class;
 363   
                 }
 364   
             } catch (Exception e) {
 365   
                 // don't do anything, but still catch it
 366   
             }
 367   
 
 368  4153
             if (target.isInstance(source)) {
 369   
                 // Attempt to consume event.
 370  1541
                 try {
 371  1541
                     if (s_debug && ((s_debugType & DEBUG_CREATE) > 0)) {
 372  74
                         System.err.println(
 373   
                             "JFCEventManager.createEvent check class:" + map[0]
 374   
                             + " can handle " + ae);
 375   
                     }
 376   
 
 377  1541
                     Class             cls  = Class.forName(map[0]);
 378  1541
                     AbstractEventData data = (AbstractEventData) cls
 379   
                         .newInstance();
 380   
 
 381  1541
                     if (data.canConsume(ae)) {
 382  360
                         return data;
 383   
                     }
 384   
                 } catch (Exception e) {
 385  0
                     System.err.println(
 386   
                         "Exception attempting to create instnce for:" + map[0]);
 387  0
                     e.printStackTrace();
 388   
                 }
 389   
             }
 390   
         }
 391   
 
 392  100
         if (s_debug && ((s_debugType & DEBUG_CREATE) > 0)) {
 393  4
             System.err.println(
 394   
                 "JFCEventManager.createEvent No EventData structure for:" + ae);
 395   
         }
 396   
 
 397  100
         return null;
 398   
     }
 399   
 
 400   
     /**
 401   
      * This method implements the {@link AWTEventListener} interface.
 402   
      * This method will be accessed for every {@link AWTEvent} which is
 403   
      * of the type: MOUSE_MOTION_EVENT, MOUSE_EVENT, KEY_EVENT, or
 404   
      * TEXT_EVENT.
 405   
      *
 406   
      * @param ae Event to be processed.
 407   
      */
 408  7508
     public void eventDispatched(final AWTEvent ae) {
 409  7508
         processEventData(ae);
 410   
     }
 411   
 
 412   
     /**
 413   
      * Remove all listeners.
 414   
      */
 415  120
     public void removeAllJFCEventDataListeners() {
 416  120
         Object[] listeners = m_listenerList.getListenerList();
 417   
 
 418  120
         for (int i = 0; i < listeners.length; i += 2) {
 419  17
             if (listeners[i] == JFCEventDataListener.class) {
 420  17
                 m_listenerList.remove(JFCEventDataListener.class,
 421   
                     (EventListener) listeners[i + 1]);
 422   
             }
 423   
         }
 424   
     }
 425   
 
 426   
     /**
 427   
      * Remove a listener.
 428   
      *
 429   
      * @param jl Listener to be removed.
 430   
      */
 431  26
     public void removeJFCEventDataListener(final JFCEventDataListener jl) {
 432  26
         m_listenerList.remove(JFCEventDataListener.class, jl);
 433   
     }
 434   
 
 435   
     /**
 436   
      * Fire event data to the listeners.
 437   
      */
 438  360
     protected void fireEventData() {
 439  360
         if ((m_pendingEvent != null) && m_pendingEvent.isValid()) {
 440  254
             if (s_debug && ((s_debugType & DEBUG_OUTPUT) > 0)) {
 441  9
                 System.err.println("JFCEventManager.outputEvent:"
 442   
                     + m_pendingEvent);
 443   
             }
 444   
 
 445  254
             Object[] listeners = m_listenerList.getListenerList();
 446   
 
 447  254
             for (int i = listeners.length - 2; i >= 0; i -= 2) {
 448  249
                 if (listeners[i] == JFCEventDataListener.class) {
 449  249
                     ((JFCEventDataListener) listeners[i + 1]).handleEvent(m_pendingEvent);
 450   
                 }
 451   
             }
 452   
         }
 453   
 
 454  360
         m_pendingEvent = null;
 455   
     }
 456   
 
 457   
     /**
 458   
      * This method converts the {@link AWTEvent} to the corresponding
 459   
      * AbstractEventData.
 460   
      *
 461   
      * @param ae AWTEvent to be processed.
 462   
      */
 463  7508
     protected synchronized void processEventData(final AWTEvent ae) {
 464  7508
         if (s_debug && ((s_debugType & DEBUG_INPUT) > 0)) {
 465  226
             System.err.println("JFCEventManager.inputEvent:"
 466   
                 + ((InputEvent) ae).getWhen() + " " + ae);
 467   
         }
 468   
 
 469  7508
         m_lastEventTime = System.currentTimeMillis();
 470   
 
 471  7508
         if (ae instanceof MouseEvent
 472   
                 && (((MouseEvent) ae).getID() == MouseEvent.MOUSE_MOVED)) {
 473  4503
             return;
 474   
         }
 475   
 
 476  3005
         if ((m_pendingEvent != null) && !m_pendingEvent.canConsume(ae)) {
 477  163
             if (!convertDrag(ae)) {
 478  136
                 fireEventData();
 479   
             }
 480   
         }
 481   
 
 482  3005
         if (m_pendingEvent == null) {
 483  460
             m_pendingEvent = createEvent(ae);
 484   
         }
 485   
 
 486  3005
         if (m_pendingEvent != null) {
 487  2905
             m_pendingEvent.consume(ae);
 488  2905
             m_lastEventTime = 0;
 489   
         }
 490   
     }
 491   
 
 492   
     /**
 493   
      * Set the recording state.
 494   
      *
 495   
      * @param recording true if recording is to be enabled.
 496   
      * otherwise false.
 497   
      */
 498  190
     private void setRecordingImpl(final boolean recording) {
 499  190
         if (recording && !(this.m_recording)) {
 500  43
             getDebug();
 501   
 
 502  43
             long wheelMask = 0;
 503   
 
 504  43
             try {
 505  43
                 wheelMask = AWTEvent.class.getField("MOUSE_WHEEL_EVENT_MASK")
 506   
                                           .getLong(null);
 507   
             } catch (Exception e) {
 508  0
                 wheelMask = 0;
 509   
             }
 510   
 
 511  43
             Toolkit.getDefaultToolkit().addAWTEventListener(this,
 512   
                 AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK
 513   
                 | AWTEvent.KEY_EVENT_MASK | AWTEvent.TEXT_EVENT_MASK
 514   
                 | wheelMask);
 515  43
             m_timerThread = new Thread(
 516   
                     new Runnable() {
 517  43
                         public void run() {
 518  43
                             while (m_recording) {
 519  2243
                                 try {
 520  2243
                                     Thread.currentThread().sleep(m_holdTime);
 521   
                                 } catch (InterruptedException ie) {
 522   
                                     // don't do anything, but still catch it
 523   
                                 }
 524   
 
 525  2242
                                 synchronized (JFCEventManager.this) {
 526  2242
                                     long time = System.currentTimeMillis();
 527   
 
 528  2242
                                     if (m_lastEventTime == 0) {
 529  309
                                         m_lastEventTime = System
 530   
                                             .currentTimeMillis();
 531   
                                     }
 532   
 
 533  2242
                                     if ((m_pendingEvent != null)
 534   
                                             && ((time - m_lastEventTime) > m_holdTime)) {
 535  224
                                         fireEventData();
 536   
                                     }
 537   
                                 }
 538   
                             }
 539   
 
 540  42
                             if (m_pendingEvent != null) {
 541  0
                                 fireEventData();
 542   
                             }
 543   
                         }
 544   
                     },
 545   
                     "JFCEventManager Timer");
 546   
 
 547  43
             m_timerThread.start();
 548  43
             this.m_recording = recording;
 549  147
         } else if (!recording && (this.m_recording)) {
 550  42
             Toolkit.getDefaultToolkit().removeAWTEventListener(this);
 551  42
             this.m_recording = recording;
 552  42
             m_timerThread.interrupt();
 553   
 
 554   
             //            try {
 555   
             //              timerThread.join();
 556   
             //            } catch (InterruptedException ie) {
 557   
             //                // don't do anything, but still catch it
 558   
             //            }
 559   
         }
 560   
 
 561  190
         this.m_recording = recording;
 562   
     }
 563   
 }
 564