001: /*
002: * @(#)ScriptGenerator.java
003: *
004: * Copyright (C) 2002-2003 Matt Albrecht
005: * groboclown@users.sourceforge.net
006: * http://groboutils.sourceforge.net
007: *
008: * Permission is hereby granted, free of charge, to any person obtaining a
009: * copy of this software and associated documentation files (the "Software"),
010: * to deal in the Software without restriction, including without limitation
011: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
012: * and/or sell copies of the Software, and to permit persons to whom the
013: * Software is furnished to do so, subject to the following conditions:
014: *
015: * The above copyright notice and this permission notice shall be included in
016: * all copies or substantial portions of the Software.
017: *
018: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
019: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
020: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
021: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
022: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
023: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
024: * DEALINGS IN THE SOFTWARE.
025: */
026:
027: package net.sourceforge.groboutils.uicapture.v1;
028:
029: import java.awt.Rectangle;
030:
031: import java.io.File;
032: import java.io.IOException;
033:
034: import net.sourceforge.groboutils.uicapture.v1.event.ICaptureListener;
035: import net.sourceforge.groboutils.uicapture.v1.event.CaptureEvent;
036: import net.sourceforge.groboutils.uicapture.v1.event.MouseWheelCaptureEvent;
037: import net.sourceforge.groboutils.uicapture.v1.event.MouseMovedCaptureEvent;
038: import net.sourceforge.groboutils.uicapture.v1.event.MouseButtonCaptureEvent;
039: import net.sourceforge.groboutils.uicapture.v1.event.MousePressedCaptureEvent;
040: import net.sourceforge.groboutils.uicapture.v1.event.MouseReleasedCaptureEvent;
041: import net.sourceforge.groboutils.uicapture.v1.event.KeyCaptureEvent;
042: import net.sourceforge.groboutils.uicapture.v1.event.KeyPressedCaptureEvent;
043: import net.sourceforge.groboutils.uicapture.v1.event.KeyReleasedCaptureEvent;
044: import net.sourceforge.groboutils.uicapture.v1.event.IAllowCapturePassThroughListener;
045:
046: /**
047: * Listens to CaptureEvents, and converts these into script commands to the
048: * IScriptMaker. It allows for easy subclassing through having a "Meta-Mode".
049: * All events will be swallowed (not passed to the UI or IScriptMaker)
050: * while in this meta-mode.
051: *
052: * @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
053: * @version Jan 7, 2002
054: */
055: public class ScriptGenerator implements ICaptureListener,
056: IAllowCapturePassThroughListener {
057: private IScriptMaker maker = null;
058: private boolean metaMode = false;
059: private long lastEventTime = -1;
060: private VirtualWindow window = null;
061: private IScreenScraper ss = null;
062: private IFocusedWindowFinder fwf = null;
063: private String baseImageName = null;
064: private int filenameIndex = 0;
065: private boolean isRunning = false;
066:
067: //-------------------------------------------------------------------------
068: // Constructors
069:
070: /**
071: * Uses the Default version for the IScreenScraper and IFocusedWindowFinder.
072: */
073: public ScriptGenerator(IScriptMaker maker, String baseImageName) {
074: this (new DefaultScreenScraper(),
075: new DefaultFocusedWindowFinder(), maker, baseImageName);
076: }
077:
078: /**
079: * Create using the given arguments to build the framework.
080: */
081: public ScriptGenerator(IScreenScraper ss, IFocusedWindowFinder fwf,
082: IScriptMaker maker, String baseImageName) {
083: this .ss = ss;
084: this .fwf = fwf;
085: this .maker = maker;
086: this .baseImageName = baseImageName;
087: }
088:
089: //-------------------------------------------------------------------------
090: // Public Methods
091:
092: /*
093: * Should this be here ????
094: public VirtualWindow getVirtualWindow()
095: {
096: return this.window;
097: }
098: */
099:
100: /**
101: *
102: * @exception java.awt.AWTException Robot isn't supported.
103: */
104: public void begin() throws java.awt.AWTException {
105: this .window = new VirtualWindow(null, true);
106: this .window.addCaptureListener(this );
107: this .maker.start();
108: this .isRunning = true;
109: }
110:
111: public void end() {
112: this .isRunning = false;
113: fireStop();
114: }
115:
116: public boolean isRunning() {
117: return this .isRunning;
118: }
119:
120: //-------------------------------------------------------------------------
121: // Meta Methods
122:
123: /**
124: *
125: */
126: public boolean isInMetaMode() {
127: return this .metaMode;
128: }
129:
130: /**
131: *
132: */
133: public void setInMetaMode(boolean set) {
134: this .metaMode = set;
135: }
136:
137: /**
138: * Performs a meta-mode action when this event is caught and the
139: * generator is in meta-mode. Default action does nothing.
140: */
141: protected void metaMouseWheelMoved(MouseWheelCaptureEvent ce) {
142: // do nothing
143: }
144:
145: /**
146: * Performs a meta-mode action when this event is caught and the
147: * generator is in meta-mode. Default action does nothing.
148: */
149: protected void metaMousePressed(MousePressedCaptureEvent ce) {
150: // do nothing
151: }
152:
153: /**
154: * Performs a meta-mode action when this event is caught and the
155: * generator is in meta-mode. Default action does nothing.
156: */
157: protected void metaMouseReleased(MouseReleasedCaptureEvent ce) {
158: // do nothing
159: }
160:
161: /**
162: * Performs a meta-mode action when this event is caught and the
163: * generator is in meta-mode. Default action does nothing.
164: */
165: protected void metaKeyPressed(KeyPressedCaptureEvent ce) {
166: // do nothing
167: }
168:
169: /**
170: * Performs a meta-mode action when this event is caught and the
171: * generator is in meta-mode. Default action does nothing.
172: */
173: protected void metaKeyReleased(KeyReleasedCaptureEvent ce) {
174: // do nothing
175: }
176:
177: /**
178: * Performs a meta-mode action when this event is caught and the
179: * generator is in meta-mode. Default action does nothing.
180: */
181: protected void metaMouseMoved(MouseMovedCaptureEvent ce) {
182: // do nothing
183: }
184:
185: //-------------------------------------------------------------------------
186: // Fire ScriptMaker Event Methods
187:
188: /**
189: *
190: */
191: protected synchronized void fireStop() {
192: if (this .window != null) {
193: this .window.removeCaptureListener(this );
194:
195: if (isRunning()) {
196: this .maker.end();
197: }
198:
199: this .window.dispose();
200: this .window = null;
201: }
202: }
203:
204: /**
205: * Saves the entire screen to a file.
206: *
207: * @param filename the file to save the image as.
208: */
209: protected synchronized void fireSaveScreen() {
210: if (isRunning()) {
211: fireSaveScreenImage(new Rectangle(this .window.getWindow()
212: .getCoveredScreen()));
213: }
214: }
215:
216: /**
217: * Saves a picture of the underlying UI's focused window to a file.
218: *
219: * @param filename the file to save the image as.
220: */
221: protected synchronized void fireSaveFocusedWindow() {
222: if (isRunning()) {
223: Rectangle bounds = this .fwf.getFocusedWindowBounds();
224: if (bounds == null) {
225: // save the entire screen
226: fireSaveScreen();
227: } else {
228: fireSaveScreenImage(bounds);
229: }
230: }
231: }
232:
233: /**
234: * Saves the selected screen part to a file.
235: *
236: * @param filename the file to save the image as.
237: * @param x the x position of the part of the screen to grab.
238: * @param y the y position of the part of the screen to grab.
239: * @param w the width of the part of the screen to grab.
240: * @param h the height of the part of the screen to grab.
241: */
242: protected synchronized void fireSaveScreenImage(int x, int y,
243: int w, int h) {
244: if (isRunning()) {
245: fireSaveScreenImage(new Rectangle(x, y, w, h));
246: }
247: }
248:
249: /**
250: * Saves the selected screen part to a file.
251: *
252: * @param filename the file to save the image as.
253: * @param bounds the part of the screen to grab.
254: */
255: protected synchronized void fireSaveScreenImage(Rectangle bounds) {
256: if (isRunning()) {
257: File f = createFile();
258: try {
259: this .ss.writeImageToFile(this .window
260: .createScreenScrape(bounds), f);
261: this .maker.generateScreenCapture(f, bounds.x, bounds.y,
262: bounds.width, bounds.height);
263: } catch (IOException ioe) {
264: encounteredError(ioe);
265: }
266: }
267: }
268:
269: /**
270: *
271: */
272: protected synchronized void fireMouseWheelMoved(
273: MouseWheelCaptureEvent ce) {
274: if (isRunning()) {
275: generateDelay(ce);
276: this .maker.generateMoveMouseWheel(ce.getWheelRotation());
277: }
278: }
279:
280: /**
281: *
282: */
283: protected synchronized void fireMouseMoved(MouseMovedCaptureEvent ce) {
284: if (isRunning()) {
285: generateDelay(ce);
286: this .maker.generateMoveMouse(ce.getX(), ce.getY());
287: }
288: }
289:
290: /**
291: *
292: */
293: protected synchronized void fireMousePressed(
294: MouseButtonCaptureEvent ce) {
295: if (isRunning()) {
296: generateDelay(ce);
297: this .maker.generatePressMouse(ce.getModifiers());
298: }
299: }
300:
301: /**
302: *
303: */
304: protected synchronized void fireMouseReleased(
305: MouseButtonCaptureEvent ce) {
306: if (isRunning()) {
307: generateDelay(ce);
308: this .maker.generateReleaseMouse(ce.getModifiers());
309: }
310: }
311:
312: /**
313: *
314: */
315: protected synchronized void fireKeyPressed(KeyCaptureEvent ce) {
316: if (isRunning()) {
317: generateDelay(ce);
318: this .maker.generatePressKey(ce.getKeyCode());
319: }
320: }
321:
322: /**
323: *
324: */
325: protected synchronized void fireKeyReleased(KeyCaptureEvent ce) {
326: if (isRunning()) {
327: generateDelay(ce);
328: this .maker.generateReleaseKey(ce.getKeyCode());
329: }
330: }
331:
332: //-------------------------------------------------------------------------
333: // Event Methods
334:
335: /**
336: * If a subclass overrides this method, it <b>must</b> first check
337: * if meta-mode is enabled, and invoke
338: * the super's version of this method at the very end (right before
339: * leaving the method).
340: */
341: public void mouseWheelMoved(MouseWheelCaptureEvent ce) {
342: if (allowMouseWheelMoved(ce)) {
343: fireMouseWheelMoved(ce);
344: } else {
345: metaMouseWheelMoved(ce);
346: }
347: }
348:
349: /**
350: * If a subclass overrides this method, it <b>must</b> first check
351: * if meta-mode is enabled, and invoke
352: * the super's version of this method at the very end (right before
353: * leaving the method).
354: */
355: public void mouseMoved(MouseMovedCaptureEvent ce) {
356: if (allowMouseMoved(ce)) {
357: fireMouseMoved(ce);
358: } else {
359: metaMouseMoved(ce);
360: }
361: }
362:
363: /**
364: * If a subclass overrides this method, it <b>must</b> first check
365: * if meta-mode is enabled, and invoke
366: * the super's version of this method at the very end (right before
367: * leaving the method).
368: */
369: public void mousePressed(MousePressedCaptureEvent ce) {
370: if (allowMousePressed(ce)) {
371: fireMousePressed(ce);
372: } else {
373: metaMousePressed(ce);
374: }
375: }
376:
377: /**
378: * If a subclass overrides this method, it <b>must</b> first check
379: * if meta-mode is enabled, and invoke
380: * the super's version of this method at the very end (right before
381: * leaving the method).
382: */
383: public void mouseReleased(MouseReleasedCaptureEvent ce) {
384: if (allowMouseReleased(ce)) {
385: fireMouseReleased(ce);
386: } else {
387: metaMouseReleased(ce);
388: }
389: }
390:
391: /**
392: * If a subclass overrides this method, it <b>must</b> first check
393: * if meta-mode is enabled, and invoke
394: * the super's version of this method at the very end (right before
395: * leaving the method).
396: */
397: public void keyPressed(KeyPressedCaptureEvent ce) {
398: if (allowKeyPressed(ce)) {
399: fireKeyPressed(ce);
400: } else {
401: metaKeyPressed(ce);
402: }
403: }
404:
405: /**
406: * If a subclass overrides this method, it <b>must</b> first check
407: * if meta-mode is enabled, and invoke
408: * the super's version of this method at the very end (right before
409: * leaving the method).
410: */
411: public void keyReleased(KeyReleasedCaptureEvent ce) {
412: if (allowKeyReleased(ce)) {
413: fireKeyReleased(ce);
414: } else {
415: metaKeyReleased(ce);
416: }
417: }
418:
419: //-------------
420:
421: /**
422: * @see java.awt.event.MouseWheelListener
423: *
424: * @return <tt>true</tt> to allow the event to passed to the underlying
425: * UI, or <tt>false</tt> to 'swallow' the event.
426: */
427: public final boolean allowMouseWheelMoved(MouseWheelCaptureEvent ce) {
428: return !isInMetaMode();
429: }
430:
431: /**
432: * @see java.awt.event.MouseListener
433: *
434: * @return <tt>true</tt> to allow the event to passed to the underlying
435: * UI, or <tt>false</tt> to 'swallow' the event.
436: */
437: public final boolean allowMousePressed(MousePressedCaptureEvent ce) {
438: return !isInMetaMode();
439: }
440:
441: /**
442: * @see java.awt.event.MouseListener
443: *
444: * @return <tt>true</tt> to allow the event to passed to the underlying
445: * UI, or <tt>false</tt> to 'swallow' the event.
446: */
447: public final boolean allowMouseReleased(MouseReleasedCaptureEvent ce) {
448: return !isInMetaMode();
449: }
450:
451: /**
452: * @see java.awt.event.KeyListener
453: *
454: * @return <tt>true</tt> to allow the event to passed to the underlying
455: * UI, or <tt>false</tt> to 'swallow' the event.
456: */
457: public final boolean allowKeyPressed(KeyPressedCaptureEvent ce) {
458: return !isInMetaMode();
459: }
460:
461: /**
462: * @see java.awt.event.KeyListener
463: *
464: * @return <tt>true</tt> to allow the event to passed to the underlying
465: * UI, or <tt>false</tt> to 'swallow' the event.
466: */
467: public final boolean allowKeyReleased(KeyReleasedCaptureEvent ce) {
468: return !isInMetaMode();
469: }
470:
471: /**
472: * Not part of the allow interface.
473: *
474: * @return <tt>true</tt> to allow the event to passed to the underlying
475: * UI, or <tt>false</tt> to 'swallow' the event.
476: */
477: public final boolean allowMouseMoved(MouseMovedCaptureEvent ce) {
478: return !isInMetaMode();
479: }
480:
481: //-------------------------------------------------------------------------
482: // Misc Protected Methods
483:
484: /**
485: * Create a delay event in the script maker.
486: */
487: protected void generateDelay(CaptureEvent ce) {
488: long delay = getDelayTime(ce);
489: if (delay > 0) {
490: this .maker.generateDelay(delay);
491: }
492: }
493:
494: /**
495: * Calculate the amount of time between the last event and the given
496: * event.
497: *
498: * @return the delay time in milliseconds.
499: */
500: protected synchronized long getDelayTime(CaptureEvent ce) {
501: long waitTime = ce.getTimeOfEvent();
502: if (this .lastEventTime < 0) {
503: this .lastEventTime = waitTime;
504: return 0;
505: }
506: if (waitTime < 0 || waitTime < this .lastEventTime) {
507: return 0;
508: }
509: long diff = waitTime - this .lastEventTime;
510: this .lastEventTime = waitTime;
511: return diff;
512: }
513:
514: /**
515: *
516: */
517: protected synchronized File createFile() {
518: File f = new File(this .baseImageName + this .filenameIndex + '.'
519: + this .ss.getFileExtention());
520: ++this .filenameIndex;
521:
522: return f;
523: }
524:
525: /**
526: *
527: */
528: protected void encounteredError(Throwable t) {
529: t.printStackTrace();
530: }
531: }
|