/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.printing;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
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 new GC(printer)
* and then draw on the printer GC using the usual graphics calls.
*
* A Printer
object may be constructed by providing
* a PrinterData
object which identifies the printer.
* A PrintDialog
presents a print dialog to the user
* and returns an initialized instance of PrinterData
.
* Alternatively, calling new Printer()
will construct a
* printer object for the user's default printer.
*
* Application code must explicitly invoke the Printer.dispose()
* method to release the operating system resources managed by each instance
* when those instances are no longer required.
*
* IMPORTANT: This field is not part of the SWT * public API. 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 accessed from application code. *
* * @noreference This field is not intended to be referenced by clients. */ public long 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 */ static TCHAR profile; static TCHAR appName; static TCHAR keyName; static { profile = new TCHAR(0, "PrinterPorts", true); //$NON-NLS-1$ appName = new TCHAR(0, "windows", true); //$NON-NLS-1$ keyName = new TCHAR(0, "device", true); //$NON-NLS-1$ } /** * Returns an array ofPrinterData
objects
* representing all available printers. If there are no
* printers, the array will be empty.
*
* @return an array of PrinterData objects representing the 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 = ""; //$NON-NLS-1$
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 PrinterData
object representing
* the default printer or null
if there is no
* default printer.
*
* @return the default printer data or null
*
* @since 2.1
*/
public 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) return null;
int commaIndex = 0;
while(buf.tcharAt(commaIndex) != ',' && commaIndex < length) commaIndex++;
if (commaIndex < length) {
deviceName = buf.toString(0, commaIndex);
}
if (deviceName == null) return null;
String driver = ""; //$NON-NLS-1$
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);
}
static DeviceData checkNull (PrinterData data) {
if (data == null) data = new PrinterData();
if (data.driver == null || data.name == null) {
PrinterData defaultPrinter = getDefaultPrinterData();
if (defaultPrinter == null) SWT.error(SWT.ERROR_NO_HANDLES);
data.driver = defaultPrinter.driver;
data.name = defaultPrinter.name;
}
return data;
}
/**
* Constructs a new printer representing the default printer.
* * Note: You must dispose the printer when it is no longer required. *
* * @exception SWTErrorPrinterData
* object representing the desired printer. If the argument
* is null, then the default printer will be used.
* * Note: You must dispose the printer when it is no longer required. *
* * @param data the printer data for the specified printer, or null to use the default printer * * @exception IllegalArgumentExceptionDevice
class.
* @param deviceData the device data
*/
@Override
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);
long lpInitData = 0;
byte devmodeData [] = data.otherData;
long hHeap = OS.GetProcessHeap();
if (devmodeData != null && devmodeData.length != 0) {
/* If user setup info from a print dialog was specified, restore the DEVMODE struct. */
lpInitData = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, devmodeData.length);
OS.MoveMemory(lpInitData, devmodeData, devmodeData.length);
} else {
long [] hPrinter = new long [1];
OS.OpenPrinter(device, hPrinter, 0);
if (hPrinter[0] != 0) {
int dwNeeded = OS.DocumentProperties(0, hPrinter[0], device, 0, 0, 0);
if (dwNeeded >= 0) {
lpInitData = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, dwNeeded);
int rc = OS.DocumentProperties(0, hPrinter[0], device, lpInitData, 0, OS.DM_OUT_BUFFER);
if (rc != OS.IDOK) {
OS.HeapFree(hHeap, 0, lpInitData);
lpInitData = 0;
}
}
OS.ClosePrinter(hPrinter[0]);
}
}
/* Initialize DEVMODE struct fields from the printerData. */
if (lpInitData != 0) {
DEVMODE devmode = new DEVMODE ();
OS.MoveMemory(devmode, lpInitData, DEVMODE.sizeof);
devmode.dmFields |= OS.DM_ORIENTATION;
devmode.dmOrientation = data.orientation == PrinterData.LANDSCAPE ? OS.DMORIENT_LANDSCAPE : OS.DMORIENT_PORTRAIT;
if (data.copyCount != 1) {
devmode.dmFields |= OS.DM_COPIES;
devmode.dmCopies = (short)data.copyCount;
}
if (data.collate != false) {
devmode.dmFields |= OS.DM_COLLATE;
devmode.dmCollate = OS.DMCOLLATE_TRUE;
}
if (data.duplex != SWT.DEFAULT) {
devmode.dmFields |= OS.DM_DUPLEX;
switch (data.duplex) {
case PrinterData.DUPLEX_SHORT_EDGE: devmode.dmDuplex = OS.DMDUP_HORIZONTAL; break;
case PrinterData.DUPLEX_LONG_EDGE: devmode.dmDuplex = OS.DMDUP_VERTICAL; break;
default: devmode.dmDuplex = OS.DMDUP_SIMPLEX;
}
}
OS.MoveMemory(lpInitData, devmode, DEVMODE.sizeof);
}
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.
*
* IMPORTANT: This method is not part of the public
* API for Printer
. 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.
*
* IMPORTANT: This method is not part of the public
* API for Printer
. 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.
*
* 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. *
* * @param jobName the name of the print job to start * @return true if the job started successfully and false otherwise. * * @exception SWTException* After calling startJob, this method may be called any number of times * along with a matching endPage. *
* * @return true if the page started successfully and false otherwise. * * @exception SWTException* For a printer, this is the size of the physical page, in pixels. *
* * @return the bounding rectangle * * @exception SWTException* For a printer, this is the size of the printable area * of the page, in pixels. *
* * @return the client area * * @exception SWTException* Most printers have a minimum margin on each edge of the paper where the * printer device is unable to print. This margin is known as the "trim." * This method can be used to calculate the printer's minimum margins * by passing in a client area of 0, 0, 0, 0 and then using the resulting * x and y coordinates (which will be <= 0) to determine the minimum margins * for the top and left edges of the paper, and the resulting width and height * (offset by the resulting x and y) to determine the minimum margins for the * bottom and right edges of the paper, as follows: *
*PrinterData
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 Device
class.
*/
@Override
protected void release() {
super.release();
data = null;
}
/**
* Destroys the printer handle.
* This method is called internally by the dispose
* mechanism of the Device
class.
*/
@Override
protected void destroy() {
if (handle != 0) OS.DeleteDC(handle);
handle = 0;
}
}