001: /*
002: * @(#)VirtualWindowController.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.Robot;
030: import java.awt.Window;
031: import java.awt.Dimension;
032: import java.awt.Rectangle;
033:
034: import net.sourceforge.groboutils.uicapture.v1.event.MouseMovedCaptureEvent;
035: import net.sourceforge.groboutils.uicapture.v1.event.MousePressedCaptureEvent;
036: import net.sourceforge.groboutils.uicapture.v1.event.MouseReleasedCaptureEvent;
037: import net.sourceforge.groboutils.uicapture.v1.event.MouseWheelCaptureEvent;
038: import net.sourceforge.groboutils.uicapture.v1.event.KeyPressedCaptureEvent;
039: import net.sourceforge.groboutils.uicapture.v1.event.KeyReleasedCaptureEvent;
040:
041: import java.io.File;
042: import java.io.IOException;
043:
044: /**
045: * A window which covers the whole screen, and does not paint in the background.
046: * It captures keyboard and mouse events, and sends them to both all registered
047: * listeners, and to the underlying GUI as well.
048: *
049: * WARNING: if the screen size is to resize, then this will not work correctly.
050: *
051: * @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
052: * @version Jan 4, 2002
053: */
054: public class VirtualWindowController {
055: //-------------------------------------------------------------------------
056: // Private fields
057:
058: private VirtualWindow window = null;
059: private IScreenScraper ss = null;
060: private IFocusedWindowFinder fwf = null;
061:
062: private static final long MAX_ROBOT_DELAY = 60000L;
063:
064: //-------------------------------------------------------------------------
065: // Constructors
066:
067: /**
068: * Uses the Default version for the IScreenScraper and IFocusedWindowFinder.
069: */
070: public VirtualWindowController() {
071: this (new DefaultScreenScraper(),
072: new DefaultFocusedWindowFinder());
073: }
074:
075: /**
076: * Create using the given arguments to build the framework.
077: */
078: public VirtualWindowController(IScreenScraper ss,
079: IFocusedWindowFinder fwf) {
080: this .ss = ss;
081: this .fwf = fwf;
082: }
083:
084: //-------------------------------------------------------------------------
085: // Public methods
086:
087: /**
088: * Begin the reinactment process.
089: *
090: * @exception java.awt.AWTException thrown if a Robot is not supported
091: * in the current JDK implementation.
092: */
093: public void begin() throws java.awt.AWTException {
094: assertInactive();
095: this .window = new VirtualWindow(null, false);
096: }
097:
098: /**
099: * Complete the reinactment process.
100: */
101: public void end() {
102: assertActive();
103: this .window.dispose();
104: this .window = null;
105: }
106:
107: /**
108: * Pause for a period of milliseconds. Since Robot can only delay for
109: * 60 seconds at a time, this will first sleep using the Robot, then
110: * will use Thread for the remainder of the time.
111: *
112: * @param milliseconds Time in milliseconds to sleep.
113: */
114: public void sleep(long milliseconds) {
115: assertActive();
116:
117: int ms = (milliseconds > MAX_ROBOT_DELAY ? (int) MAX_ROBOT_DELAY
118: : (int) milliseconds);
119: long remainder = milliseconds - ms;
120:
121: this .window.delay(ms);
122: if (remainder > 0) {
123: try {
124: Thread.sleep(remainder);
125: } catch (InterruptedException ie) {
126: // ignore
127: }
128: }
129: }
130:
131: /**
132: * Waits until all events currently on the event queue have been processed.
133: */
134: public void waitForIdle() {
135: assertActive();
136: this .window.waitForIdle();
137: }
138:
139: /**
140: * Retrieves the size and position of the capture area of the screen.
141: *
142: * @return the screen size.
143: */
144: public Rectangle getBounds() {
145: assertActive();
146: return this .window.getWindow().getCoveredScreen();
147: }
148:
149: /**
150: * Compares the two files for identity.
151: *
152: * @return <tt>true</tt> if the files are identical, else <tt>false</tt>.
153: */
154: public boolean compareFiles(File one, File two) throws IOException {
155: throw new IllegalStateException("Not implemented yet.");
156: }
157:
158: public String getImageExtension() {
159: return this .ss.getFileExtention();
160: }
161:
162: /**
163: * Saves the entire screen to a file.
164: *
165: * @param filename the file to save the image as.
166: * @exception IOException thrown if there was a problem writing the file.
167: */
168: public void saveScreen(String filename) throws IOException {
169: assertActive();
170: saveScreenImage(filename, new Rectangle(getBounds()));
171: }
172:
173: /**
174: * Saves a picture of the underlying UI's focused window to a file.
175: *
176: * @param filename the file to save the image as.
177: * @exception IOException thrown if there was a problem writing the file.
178: */
179: public void saveFocusedWindow(String filename) throws IOException {
180: assertActive();
181: Rectangle bounds = this .fwf.getFocusedWindowBounds();
182: if (bounds == null) {
183: // save the entire screen
184: saveScreen(filename);
185: } else {
186: saveScreenImage(filename, bounds);
187: }
188: }
189:
190: /**
191: * Saves the selected screen part to a file.
192: *
193: * @param filename the file to save the image as.
194: * @param x the x position of the part of the screen to grab.
195: * @param y the y position of the part of the screen to grab.
196: * @param w the width of the part of the screen to grab.
197: * @param h the height of the part of the screen to grab.
198: * @exception IOException thrown if there was a problem writing the file.
199: */
200: public void saveScreenImage(String filename, int x, int y, int w,
201: int h) throws IOException {
202: saveScreenImage(filename, new Rectangle(x, y, w, h));
203: }
204:
205: /**
206: * Saves the selected screen part to a file.
207: *
208: * @param filename the file to save the image as.
209: * @param bounds the part of the screen to grab.
210: * @exception IOException thrown if there was a problem writing the file.
211: */
212: public void saveScreenImage(String filename, Rectangle bounds)
213: throws IOException {
214: assertActive();
215: this .ss.writeImageToFile(
216: this .window.createScreenScrape(bounds), new File(
217: filename));
218: }
219:
220: //-------------------------------------------------------------------------
221: // Event methods
222:
223: /**
224: * Simulate a mouse movement.
225: *
226: * @param x the x position (aboslute) to move the mouse to.
227: * @param y the y position (aboslute) to move the mouse to.
228: */
229: public void moveMouse(int x, int y) {
230: assertActive();
231: MouseMovedCaptureEvent ce = new MouseMovedCaptureEvent(x, y);
232: this .window.simulateEvent(ce);
233: }
234:
235: /**
236: * Simulate a mouse button press.
237: *
238: * @param modifiers the mouse button modifiers.
239: */
240: public void pressMouse(int modifiers) {
241: assertActive();
242: MousePressedCaptureEvent ce = new MousePressedCaptureEvent(
243: modifiers);
244: this .window.simulateEvent(ce);
245: }
246:
247: /**
248: * Simulate a mouse button release.
249: *
250: * @param modifiers the mouse button modifiers.
251: */
252: public void releaseMouse(int modifiers) {
253: assertActive();
254: MouseReleasedCaptureEvent ce = new MouseReleasedCaptureEvent(
255: modifiers);
256: this .window.simulateEvent(ce);
257: }
258:
259: /**
260: * Simulate a mouse wheel rotation.
261: *
262: * @param rotation the number of 'clicks' to rotate the mouse wheel.
263: */
264: public void rotateMouseWheel(int rotation) {
265: assertActive();
266: MouseWheelCaptureEvent ce = new MouseWheelCaptureEvent(rotation);
267: this .window.simulateEvent(ce);
268: }
269:
270: /**
271: * Simulate a key press.
272: *
273: * @param keyCode the key code of the key.
274: */
275: public void pressKey(int keyCode) {
276: assertActive();
277: KeyPressedCaptureEvent ce = new KeyPressedCaptureEvent(keyCode);
278: this .window.simulateEvent(ce);
279: }
280:
281: /**
282: * Simulate a key release.
283: *
284: * @param keyCode the key code of the key.
285: */
286: public void releaseKey(int keyCode) {
287: assertActive();
288: KeyReleasedCaptureEvent ce = new KeyReleasedCaptureEvent(
289: keyCode);
290: this .window.simulateEvent(ce);
291: }
292:
293: //-------------------------------------------------------------------------
294: // Protected methods
295:
296: protected void assertActive() {
297: if (this .window == null) {
298: throw new IllegalStateException("Window is not active.");
299: }
300: }
301:
302: protected void assertInactive() {
303: if (this .window != null) {
304: throw new IllegalStateException("Window is active.");
305: }
306: }
307: }
|