package org.eclipse.swt.printing; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved | |
*/ | |
import org.eclipse.swt.*; | |
import org.eclipse.swt.graphics.*; | |
import org.eclipse.swt.internal.*; | |
import org.eclipse.swt.internal.win32.*; | |
/** | |
* Instances of this class are used to print to a printer. | |
* Applications create a GC on a printer using <code>new GC(printer)</code> | |
* and then draw on the printer GC using the usual graphics calls. | |
* <p> | |
* A <code>Printer</code> object may be constructed by providing | |
* a <code>PrinterData</code> object which identifies the printer. | |
* A <code>PrintDialog</code> presents a print dialog to the user | |
* and returns an initialized instance of <code>PrinterData</code>. | |
* Alternatively, calling <code>new Printer()</code> will construct a | |
* printer object for the user's default printer. | |
* </p><p> | |
* Application code must explicitly invoke the <code>Printer.dispose()</code> | |
* method to release the operating system resources managed by each instance | |
* when those instances are no longer required. | |
* </p> | |
* | |
* @see PrinterData | |
* @see PrintDialog | |
*/ | |
public final class Printer extends Device { | |
/** | |
* the handle to the printer DC | |
* (Warning: This field is platform dependent) | |
*/ | |
public int handle; | |
/** | |
* the printer data describing this printer | |
*/ | |
PrinterData data; | |
/** | |
* whether or not a GC was created for this printer | |
*/ | |
boolean isGCCreated = false; | |
/** | |
* strings used to access the Windows registry | |
* (Warning: These fields are platform dependent) | |
*/ | |
static TCHAR profile; | |
static TCHAR appName; | |
static TCHAR keyName; | |
static { | |
profile = new TCHAR(0, "PrinterPorts", true); | |
appName = new TCHAR(0, "windows", true); | |
keyName = new TCHAR(0, "device", true); | |
} | |
/** | |
* Returns an array of <code>PrinterData</code> objects | |
* representing all available printers. | |
* | |
* @return the list of available printers | |
*/ | |
public static PrinterData[] getPrinterList() { | |
int length = 1024; | |
/* Use the character encoding for the default locale */ | |
TCHAR buf = new TCHAR(0, length); | |
TCHAR nullBuf = new TCHAR(0, 1); | |
int n = OS.GetProfileString(profile, null, nullBuf, buf, length); | |
if (n == 0) return new PrinterData[0]; | |
String[] deviceNames = new String[5]; | |
int nameCount = 0; | |
int index = 0; | |
for (int i = 0; i < n; i++) { | |
if (buf.tcharAt(i) == 0) { | |
if (nameCount == deviceNames.length) { | |
String[] newNames = new String[deviceNames.length + 5]; | |
System.arraycopy(deviceNames, 0, newNames, 0, deviceNames.length); | |
deviceNames = newNames; | |
} | |
deviceNames[nameCount] = buf.toString(index, i - index); | |
nameCount++; | |
index = i + 1; | |
} | |
} | |
PrinterData printerList[] = new PrinterData[nameCount]; | |
for (int p = 0; p < nameCount; p++) { | |
String device = deviceNames[p]; | |
String driver = ""; | |
if (OS.GetProfileString(profile, new TCHAR(0, device, true), nullBuf, buf, length) > 0) { | |
int commaIndex = 0; | |
while (buf.tcharAt(commaIndex) != ',' && commaIndex < length) commaIndex++; | |
if (commaIndex < length) { | |
driver = buf.toString(0, commaIndex); | |
} | |
} | |
printerList[p] = new PrinterData(driver, device); | |
} | |
return printerList; | |
} | |
/* | |
* Returns a <code>PrinterData</code> object representing | |
* the default printer. | |
* | |
* @exception SWTError <ul> | |
* <li>ERROR_NO_HANDLES - if an error occurred constructing the default printer data</li> | |
* </ul> | |
* | |
* @return the default printer data | |
*/ | |
static PrinterData getDefaultPrinterData() { | |
String deviceName = null; | |
int length = 1024; | |
/* Use the character encoding for the default locale */ | |
TCHAR buf = new TCHAR(0, length); | |
TCHAR nullBuf = new TCHAR(0, 1); | |
int n = OS.GetProfileString(appName, keyName, nullBuf, buf, length); | |
if (n == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
int commaIndex = 0; | |
while(buf.tcharAt(commaIndex) != ',' && commaIndex < length) commaIndex++; | |
if (commaIndex < length) { | |
deviceName = buf.toString(0, commaIndex); | |
} | |
String driver = ""; | |
if (OS.GetProfileString(profile, new TCHAR(0, deviceName, true), nullBuf, buf, length) > 0) { | |
commaIndex = 0; | |
while (buf.tcharAt(commaIndex) != ',' && commaIndex < length) commaIndex++; | |
if (commaIndex < length) { | |
driver = buf.toString(0, commaIndex); | |
} | |
} | |
return new PrinterData(driver, deviceName); | |
} | |
/** | |
* Constructs a new printer representing the default printer. | |
* <p> | |
* You must dispose the printer when it is no longer required. | |
* </p> | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_UNSPECIFIED - if there are no valid printers | |
* </ul> | |
* | |
* @see #dispose | |
*/ | |
public Printer() { | |
this(getDefaultPrinterData()); | |
} | |
/** | |
* Constructs a new printer given a <code>PrinterData</code> | |
* object representing the desired printer. | |
* <p> | |
* You must dispose the printer when it is no longer required. | |
* </p> | |
* | |
* @param data the printer data for the specified printer | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_INVALID_ARGUMENT - if the specified printer data does not represent a valid printer | |
* <li>ERROR_UNSPECIFIED - if there are no valid printers | |
* </ul> | |
* | |
* @see #dispose | |
*/ | |
public Printer(PrinterData data) { | |
super(data); | |
} | |
/** | |
* Creates the printer handle. | |
* This method is called internally by the instance creation | |
* mechanism of the <code>Device</code> class. | |
*/ | |
protected void create(DeviceData deviceData) { | |
data = (PrinterData)deviceData; | |
/* Use the character encoding for the default locale */ | |
TCHAR driver = new TCHAR(0, data.driver, true); | |
TCHAR device = new TCHAR(0, data.name, true); | |
int lpInitData = 0; | |
byte buffer [] = data.otherData; | |
int hHeap = OS.GetProcessHeap(); | |
if (buffer != null && buffer.length != 0) { | |
lpInitData = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, buffer.length); | |
OS.MoveMemory(lpInitData, buffer, buffer.length); | |
} | |
handle = OS.CreateDC(driver, device, 0, lpInitData); | |
if (lpInitData != 0) OS.HeapFree(hHeap, 0, lpInitData); | |
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
} | |
/** | |
* Invokes platform specific functionality to allocate a new GC handle. | |
* <p> | |
* <b>IMPORTANT:</b> This method is <em>not</em> part of the public | |
* API for <code>Printer</code>. It is marked public only so that it | |
* can be shared within the packages provided by SWT. It is not | |
* available on all platforms, and should never be called from | |
* application code. | |
* </p> | |
* | |
* @param data the platform specific GC data | |
* @return the platform specific GC handle | |
* | |
* @private | |
*/ | |
public int internal_new_GC(GCData data) { | |
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
if (data != null) { | |
if (isGCCreated) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
data.device = this; | |
data.hFont = OS.GetCurrentObject(handle, OS.OBJ_FONT); | |
isGCCreated = true; | |
} | |
return handle; | |
} | |
/** | |
* Invokes platform specific functionality to dispose a GC handle. | |
* <p> | |
* <b>IMPORTANT:</b> This method is <em>not</em> part of the public | |
* API for <code>Printer</code>. It is marked public only so that it | |
* can be shared within the packages provided by SWT. It is not | |
* available on all platforms, and should never be called from | |
* application code. | |
* </p> | |
* | |
* @param handle the platform specific GC handle | |
* @param data the platform specific GC data | |
* | |
* @private | |
*/ | |
public void internal_dispose_GC(int hDC, GCData data) { | |
if (data != null) isGCCreated = false; | |
} | |
/** | |
* Starts a print job and returns true if the job started successfully | |
* and false otherwise. | |
* <p> | |
* This must be the first method called to initiate a print job, | |
* followed by any number of startPage/endPage calls, followed by | |
* endJob. Calling startPage, endPage, or endJob before startJob | |
* will result in undefined behavior. | |
* </p> | |
* | |
* @return true if the job started successfully and false otherwise. | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> | |
* </ul> | |
* | |
* @see #startPage | |
* @see #endPage | |
* @see #endJob | |
*/ | |
public boolean startJob(String jobName) { | |
checkDevice(); | |
DOCINFO di = new DOCINFO(); | |
di.cbSize = DOCINFO.sizeof; | |
int hHeap = OS.GetProcessHeap(); | |
int lpszDocName = 0; | |
if (jobName != null && jobName.length() != 0) { | |
/* Use the character encoding for the default locale */ | |
TCHAR buffer = new TCHAR(0, jobName, true); | |
int byteCount = buffer.length() * TCHAR.sizeof; | |
lpszDocName = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount); | |
OS.MoveMemory(lpszDocName, buffer, byteCount); | |
di.lpszDocName = lpszDocName; | |
} | |
int lpszOutput = 0; | |
if (data.printToFile && data.fileName != null) { | |
/* Use the character encoding for the default locale */ | |
TCHAR buffer = new TCHAR(0, data.fileName, true); | |
int byteCount = buffer.length() * TCHAR.sizeof; | |
lpszOutput = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount); | |
OS.MoveMemory(lpszOutput, buffer, byteCount); | |
di.lpszOutput = lpszOutput; | |
} | |
int rc = OS.StartDoc(handle, di); | |
if (lpszDocName != 0) OS.HeapFree(hHeap, 0, lpszDocName); | |
if (lpszOutput != 0) OS.HeapFree(hHeap, 0, lpszOutput); | |
return rc > 0; | |
} | |
/** | |
* Ends the current print job. | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> | |
* </ul> | |
* | |
* @see #startJob | |
* @see #startPage | |
* @see #endPage | |
*/ | |
public void endJob() { | |
checkDevice(); | |
OS.EndDoc(handle); | |
} | |
/** | |
* Cancels a print job in progress. | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> | |
* </ul> | |
*/ | |
public void cancelJob() { | |
checkDevice(); | |
OS.AbortDoc(handle); | |
} | |
/** | |
* Starts a page and returns true if the page started successfully | |
* and false otherwise. | |
* <p> | |
* After calling startJob, this method may be called any number of times | |
* along with a matching endPage. | |
* </p> | |
* | |
* @return true if the page started successfully and false otherwise. | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> | |
* </ul> | |
* | |
* @see #endPage | |
* @see #startJob | |
* @see #endJob | |
*/ | |
public boolean startPage() { | |
checkDevice(); | |
int rc = OS.StartPage(handle); | |
if (rc <= 0) OS.AbortDoc(handle); | |
return rc > 0; | |
} | |
/** | |
* Ends the current page. | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> | |
* </ul> | |
* | |
* @see #startPage | |
* @see #startJob | |
* @see #endJob | |
*/ | |
public void endPage() { | |
checkDevice(); | |
OS.EndPage(handle); | |
} | |
/** | |
* Returns a point whose x coordinate is the horizontal | |
* dots per inch of the printer, and whose y coordinate | |
* is the vertical dots per inch of the printer. | |
* | |
* @return the horizontal and vertical DPI | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> | |
* </ul> | |
*/ | |
public Point getDPI() { | |
checkDevice(); | |
int dpiX = OS.GetDeviceCaps(handle, OS.LOGPIXELSX); | |
int dpiY = OS.GetDeviceCaps(handle, OS.LOGPIXELSY); | |
return new Point(dpiX, dpiY); | |
} | |
/** | |
* Returns a rectangle describing the receiver's size and location. | |
* For a printer, this is the size of a page, in pixels. | |
* | |
* @return the bounding rectangle | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> | |
* </ul> | |
* | |
* @see #getClientArea | |
* @see #computeTrim | |
*/ | |
public Rectangle getBounds() { | |
checkDevice(); | |
int width = OS.GetDeviceCaps(handle, OS.PHYSICALWIDTH); | |
int height = OS.GetDeviceCaps(handle, OS.PHYSICALHEIGHT); | |
return new Rectangle(0, 0, width, height); | |
} | |
/** | |
* Returns a rectangle which describes the area of the | |
* receiver which is capable of displaying data. | |
* For a printer, this is the size of the printable area | |
* of a page, in pixels. | |
* | |
* @return the client area | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> | |
* </ul> | |
* | |
* @see #getBounds | |
* @see #computeTrim | |
*/ | |
public Rectangle getClientArea() { | |
checkDevice(); | |
int width = OS.GetDeviceCaps(handle, OS.HORZRES); | |
int height = OS.GetDeviceCaps(handle, OS.VERTRES); | |
return new Rectangle(0, 0, width, height); | |
} | |
/** | |
* Given a desired <em>client area</em> for the receiver | |
* (as described by the arguments), returns the bounding | |
* rectangle which would be required to produce that client | |
* area. | |
* <p> | |
* In other words, it returns a rectangle such that, if the | |
* receiver's bounds were set to that rectangle, the area | |
* of the receiver which is capable of displaying data | |
* (that is, not covered by the "trimmings") would be the | |
* rectangle described by the arguments (relative to the | |
* receiver's parent). | |
* </p> | |
* Note that there is no setBounds for a printer. This method | |
* is usually used by passing in the client area (the 'printable | |
* area') of the printer. It can also be useful to pass in 0, 0, 0, 0. | |
* | |
* @return the required bounds to produce the given client area | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> | |
* </ul> | |
* | |
* @see #getBounds | |
* @see #getClientArea | |
*/ | |
public Rectangle computeTrim(int x, int y, int width, int height) { | |
checkDevice(); | |
int printX = -OS.GetDeviceCaps(handle, OS.PHYSICALOFFSETX); | |
int printY = -OS.GetDeviceCaps(handle, OS.PHYSICALOFFSETY); | |
int printWidth = OS.GetDeviceCaps(handle, OS.HORZRES); | |
int printHeight = OS.GetDeviceCaps(handle, OS.VERTRES); | |
int paperWidth = OS.GetDeviceCaps(handle, OS.PHYSICALWIDTH); | |
int paperHeight = OS.GetDeviceCaps(handle, OS.PHYSICALHEIGHT); | |
int hTrim = paperWidth - printWidth; | |
int vTrim = paperHeight - printHeight; | |
return new Rectangle(x + printX, y + printY, width + hTrim, height + vTrim); | |
} | |
/** | |
* Returns a <code>PrinterData</code> object representing the | |
* target printer for this print job. | |
* | |
* @return a PrinterData object describing the receiver | |
*/ | |
public PrinterData getPrinterData() { | |
return data; | |
} | |
/** | |
* Checks the validity of this device. | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> | |
* </ul> | |
*/ | |
protected void checkDevice() { | |
if (handle == 0) SWT.error(SWT.ERROR_DEVICE_DISPOSED); | |
} | |
/** | |
* Releases any internal state prior to destroying this printer. | |
* This method is called internally by the dispose | |
* mechanism of the <code>Device</code> class. | |
*/ | |
protected void release() { | |
super.release(); | |
data = null; | |
} | |
/** | |
* Destroys the printer handle. | |
* This method is called internally by the dispose | |
* mechanism of the <code>Device</code> class. | |
*/ | |
protected void destroy() { | |
if (handle != 0) OS.DeleteDC(handle); | |
handle = 0; | |
} | |
} |