| /******************************************************************************* |
| * Copyright (c) 2012, 2016 Original authors and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Original authors and others - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.nebula.widgets.nattable.print; |
| |
| import java.text.SimpleDateFormat; |
| import java.util.ArrayList; |
| import java.util.Date; |
| import java.util.List; |
| |
| import org.eclipse.nebula.widgets.nattable.Messages; |
| import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes; |
| import org.eclipse.nebula.widgets.nattable.config.Direction; |
| import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; |
| import org.eclipse.nebula.widgets.nattable.formula.command.DisableFormulaCachingCommand; |
| import org.eclipse.nebula.widgets.nattable.formula.command.EnableFormulaCachingCommand; |
| import org.eclipse.nebula.widgets.nattable.layer.ILayer; |
| import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; |
| import org.eclipse.nebula.widgets.nattable.print.command.PrintEntireGridCommand; |
| import org.eclipse.nebula.widgets.nattable.print.command.TurnViewportOffCommand; |
| import org.eclipse.nebula.widgets.nattable.print.command.TurnViewportOnCommand; |
| import org.eclipse.nebula.widgets.nattable.print.config.PrintConfigAttributes; |
| import org.eclipse.nebula.widgets.nattable.resize.AutoResizeHelper; |
| import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes; |
| import org.eclipse.nebula.widgets.nattable.style.DisplayMode; |
| import org.eclipse.nebula.widgets.nattable.style.IStyle; |
| import org.eclipse.nebula.widgets.nattable.summaryrow.command.CalculateSummaryRowValuesCommand; |
| import org.eclipse.nebula.widgets.nattable.util.GUIHelper; |
| import org.eclipse.nebula.widgets.nattable.util.IClientAreaProvider; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.graphics.Transform; |
| import org.eclipse.swt.printing.PrintDialog; |
| import org.eclipse.swt.printing.Printer; |
| import org.eclipse.swt.printing.PrinterData; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Shell; |
| |
| /** |
| * This class is used to print a layer. Usually you create an instance by using |
| * the top most layer in the layer stack. For grids this is the GridLayer, |
| * otherwise the ViewportLayer is a good choice. |
| */ |
| public class LayerPrinter { |
| |
| private class PrintTarget { |
| |
| private final IConfigRegistry configRegistry; |
| private final ILayer layer; |
| private final IClientAreaProvider originalClientAreaProvider; |
| |
| PrintTarget(ILayer layer, IConfigRegistry configRegistry) { |
| this.layer = layer; |
| this.configRegistry = configRegistry; |
| this.originalClientAreaProvider = layer.getClientAreaProvider(); |
| } |
| } |
| |
| private final List<PrintTarget> printTargets = new ArrayList<PrintTarget>(); |
| |
| public static final int FOOTER_HEIGHT_IN_PRINTER_DPI = 300; |
| |
| final SimpleDateFormat dateFormat; |
| private final String footerDate; |
| |
| private final int footerHeight; |
| |
| /** |
| * @since 1.4 |
| */ |
| protected boolean preRender = true; |
| |
| private final Direction fittingMode; |
| |
| /** |
| * |
| * @param layer |
| * The layer to print. Usually the top most layer in the layer |
| * stack. For grids this should be the GridLayer, for custom |
| * CompositeLayer compositions the CompositeLayer, otherwise the |
| * ViewportLayer is a good choice. |
| * @param configRegistry |
| * The ConfigRegistry needed for rendering to the print GC. |
| */ |
| public LayerPrinter(ILayer layer, IConfigRegistry configRegistry) { |
| this.printTargets.add(new PrintTarget(layer, configRegistry)); |
| |
| // configure the footer height |
| Integer fh = configRegistry.getConfigAttribute( |
| PrintConfigAttributes.FOOTER_HEIGHT, |
| DisplayMode.NORMAL); |
| this.footerHeight = (fh != null) ? fh : FOOTER_HEIGHT_IN_PRINTER_DPI; |
| |
| // configure the footer date |
| String configuredFormat = configRegistry.getConfigAttribute( |
| PrintConfigAttributes.DATE_FORMAT, |
| DisplayMode.NORMAL); |
| if (configuredFormat != null) { |
| this.dateFormat = new SimpleDateFormat(configuredFormat); |
| } else { |
| this.dateFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm a"); //$NON-NLS-1$ |
| } |
| |
| this.footerDate = this.dateFormat.format(new Date()); |
| |
| // configure the fitting mode |
| Direction configuredFittingMode = configRegistry.getConfigAttribute( |
| PrintConfigAttributes.FITTING_MODE, |
| DisplayMode.NORMAL); |
| this.fittingMode = (configuredFittingMode != null) ? configuredFittingMode : Direction.NONE; |
| } |
| |
| /** |
| * Adds the given {@link ILayer} as print target. It can be used to register |
| * multiple NatTable or layer stacks in one print job. |
| * |
| * @param layer |
| * The {@link ILayer} that should be printed together with the |
| * main {@link ILayer} registered via constructor. |
| * @param configRegistry |
| * The {@link IConfigRegistry} that should be used to print the |
| * given {@link ILayer}. |
| * |
| * @since 1.5 |
| */ |
| public void addPrintTarget(ILayer layer, IConfigRegistry configRegistry) { |
| this.printTargets.add(new PrintTarget(layer, configRegistry)); |
| } |
| |
| /** |
| * Computes the scale factor to match the printer resolution. |
| * |
| * @param layer |
| * The layer for which the scale factor should be calculated. |
| * @param printer |
| * The printer that will be used. |
| * @param dpi |
| * <code>true</code> if in any case the dpi scaling factor should |
| * be returned, <code>false</code> if the calculation properties |
| * need to be checked whether the scaling factor to match a page |
| * should be returned |
| * @return The amount to scale the screen resolution by, to match the |
| * printer the resolution. |
| */ |
| private float[] computeScaleFactor(ILayer layer, Printer printer, boolean dpi) { |
| Point screenDPI = Display.getDefault().getDPI(); |
| Point printerDPI = printer.getDPI(); |
| |
| float sfX = Float.valueOf(printerDPI.x) / Float.valueOf(screenDPI.x); |
| float sfY = Float.valueOf(printerDPI.y) / Float.valueOf(screenDPI.y); |
| |
| if (!dpi && (this.fittingMode != Direction.NONE)) { |
| Rectangle total = getTotalArea(layer); |
| Rectangle print = computePrintArea(printer); |
| |
| float pixelX = Float.valueOf(print.width) / Float.valueOf(total.width); |
| float pixelY = (Float.valueOf(print.height) - getFooterHeightInPrinterDPI()) / Float.valueOf(total.height); |
| |
| switch (this.fittingMode) { |
| case HORIZONTAL: |
| return new float[] { pixelX, pixelX }; |
| case VERTICAL: |
| return new float[] { pixelY, pixelY }; |
| case BOTH: |
| return new float[] { pixelX, pixelY }; |
| } |
| } |
| |
| return new float[] { sfX, sfY }; |
| } |
| |
| /** |
| * @param layer |
| * The layer for which the total area is requested. |
| * @return The size of the layer to fit all the contents. |
| */ |
| private Rectangle getTotalArea(ILayer layer) { |
| return new Rectangle(0, 0, layer.getWidth(), layer.getHeight()); |
| } |
| |
| /** |
| * Calculates number of horizontal and vertical pages needed to print all |
| * registered layers. |
| * |
| * @param printer |
| * The printer that will be used. |
| * @return The number of pages that are needed to print. |
| */ |
| private int getPageCount(Printer printer) { |
| int result = 0; |
| for (PrintTarget target : this.printTargets) { |
| Point layerResult = getPageCount(target, printer); |
| result += (layerResult.x * layerResult.y); |
| } |
| return result; |
| } |
| |
| /** |
| * Calculates number of horizontal and vertical pages needed to print the |
| * entire layer of the given print target. |
| * |
| * @param target |
| * The print target to print. |
| * @param printer |
| * The printer that will be used. |
| * @return The number of horizontal and vertical pages that are needed to |
| * print the layer of the given print target. |
| */ |
| private Point getPageCount(PrintTarget target, Printer printer) { |
| Rectangle printArea = computePrintArea(printer); |
| float[] scaleFactor = computeScaleFactor(target.layer, printer, false); |
| |
| Integer[] gridLineWidth = getGridLineWidth(target.configRegistry); |
| |
| // calculate pages based on non cut off columns/rows |
| int numOfHorizontalPages = 0; |
| int pageWidth = Math.round(Float.valueOf(printArea.width / scaleFactor[0])); |
| int endX = 0; |
| while (endX < target.layer.getWidth()) { |
| endX += pageWidth; |
| int colPos = target.layer.getColumnPositionByX(endX); |
| if (colPos >= 0) { |
| ILayerCell cell = findColumnCellForBounds(target.layer, colPos); |
| if (cell != null) { |
| Rectangle cellBounds = cell.getBounds(); |
| if (cellBounds.x < endX) { |
| endX -= (endX - cellBounds.x); |
| endX -= gridLineWidth[1]; |
| } |
| } |
| } else { |
| endX = target.layer.getWidth(); |
| } |
| |
| numOfHorizontalPages++; |
| } |
| |
| int numOfVerticalPages = 0; |
| int pageHeight = Math.round(Float.valueOf((printArea.height - getFooterHeightInPrinterDPI()) / scaleFactor[1])); |
| int endY = 0; |
| while (endY < target.layer.getHeight()) { |
| endY += pageHeight; |
| int rowPos = target.layer.getRowPositionByY(endY); |
| if (rowPos >= 0) { |
| ILayerCell cell = findRowCellForBounds(target.layer, rowPos); |
| if (cell != null) { |
| Rectangle cellBounds = cell.getBounds(); |
| if (cellBounds.y < endY) { |
| endY -= (endY - cellBounds.y); |
| endY -= gridLineWidth[1]; |
| } |
| } |
| } else { |
| endY = target.layer.getHeight(); |
| } |
| |
| numOfVerticalPages++; |
| } |
| |
| if (gridLineWidth[0] == null) { |
| target.configRegistry.unregisterConfigAttribute(CellConfigAttributes.GRID_LINE_WIDTH); |
| } |
| |
| return new Point(numOfHorizontalPages, numOfVerticalPages); |
| } |
| |
| private ILayerCell findColumnCellForBounds(ILayer layer, int colPos) { |
| int rowPos = 0; |
| ILayerCell cell = layer.getCellByPosition(colPos, rowPos); |
| while (cell != null && cell.isSpannedCell()) { |
| // if the cell is spanned, check the cell at the next row |
| rowPos++; |
| cell = layer.getCellByPosition(colPos, rowPos); |
| } |
| return cell; |
| } |
| |
| private ILayerCell findRowCellForBounds(ILayer layer, int rowPos) { |
| int colPos = 0; |
| ILayerCell cell = layer.getCellByPosition(colPos, rowPos); |
| while (cell != null && cell.isSpannedCell()) { |
| // if the cell is spanned, check the cell at the next column |
| colPos++; |
| cell = layer.getCellByPosition(colPos, rowPos); |
| } |
| return cell; |
| } |
| |
| /** |
| * @return The footer height in printer DPI that should be used to render |
| * the footer. |
| * @since 1.5 |
| */ |
| protected int getFooterHeightInPrinterDPI() { |
| return this.footerHeight; |
| } |
| |
| /** |
| * @param configRegistry |
| * The {@link IConfigRegistry} to retrieve the grid line width |
| * from. |
| * @return Integer array that contains the original configured width at |
| * index 0 and the grid line width to use at index 1. |
| * @since 1.5 |
| */ |
| protected Integer[] getGridLineWidth(IConfigRegistry configRegistry) { |
| // check if a grid line width is configured |
| Integer width = configRegistry.getConfigAttribute( |
| CellConfigAttributes.GRID_LINE_WIDTH, |
| DisplayMode.NORMAL); |
| Integer gridLineWidth = width; |
| // if no explicit width is set, we temporary specify a grid line |
| // width of 2 for optimized grid line printing |
| if (width == null) { |
| configRegistry.registerConfigAttribute( |
| CellConfigAttributes.GRID_LINE_WIDTH, 2); |
| gridLineWidth = 2; |
| } |
| return new Integer[] { width, gridLineWidth }; |
| } |
| |
| /** |
| * Will first open the PrintDialog to let a user configure the print job and |
| * then starts the print job. |
| * |
| * @param shell |
| * The shell which should be the parent of the PrintDialog. |
| */ |
| public void print(final Shell shell) { |
| // turn viewport off to ensure calculation of the print pages for the |
| // whole table |
| for (PrintTarget target : this.printTargets) { |
| target.layer.doCommand(new TurnViewportOffCommand()); |
| } |
| |
| Printer printer = null; |
| try { |
| printer = setupPrinter(shell); |
| if (printer == null) { |
| return; |
| } |
| } finally { |
| // turn viewport on |
| for (PrintTarget target : this.printTargets) { |
| target.layer.doCommand(new TurnViewportOnCommand()); |
| } |
| } |
| |
| // Note: As we are operating on the same layer instance that is shown in |
| // the UI executing the print job asynchronously will not cause a real |
| // asynchronous execution. The UI will hang until the print job is done, |
| // because we access the information to print from the same instance. |
| // For further developments we need to ensure that for printing a deep |
| // copy of the layer needs to be performed instead of operating on the |
| // same instance. |
| Display.getDefault().asyncExec(new PrintJob(printer)); |
| } |
| |
| /** |
| * Checks if a given page number should be printed. Page is allowed to print |
| * if: User asked to print all pages or Page in a specified range |
| * |
| * @param printerData |
| * The printer settings made by the user. Needed to determine if |
| * a page should be printed dependent to the scope |
| * @param currentPage |
| * The page that should be checked |
| * @return <code>true</code> if the given page should be printed, |
| * <code>false</code> if not |
| */ |
| private boolean shouldPrint(PrinterData printerData, int totalPageCount) { |
| if (printerData.scope == PrinterData.PAGE_RANGE) { |
| return totalPageCount >= printerData.startPage |
| && totalPageCount <= printerData.endPage; |
| } |
| return true; |
| } |
| |
| /** |
| * Opens the PrintDialog to let the user specify the printer and print |
| * configurations to use. |
| * |
| * @param shell |
| * The Shell which should be the parent for the PrintDialog |
| * @return The selected printer with the print configuration made by the |
| * user. |
| */ |
| private Printer setupPrinter(final Shell shell) { |
| Printer defaultPrinter = new Printer(); |
| int pageCount = getPageCount(defaultPrinter); |
| defaultPrinter.dispose(); |
| |
| final PrintDialog printDialog = new PrintDialog(shell); |
| printDialog.setStartPage(1); |
| printDialog.setEndPage(pageCount); |
| printDialog.setScope(PrinterData.ALL_PAGES); |
| |
| PrinterData printerData = printDialog.open(); |
| if (printerData == null) { |
| return null; |
| } |
| return new Printer(printerData); |
| } |
| |
| /** |
| * Computes the print area, including margins |
| * |
| * @param printer |
| * The printer that will be used. |
| * @return The print area that will be used to render the table. |
| */ |
| private Rectangle computePrintArea(Printer printer) { |
| // Get the printable area |
| Rectangle rect = printer.getClientArea(); |
| |
| // Compute the trim |
| Rectangle trim = printer.computeTrim(0, 0, 0, 0); |
| |
| // Get the printer's DPI |
| Point dpi = printer.getDPI(); |
| dpi.x = dpi.x / 2; |
| dpi.y = dpi.y / 2; |
| |
| // Calculate the printable area, using 1 inch margins |
| int left = trim.x + dpi.x; |
| if (left < rect.x) |
| left = rect.x; |
| |
| int right = (rect.width + trim.x + trim.width) - dpi.x; |
| if (right > rect.width) |
| right = rect.width; |
| |
| int top = trim.y + dpi.y; |
| if (top < rect.y) |
| top = rect.y; |
| |
| int bottom = (rect.height + trim.y + trim.height) - dpi.y; |
| if (bottom > rect.height) |
| bottom = rect.height; |
| |
| return new Rectangle(left, top, right - left, bottom - top); |
| } |
| |
| /** |
| * Enable in-memory pre-rendering. This is necessary in case content |
| * painters are used that are configured for content based auto-resizing. |
| * |
| * @since 1.4 |
| */ |
| public void enablePreRendering() { |
| this.preRender = true; |
| } |
| |
| /** |
| * Disable in-memory pre-rendering. You should consider to disable |
| * pre-rendering if no content painters are used that are configured for |
| * content based auto-resizing. |
| * |
| * @since 1.4 |
| */ |
| public void disablePreRendering() { |
| this.preRender = false; |
| } |
| |
| /** |
| * The job for printing the layer. |
| */ |
| private class PrintJob implements Runnable { |
| /** |
| * The printer that will be used. |
| */ |
| private final Printer printer; |
| |
| /** |
| * @param printer |
| * The printer that will be used. |
| */ |
| private PrintJob(Printer printer) { |
| this.printer = printer; |
| } |
| |
| @Override |
| public void run() { |
| if (this.printer.startJob("NatTable")) { //$NON-NLS-1$ |
| GC gc = new GC(this.printer); |
| try { |
| int currentPage = 1; |
| |
| for (PrintTarget target : LayerPrinter.this.printTargets) { |
| target.layer.doCommand(new TurnViewportOffCommand()); |
| float[] scaleFactor = null; |
| float[] dpiFactor = null; |
| try { |
| scaleFactor = computeScaleFactor(target.layer, this.printer, false); |
| dpiFactor = computeScaleFactor(target.layer, this.printer, true); |
| } finally { |
| target.layer.doCommand(new TurnViewportOnCommand()); |
| } |
| |
| Integer[] gridLineWidth = getGridLineWidth(target.configRegistry); |
| |
| // if pre-rendering is enabled, render in-memory to |
| // trigger content based auto-resizing |
| if (LayerPrinter.this.preRender) { |
| Transform tempTransform = new Transform(this.printer); |
| tempTransform.scale(scaleFactor[0], scaleFactor[1]); |
| AutoResizeHelper.autoResize(target.layer, target.configRegistry); |
| tempTransform.dispose(); |
| } |
| |
| try { |
| // if a SummaryRowLayer is in the layer stack, we |
| // need to ensure that the values are calculated |
| target.layer.doCommand(new CalculateSummaryRowValuesCommand()); |
| |
| // ensure that the viewport is turned off |
| target.layer.doCommand(new TurnViewportOffCommand()); |
| |
| // ensure that formula processing is performed in |
| // the current thread |
| target.layer.doCommand(new DisableFormulaCachingCommand()); |
| |
| // set the size of the layer according to the print |
| // settings made by the user |
| setLayerSize(target, this.printer.getPrinterData()); |
| |
| final Rectangle printerClientArea = computePrintArea(this.printer); |
| final int printBoundsWidth = Math.round(Float.valueOf(printerClientArea.width / scaleFactor[0])); |
| int printBoundsHeight = Math.round(Float.valueOf((printerClientArea.height - getFooterHeightInPrinterDPI()) / scaleFactor[1])); |
| |
| final Point pageCount = getPageCount(target, this.printer); |
| |
| // Print pages Left to Right and then Top to Down |
| int startY = 0; |
| for (int verticalPageNumber = 0; verticalPageNumber < pageCount.y; verticalPageNumber++) { |
| |
| int endY = startY + printBoundsHeight; |
| // int rowPos = |
| // target.layer.getRowPositionByY(endY); |
| int rowPos = target.layer.getRowPositionByY(endY); |
| if (rowPos >= 0) { |
| ILayerCell cell = findRowCellForBounds(target.layer, rowPos); |
| if (cell != null) { |
| Rectangle cellBounds = cell.getBounds(); |
| if (cellBounds.y < endY) { |
| printBoundsHeight -= (endY - cellBounds.y); |
| } |
| } |
| } |
| |
| int startX = 0; |
| for (int horizontalPageNumber = 0; horizontalPageNumber < pageCount.x; horizontalPageNumber++) { |
| |
| // Calculate bounds for the next page |
| Rectangle printBounds = new Rectangle( |
| startX, |
| startY, |
| printBoundsWidth, |
| printBoundsHeight); |
| |
| int endX = startX + printBounds.width; |
| int colPos = target.layer.getColumnPositionByX(endX); |
| if (colPos >= 0) { |
| ILayerCell cell = findColumnCellForBounds(target.layer, colPos); |
| if (cell != null) { |
| Rectangle cellBounds = cell.getBounds(); |
| if (cellBounds.x < endX) { |
| printBounds.width -= (endX - cellBounds.x); |
| } |
| } |
| } |
| |
| Rectangle footerBounds = new Rectangle( |
| Math.round(Float.valueOf((printerClientArea.width / dpiFactor[0]) * horizontalPageNumber)), |
| Math.round(Float.valueOf(((printerClientArea.height - getFooterHeightInPrinterDPI()) / dpiFactor[1]) * verticalPageNumber)), |
| Math.round(Float.valueOf(printerClientArea.width / dpiFactor[0])), |
| Math.round(Float.valueOf((printerClientArea.height - getFooterHeightInPrinterDPI()) / dpiFactor[1]))); |
| |
| if (shouldPrint(this.printer.getPrinterData(), currentPage)) { |
| this.printer.startPage(); |
| |
| Transform printerTransform = new Transform(this.printer); |
| Transform footerTransform = new Transform(this.printer); |
| |
| // FIXME |
| Rectangle intersect = new Rectangle( |
| 0, |
| 0, |
| target.layer.getWidth(), |
| target.layer.getHeight()); |
| |
| intersect = printBounds.intersection(intersect); |
| |
| configureScalingTransform(printerTransform, scaleFactor, printerClientArea, intersect); |
| configureScalingTransform(footerTransform, dpiFactor, printerClientArea, footerBounds); |
| |
| gc.setTransform(printerTransform); |
| printLayer(target, gc, intersect); |
| |
| gc.setTransform(footerTransform); |
| printFooter(gc, currentPage, footerBounds, target.configRegistry); |
| |
| this.printer.endPage(); |
| printerTransform.dispose(); |
| footerTransform.dispose(); |
| } |
| currentPage++; |
| |
| startX += printBounds.width; |
| } |
| startY += printBoundsHeight; |
| } |
| |
| } finally { |
| restoreLayerState(target); |
| } |
| |
| // there was no explicit width configured, so we |
| // configured a temporary one for grid line printing. |
| // this configuration needs to be removed again |
| if (gridLineWidth[0] == null) { |
| target.configRegistry.unregisterConfigAttribute(CellConfigAttributes.GRID_LINE_WIDTH); |
| } |
| } |
| } finally { |
| this.printer.endJob(); |
| gc.dispose(); |
| this.printer.dispose(); |
| } |
| } |
| } |
| |
| /** |
| * Configure the given {@link Transform} in order to support scaling |
| * correctly on printing. |
| * |
| * @param transform |
| * The {@link Transform} to configure |
| * @param scaleFactor |
| * The scale factor to set and to be used for translation |
| * @param printerClientArea |
| * The client area of the printer |
| * @param printBounds |
| * The print bounds |
| */ |
| private void configureScalingTransform( |
| Transform transform, float[] scaleFactor, |
| Rectangle printerClientArea, Rectangle printBounds) { |
| // Adjust for DPI difference between display and printer |
| transform.scale(scaleFactor[0], scaleFactor[1]); |
| |
| // Adjust for margins |
| transform.translate( |
| printerClientArea.x / scaleFactor[0], |
| printerClientArea.y / scaleFactor[1]); |
| |
| // Grid will not automatically print the pages |
| // at the left margin. |
| // Example: page 1 will print at x = 0, page 2 |
| // at x = 100, page 3 at x = 300 |
| // Adjust to print from the left page margin. |
| // i.e x = 0 |
| transform.translate(-1 * printBounds.x, -1 * printBounds.y); |
| } |
| |
| /** |
| * Set the client area of the layer so it matches the print settings |
| * made by the user. In case a user selected to print everything, the |
| * size needs to be extended so that all the contents fit in the |
| * viewport to ensure that we print the <i>entire</i> table. |
| * |
| * @param target |
| * The print target to print. |
| * @param printerData |
| * The PrinterData that was configured by the user on the |
| * PrintDialog. |
| */ |
| private void setLayerSize(PrintTarget target, PrinterData printerData) { |
| if (printerData != null && printerData.scope == PrinterData.SELECTION) { |
| target.layer.setClientAreaProvider(target.originalClientAreaProvider); |
| } else { |
| final Rectangle fullLayerSize = getTotalArea(target.layer); |
| |
| target.layer.setClientAreaProvider(new IClientAreaProvider() { |
| @Override |
| public Rectangle getClientArea() { |
| return fullLayerSize; |
| } |
| }); |
| |
| // in case the whole layer should be printed or only the |
| // selected pages, we need to ensure to set the starting point |
| // to 0/0 |
| target.layer.doCommand(new PrintEntireGridCommand()); |
| } |
| } |
| |
| /** |
| * Print the part of the layer that matches the given print bounds. |
| * |
| * @param target |
| * The print target to print |
| * @param gc |
| * The print GC to render the layer to. |
| * @param printBounds |
| * The bounds of the print page. |
| */ |
| private void printLayer(PrintTarget target, GC gc, Rectangle printBounds) { |
| target.layer.getLayerPainter().paintLayer( |
| target.layer, gc, 0, 0, printBounds, target.configRegistry); |
| } |
| |
| /** |
| * Print the footer to the page. |
| * |
| * @param gc |
| * The print GC to render the footer to. |
| * @param totalPageCount |
| * The total number of pages that are printed. |
| * @param printBounds |
| * The bounds of the print page. |
| * @param configRegistry |
| * The {@link IConfigRegistry} needed to retrieve the footer |
| * style. |
| */ |
| private void printFooter(GC gc, int totalPageCount, Rectangle printBounds, IConfigRegistry configRegistry) { |
| Color oldForeground = gc.getForeground(); |
| Color oldBackground = gc.getBackground(); |
| Font oldFont = gc.getFont(); |
| |
| Color footerForeground = null; |
| Color footerBackground = null; |
| Font footerFont = null; |
| |
| IStyle style = configRegistry.getConfigAttribute( |
| PrintConfigAttributes.FOOTER_STYLE, |
| DisplayMode.NORMAL); |
| if (style != null) { |
| footerForeground = style.getAttributeValue(CellStyleAttributes.FOREGROUND_COLOR); |
| footerBackground = style.getAttributeValue(CellStyleAttributes.BACKGROUND_COLOR); |
| footerFont = style.getAttributeValue(CellStyleAttributes.FONT); |
| } |
| gc.setForeground(footerForeground != null ? footerForeground : GUIHelper.COLOR_BLACK); |
| gc.setBackground(footerBackground != null ? footerBackground : GUIHelper.COLOR_WHITE); |
| gc.setFont(footerFont != null ? footerFont : GUIHelper.DEFAULT_FONT); |
| |
| gc.drawLine( |
| printBounds.x, |
| printBounds.y + printBounds.height + 10, |
| printBounds.x + printBounds.width, |
| printBounds.y + printBounds.height + 10); |
| |
| gc.drawText( |
| Messages.getString("Printer.page") + " " + totalPageCount, //$NON-NLS-1$ //$NON-NLS-2$ |
| printBounds.x, |
| printBounds.y + printBounds.height + 15); |
| |
| gc.drawText( |
| LayerPrinter.this.footerDate, |
| printBounds.x + printBounds.width - gc.textExtent(LayerPrinter.this.footerDate).x, |
| printBounds.y + printBounds.height + 15); |
| |
| gc.setForeground(oldForeground); |
| gc.setBackground(oldBackground); |
| gc.setFont(oldFont); |
| } |
| |
| /** |
| * Restores the layer state to match the display characteristics again. |
| * This is done by resetting the client area provider, turning the |
| * viewport on and enabling formula result caching again. |
| * |
| * @param target |
| * The print target whose state should be restarted. |
| */ |
| private void restoreLayerState(PrintTarget target) { |
| target.layer.setClientAreaProvider(target.originalClientAreaProvider); |
| target.layer.doCommand(new TurnViewportOnCommand()); |
| target.layer.doCommand(new EnableFormulaCachingCommand()); |
| } |
| |
| } |
| |
| } |