/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.ui.internal.print;
import java.util.List;
import java.util.Stack;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.SWTGraphics;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Transform;
import org.eclipse.swt.printing.Printer;
import org.eclipse.swt.printing.PrinterData;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.xmind.gef.GEF;
import org.xmind.gef.IGraphicalViewer;
import org.xmind.gef.draw2d.RotatableWrapLabel;
import org.xmind.gef.draw2d.graphics.Rotate90Graphics;
import org.xmind.gef.draw2d.graphics.ScaledGraphics;
import org.xmind.gef.image.FigureRenderer;
import org.xmind.gef.image.IExportAreaProvider;
import org.xmind.gef.image.IExportSourceProvider;
import org.xmind.gef.image.ImageExportUtils;
import org.xmind.gef.image.ResizeConstants;
import org.xmind.gef.util.Properties;
import org.xmind.ui.mindmap.GhostShellProvider;
import org.xmind.ui.mindmap.IMindMap;
import org.xmind.ui.mindmap.IMindMapViewer;
import org.xmind.ui.mindmap.MindMapExportViewer;
import org.xmind.ui.mindmap.MindMapUI;
import org.xmind.ui.mindmap.MindMapViewerExportSourceProvider;
import org.xmind.ui.resources.FontUtils;
import org.xmind.ui.util.Logger;
import org.xmind.ui.util.UnitConvertor;
public class PrintClient extends FigureRenderer {
private class MindMapViewerPrintSourceProvider
extends MindMapViewerExportSourceProvider {
/**
* @param viewer
*/
public MindMapViewerPrintSourceProvider(IGraphicalViewer viewer) {
super(viewer);
}
/**
*
*/
public MindMapViewerPrintSourceProvider(IGraphicalViewer viewer,
int margins) {
super(viewer, margins);
}
/*
* (non-Javadoc)
*
* @see org.xmind.ui.mindmap.MindMapViewerExportSourceProvider#
* collectContents (java.util.List)
*/
@Override
protected void collectContents(List<IFigure> figures) {
if (!settings.getBoolean(PrintConstants.NO_BACKGROUND)) {
figures.add(getViewer().getLayer(GEF.LAYER_BACKGROUND));
}
figures.add(getViewer().getLayer(GEF.LAYER_CONTENTS));
figures.add(getViewer().getLayer(MindMapUI.LAYER_TITLE));
}
}
private static final int VIEWER_MARGIN = 15;
// private static final int TEXT_MARGIN = 5;
private static final int TEXT_MARGIN = 0;
private String jobName;
private PrinterData printerData;
private IDialogSettings settings;
private Shell parentShell;
private Printer printer = null;
private Rectangle pageBounds = null;
private Rectangle pageClientArea = null;
private Point dpi = null;
private boolean needRotate = false;
private boolean jobStarted = false;
// private List<MindMapExportContentProvider> providers = null;
private IExportSourceProvider source = null;
private IExportAreaProvider area = null;
private GhostShellProvider shell = null;
private Transform transform;
public PrintClient(String jobName, Shell parentShell,
PrinterData printerData, IDialogSettings settings) {
this.jobName = jobName;
this.parentShell = parentShell;
this.printerData = printerData;
this.settings = settings;
}
public void print(IMindMap sourceMap) {
if (!start())
return;
printMap(sourceMap);
}
protected void printMap(IMindMap sourceMap) {
if (shell == null) {
shell = new GhostShellProvider(parentShell.getDisplay());
}
Properties properties = new Properties();
properties.set(IMindMapViewer.VIEWER_MARGIN,
Math.max(pageBounds.width, pageBounds.height));
int margin = VIEWER_MARGIN * dpi.x / UnitConvertor.getScreenDpi().x;
// properties.set(IMindMapViewer.VIEWER_MARGIN, margin);
properties.set(IMindMapViewer.VIEWER_GRADIENT, Boolean.FALSE);
boolean plusVisible = getBoolean(settings, PrintConstants.PLUS_VISIBLE,
PrintConstants.DEFAULT_PLUS_VISIBLE);
boolean minusVisible = getBoolean(settings,
PrintConstants.MINUS_VISIBLE,
PrintConstants.DEFAULT_MINUS_VISIBLE);
properties.set(IMindMapViewer.PLUS_VISIBLE, plusVisible);
properties.set(IMindMapViewer.MINUS_VISIBLE, minusVisible);
IGraphicalViewer exportViewer = new MindMapExportViewer(shell,
sourceMap, properties);
this.source = new MindMapViewerPrintSourceProvider(exportViewer,
margin);
render();
}
private boolean getBoolean(IDialogSettings settings, String key,
boolean defaultValue) {
boolean value = defaultValue;
if (settings.get(key) != null) {
value = settings.getBoolean(key);
}
return value;
}
public void print(IGraphicalViewer sourceViewer) {
if (!start())
return;
// IMindMap map = (IMindMap) sourceViewer.getAdapter(IMindMap.class);
// if (map == null
// || map.getCentralTopic() == map.getSheet().getRootTopic()) {
int margin = VIEWER_MARGIN * dpi.x / UnitConvertor.getScreenDpi().x;
this.source = new MindMapViewerPrintSourceProvider(sourceViewer,
margin);
render();
// } else {
// printMap(new MindMap(map.getSheet()));
// }
}
private boolean start() {
if (printer == null) {
printer = new Printer(printerData);
}
receivePrinterInfo();
if (!jobStarted) {
if (!printer.startJob(jobName))
return false;
jobStarted = true;
}
return printer.startPage();
}
/**
*
*/
private void render() {
this.area = ImageExportUtils.createExportAreaProvider(
source.getSourceArea(), ResizeConstants.RESIZE_STRETCH,
needRotate ? pageClientArea.height : pageClientArea.width,
needRotate ? pageClientArea.width : pageClientArea.height,
source.getMargins());
init(source, area);
GC gc = new GC(printer);
try {
render(gc);
} finally {
gc.dispose();
}
printer.endPage();
}
/*
* (non-Javadoc)
*
* @see
* org.xmind.gef.image.FigureRenderer#render(org.eclipse.swt.graphics.GC)
*/
@Override
public void render(GC gc) {
//draw source content
gc.setClipping(pageClientArea.x, pageClientArea.y, pageClientArea.width,
pageClientArea.height);
pushState(gc);
drawSourceContent(gc);
popState(gc);
//draw border
gc.setClipping(pageClientArea.x, pageClientArea.y, pageClientArea.width,
pageClientArea.height);
if (settings.getBoolean(PrintConstants.BORDER)) {
drawBorder(gc);
}
//draw header/footer
org.eclipse.swt.graphics.Rectangle pageBounds = printer.getClientArea();
gc.setClipping(pageBounds.x, pageBounds.y, pageBounds.width,
pageBounds.height);
String headerText = settings.get(PrintConstants.HEADER_TEXT);
if (headerText != null && !"".equals(headerText)) { //$NON-NLS-1$
drawHeader(gc, headerText);
}
String footerText = settings.get(PrintConstants.FOOTER_TEXT);
if (footerText != null && !"".equals(footerText)) { //$NON-NLS-1$
drawFooter(gc, footerText);
}
}
public void drawSourceContent(GC gc) {
super.render(gc);
}
private void pushState(GC gc) {
Transform tempTransform = new Transform(gc.getDevice());
gc.getTransform(tempTransform);
float[] elements = new float[6];
tempTransform.getElements(elements);
if (transform != null && !transform.isDisposed()) {
transform.dispose();
}
transform = new Transform(gc.getDevice(), elements);
tempTransform.dispose();
}
private void popState(GC gc) {
gc.setTransform(transform);
}
/*
* (non-Javadoc)
*
* @see
* org.xmind.gef.image.FigureRenderer#createGraphics(org.eclipse.draw2d.
* Graphics, java.util.Stack)
*/
@Override
protected void createGraphics(Graphics graphics, Stack<Graphics> stack) {
Rectangle bounds = getBounds();
graphics.translate(
pageClientArea.x
- (needRotate ? (-bounds.y - bounds.height) : bounds.x),
pageClientArea.y - (needRotate ? bounds.x : bounds.y));
if (getScale() > 0) {
if (ScaledGraphics.SCALED_GRAPHICS_ENABLED) {
ScaledGraphics scaledGraphics = new ScaledGraphics(graphics);
scaledGraphics.scale(getScale());
stack.push(scaledGraphics);
graphics = scaledGraphics;
} else {
graphics.scale(getScale());
}
}
if (needRotate) {
Rotate90Graphics rotatedGraphics = new Rotate90Graphics(graphics);
stack.push(rotatedGraphics);
graphics = rotatedGraphics;
}
}
private void drawHeader(GC gc, String text) {
Font font = getFont(PrintConstants.HEADER_FONT);
try {
drawText(gc, text, font, getAlign(PrintConstants.HEADER_ALIGN,
PositionConstants.CENTER), true);
} finally {
font.dispose();
}
}
private void drawFooter(GC gc, String text) {
Font font = getFont(PrintConstants.FOOTER_FONT);
try {
drawText(gc, text, font, getAlign(PrintConstants.FOOTER_ALIGN,
PositionConstants.RIGHT), false);
} finally {
font.dispose();
}
}
private int getAlign(String alignKey, int defaultAlign) {
return PrintConstants.toDraw2DAlignment(settings.get(alignKey),
defaultAlign);
}
private Font getFont(String fontKey) {
Font font = null;
String fontValue = settings.get(fontKey);
if (fontValue != null) {
FontData[] fontData = FontUtils.toFontData(fontValue);
if (fontData != null) {
for (FontData fd : fontData) {
fd.setHeight(fd.getHeight() * dpi.y
/ UnitConvertor.getScreenDpi().y);
}
font = new Font(Display.getCurrent(), fontData);
}
}
if (font == null) {
FontData[] defaultFontData = JFaceResources
.getDefaultFontDescriptor().getFontData();
int defaultHeight = defaultFontData[0].getHeight();
font = new Font(Display.getCurrent(), FontUtils.newHeight(
defaultFontData,
defaultHeight * dpi.y / UnitConvertor.getScreenDpi().y));
}
return font;
}
private void drawText(GC gc, String text, Font font, int alignment,
boolean top) {
RotatableWrapLabel label = new RotatableWrapLabel();
label.setText(text);
label.setFont(font);
label.setTextAlignment(alignment);
label.setForegroundColor(
parentShell.getDisplay().getSystemColor(SWT.COLOR_BLACK));
Rectangle pageBounds = new Rectangle(printer.getClientArea());
int width = needRotate ? pageClientArea.height : pageClientArea.width;
int marginWidth = TEXT_MARGIN * dpi.x / UnitConvertor.getScreenDpi().x;
int marginHeight = TEXT_MARGIN * dpi.y / UnitConvertor.getScreenDpi().y;
if (needRotate) {
int temp = marginWidth;
marginWidth = marginHeight;
marginHeight = temp;
}
width -= marginWidth * 2;
Dimension size = label.getPreferredSize(width, -1);
int x = -width / 2;
int y;
if (top) {
y = -pageClientArea.height / 2 - (pageClientArea.y - pageBounds.y)
+ Math.max(
(pageClientArea.y - pageBounds.y - size.height) / 2,
marginWidth);
} else {
y = pageClientArea.height / 2
+ (pageBounds.y + pageBounds.height
- (pageClientArea.y + pageClientArea.height))
- size.height
- Math.max((pageBounds.y + pageBounds.height
- (pageClientArea.y + pageClientArea.height)
- size.height) / 2, marginWidth);
}
label.setBounds(new Rectangle(x, y, width, size.height));
SWTGraphics baseGraphics = new SWTGraphics(gc);
baseGraphics.translate(pageClientArea.x + pageClientArea.width / 2,
pageClientArea.y + pageClientArea.height / 2);
Graphics graphics = baseGraphics;
Rotate90Graphics rotatedGraphics = null;
if (needRotate) {
rotatedGraphics = new Rotate90Graphics(graphics);
graphics = rotatedGraphics;
}
try {
label.paint(graphics);
} catch (Throwable e) {
Logger.log(e, "Error occurred while printing"); //$NON-NLS-1$
} finally {
if (rotatedGraphics != null) {
rotatedGraphics.dispose();
}
baseGraphics.dispose();
}
}
private void drawBorder(GC gc) {
gc.setForeground(
parentShell.getDisplay().getSystemColor(SWT.COLOR_BLACK));
gc.setLineWidth(1);
gc.setLineStyle(SWT.LINE_SOLID);
gc.drawRectangle(pageClientArea.x, pageClientArea.y,
pageClientArea.width - 1, pageClientArea.height - 1);
}
// private void drawSourceContent(GC gc, IMindMap source) {
// MindMapImageExporter exporter = new MindMapImageExporter(
// parentShell.getDisplay());
// exporter.setSource(source, properties, null);
//
// MindMapExportContentProvider provider = new MindMapExportContentProvider(
// parentShell, source);
// if (providers == null) {
// providers = new ArrayList<MindMapExportContentProvider>();
// }
// providers.add(provider);
// provider.setProperty(IMindMapViewer.VIEWER_MARGIN,
// Math.max(pageBounds.width, pageBounds.height));
// provider.setMargin(VIEWER_MARGIN * dpi.x
// / UnitConvertor.getScreenDpi().x);
// provider.setProperty(IMindMapViewer.VIEWER_GRADIENT, Boolean.FALSE);
// provider.setResizeStrategy(ResizeConstants.RESIZE_STRETCH,
// needRotate ? pageClientArea.height : pageClientArea.width,
// needRotate ? pageClientArea.width : pageClientArea.height);
// try {
// Rectangle exportArea = provider.getExportArea();
// double scale = provider.getScale();
// IFigure contents = provider.getContents();
// if (settings.getBoolean(PrintConstants.NO_BACKGROUND)) {
// Layer layer = provider.getViewer().getLayer(
// GEF.LAYER_BACKGROUND);
// if (layer != null) {
// layer.setOpaque(false);
// }
// }
//
// SWTGraphics baseGraphcis = new SWTGraphics(gc);
// baseGraphcis.translate(pageClientArea.x
// - (needRotate ? (-exportArea.y - exportArea.height)
// : exportArea.x), pageClientArea.y
// - (needRotate ? exportArea.x : exportArea.y));
// Graphics graphics = baseGraphcis;
// ScaledGraphics scaledGraphics = null;
// Rotate90Graphics rotatedGraphics = null;
// if (scale > 0) {
// scaledGraphics = new ScaledGraphics(graphics);
// scaledGraphics.scale(scale);
// graphics = scaledGraphics;
// }
// if (needRotate) {
// rotatedGraphics = new Rotate90Graphics(graphics);
// graphics = rotatedGraphics;
// }
// try {
// contents.paint(graphics);
// } catch (Throwable e) {
// Logger.log(e, "Error occurred while painting mind map: " //$NON-NLS-1$
// + source.getCentralTopic().getTitleText());
// } finally {
// if (rotatedGraphics != null) {
// rotatedGraphics.dispose();
// }
// if (scaledGraphics != null) {
// scaledGraphics.dispose();
// }
// baseGraphcis.dispose();
// }
// } catch (Throwable e) {
// Logger.log(e, "Error occurred while painting mind map: " //$NON-NLS-1$
// + source.getCentralTopic().getTitleText());
// }
// }
private void receivePrinterInfo() {
dpi = new Point(printer.getDPI());
pageBounds = new Rectangle(printer.getBounds());
// Rectangle trim = new Rectangle(printer.computeTrim(0, 0, 0, 0));
// pageMargins = new Insets(-trim.y, -trim.x, trim.right(), trim.bottom());
pageClientArea = new Rectangle(printer.getClientArea());
// pageClientArea.x = pageBounds.x
// + (pageBounds.width - pageClientArea.width) / 2;
// pageClientArea.y = pageBounds.y
// + (pageBounds.height - pageClientArea.height) / 2;
int leftMargin = getUserMargin(PrintConstants.LEFT_MARGIN);
int rightMargin = getUserMargin(PrintConstants.RIGHT_MARGIN);
int topMargin = getUserMargin(PrintConstants.TOP_MARGIN);
int bottomMargin = getUserMargin(PrintConstants.BOTTOM_MARGIN);
// pageClientArea.expand(pageMargins);
pageClientArea.x += leftMargin;
pageClientArea.y += topMargin;
pageClientArea.width -= leftMargin + rightMargin;
pageClientArea.height -= topMargin + bottomMargin;
// needRotate = pageBounds.height > pageBounds.width;
needRotate = false;
int headerHeight = PrintUtils.getHeaderHeight(settings, dpi.y);
int footerHeight = PrintUtils.getBottomHeight(settings, dpi.y);
pageClientArea.expand(new Insets(-headerHeight, 0, -footerHeight, 0));
}
private int getUserMargin(String key) {
double margin;
try {
margin = settings.getDouble(key);
} catch (NumberFormatException e) {
margin = PrintConstants.DEFAULT_MARGIN;
}
double dpi;
if (PrintConstants.LEFT_MARGIN.equals(key)
|| PrintConstants.RIGHT_MARGIN.equals(key)) {
dpi = this.dpi.x;
} else {
dpi = this.dpi.y;
}
return (int) (margin * dpi);
}
public void dispose() {
if (shell != null) {
shell.dispose();
shell = null;
}
if (printer != null) {
if (!printer.isDisposed()) {
printer.endJob();
}
printer.dispose();
printer = null;
}
if (transform != null) {
transform.dispose();
transform = null;
}
jobStarted = false;
// if (providers != null) {
// for (Object o : providers.toArray()) {
// ((MindMapExportContentProvider) o).dispose();
// }
// providers = null;
// }
}
}