Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.eteks.sweethome3d.swing.HomePrintableComponent Maven / Gradle / Ivy
/*
* HomePrintableComponent.java 27 aout 07
*
* Sweet Home 3D, Copyright (c) 2007 Emmanuel PUYBARET / eTeks
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.eteks.sweethome3d.swing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.security.AccessControlException;
import java.text.MessageFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import javax.swing.JComponent;
import javax.swing.JLabel;
import com.eteks.sweethome3d.model.Home;
import com.eteks.sweethome3d.model.HomePieceOfFurniture;
import com.eteks.sweethome3d.model.HomePrint;
import com.eteks.sweethome3d.model.LengthUnit;
import com.eteks.sweethome3d.model.Level;
import com.eteks.sweethome3d.viewcontroller.ContentManager;
import com.eteks.sweethome3d.viewcontroller.HomeController;
import com.eteks.sweethome3d.viewcontroller.PlanView;
import com.eteks.sweethome3d.viewcontroller.View;
/**
* A printable component used to print or preview the furniture, the plan
* and the 3D view of a home.
*/
public class HomePrintableComponent extends JComponent implements Printable {
/**
* List of the variables that the user may insert in header and footer.
*/
public enum Variable {
PAGE_NUMBER("$pageNumber", "{0, number, integer}"),
PAGE_COUNT("$pageCount", "{1, number, integer}"),
PLAN_SCALE("$planScale", "{2}"),
DATE("$date", "{3, date}"),
TIME("$time", "{3, time}"),
HOME_PRESENTATION_NAME("$name", "{4}"),
HOME_NAME("$file", "{5}"),
LEVEL_NAME("$level", "{6}");
private final String userCode;
private final String formatCode;
private Variable(String userCode, String formatCode) {
this.userCode = userCode;
this.formatCode = formatCode;
}
/**
* Returns a user readable code matching this field.
*/
public String getUserCode() {
return this.userCode;
}
/**
* Returns a format usable code matching this field.
*/
public String getFormatCode() {
return this.formatCode;
}
/**
* Returns the message format built from a format that uses variables.
*/
public static MessageFormat getMessageFormat(String format) {
// Replace $$ escape sequence ($$ is the escape sequence for $ character)
final String temp = "|#&%<>/!";
format = format.replace("$$", temp);
// Replace MessageFormat escape sequences
format = format.replace("'", "''");
format = format.replace("{", "'{'");
// Replace variable by their MessageFormat code
for (Variable variable : Variable.values()) {
format = format.replace(variable.getUserCode(), variable.getFormatCode());
}
format = format.replace(temp, "$");
return new MessageFormat(format);
}
};
private static final float HEADER_FOOTER_MARGIN = LengthUnit.centimeterToInch(0.2f) * 72;
private final Home home;
private final HomeController controller;
private final Font defaultFont;
private final Font headerFooterFont;
private int page;
private int pageCount = -1;
private Set printablePages = new HashSet();
private int furniturePageCount;
private int planPageCount;
private Date printDate;
private JLabel fixedHeaderLabel;
private JLabel fixedFooterLabel;
private JLabel fixedFirstPageHeaderLabel;
private JLabel fixedFirstPageFooterLabel;
/**
* Creates a printable component that will print or display the
* furniture view, the plan view and 3D view of the home
* managed by controller
.
*/
public HomePrintableComponent(Home home, HomeController controller, Font defaultFont) {
this.home = home;
this.controller = controller;
this.defaultFont = defaultFont;
this.headerFooterFont = defaultFont.deriveFont(11f);
try {
ResourceBundle resource = ResourceBundle.getBundle(HomePrintableComponent.class.getName());
this.fixedHeaderLabel = getFixedHeaderOrFooterLabel(resource, "fixedHeader");
this.fixedFooterLabel = getFixedHeaderOrFooterLabel(resource, "fixedFooter");
this.fixedFirstPageHeaderLabel = getFixedHeaderOrFooterLabel(resource, "fixedFirstPageHeader");
if (this.fixedFirstPageHeaderLabel == null) {
this.fixedFirstPageHeaderLabel = this.fixedHeaderLabel;
}
this.fixedFirstPageFooterLabel = getFixedHeaderOrFooterLabel(resource, "fixedFirstPageFooter");
if (this.fixedFirstPageFooterLabel == null) {
this.fixedFirstPageFooterLabel = this.fixedFooterLabel;
}
} catch (MissingResourceException ex) {
// No resource bundle
}
}
private JLabel getFixedHeaderOrFooterLabel(ResourceBundle resource, String resourceKey) {
try {
// Build URL base for resources referenced in fixed header or footer
String classFile = "/" + HomePrintableComponent.class.getName().replace('.', '/') + ".properties";
String urlBase = HomePrintableComponent.class.getResource(classFile).toString();
urlBase = urlBase.substring(0, urlBase.length() - classFile.length());
String fixedHeaderOrFooter = String.format(resource.getString(resourceKey), urlBase);
JLabel fixedHeaderOrFooterLabel = new JLabel(fixedHeaderOrFooter, JLabel.CENTER);
fixedHeaderOrFooterLabel.setFont(this.headerFooterFont);
fixedHeaderOrFooterLabel.setSize(fixedHeaderOrFooterLabel.getPreferredSize());
return fixedHeaderOrFooterLabel;
} catch (MissingResourceException ex) {
// No fixed label
return null;
}
}
/**
* Prints a given page
.
*/
public int print(Graphics g, PageFormat pageFormat, int page) throws PrinterException {
// Check current thread isn't interrupted
if (Thread.interrupted()) {
throw new InterruptedPrinterException();
}
Graphics2D g2D = (Graphics2D)g;
g2D.setFont(this.defaultFont);
g2D.setColor(Color.WHITE);
g2D.fill(new Rectangle2D.Double(0, 0, pageFormat.getWidth(), pageFormat.getHeight()));
Paper oldPaper = pageFormat.getPaper();
try {
// Let the user be able to force a fixed margin in case of bugs in page setup dialogs or printer drivers
String fixedPrintMargin = System.getProperty("com.eteks.sweethome3d.swing.fixedPrintMargin", null);
if (fixedPrintMargin != null) {
float margin = LengthUnit.centimeterToInch(Float.parseFloat(fixedPrintMargin)) * 72;
Paper noMarginPaper = pageFormat.getPaper();
noMarginPaper.setImageableArea(margin, margin, oldPaper.getWidth() - 2 * margin, oldPaper.getHeight() - 2 * margin);
pageFormat.setPaper(noMarginPaper);
}
} catch (NumberFormatException ex) {
ex.printStackTrace();
} catch (AccessControlException ex) {
// If com.eteks.sweethome3d.swing.fixedPrintMargin can't be read, ignore fixed margin
}
int pageExists = NO_SUCH_PAGE;
HomePrint homePrint = this.home.getPrint();
// Prepare header and footer
float imageableY = (float)pageFormat.getImageableY();
float imageableHeight = (float)pageFormat.getImageableHeight();
String header = null;
float xHeader = 0;
float yHeader = 0;
float xFixedHeader = 0;
float yFixedHeader = 0;
String footer = null;
float xFooter = 0;
float yFooter = 0;
float xFixedFooter = 0;
float yFixedFooter = 0;
JLabel fixedHeaderPageLabel = page == 0
? this.fixedFirstPageHeaderLabel : this.fixedHeaderLabel;
JLabel fixedFooterPageLabel = page == 0
? this.fixedFirstPageFooterLabel : this.fixedFooterLabel;
if (fixedHeaderPageLabel != null) {
fixedHeaderPageLabel.setSize((int)pageFormat.getImageableWidth(), fixedHeaderPageLabel.getPreferredSize().height);
imageableHeight -= fixedHeaderPageLabel.getHeight() + HEADER_FOOTER_MARGIN;
imageableY += fixedHeaderPageLabel.getHeight() + HEADER_FOOTER_MARGIN;
xFixedHeader = (float)pageFormat.getImageableX();
yFixedHeader = (float)pageFormat.getImageableY();
}
if (fixedFooterPageLabel != null) {
fixedFooterPageLabel.setSize((int)pageFormat.getImageableWidth(), fixedFooterPageLabel.getPreferredSize().height);
imageableHeight -= fixedFooterPageLabel.getHeight() + HEADER_FOOTER_MARGIN;
xFixedFooter = (float)pageFormat.getImageableX();
yFixedFooter = (float)(pageFormat.getImageableY() + pageFormat.getImageableHeight()) - fixedFooterPageLabel.getHeight();
}
Rectangle clipBounds = g2D.getClipBounds();
AffineTransform oldTransform = g2D.getTransform();
final PlanView planView = this.controller.getPlanController().getView();
if (homePrint != null
|| fixedHeaderPageLabel != null
|| fixedFooterPageLabel != null) {
if (homePrint != null) {
FontMetrics fontMetrics = g2D.getFontMetrics(this.headerFooterFont);
float headerFooterHeight = fontMetrics.getAscent() + fontMetrics.getDescent() + HEADER_FOOTER_MARGIN;
// Retrieve variable values
int pageNumber = page + 1;
int pageCount = getPageCount();
String planScale = "?";
if (homePrint.getPlanScale() != null) {
planScale = "1/" + Math.round(1 / homePrint.getPlanScale());
} else {
Float preferredScale = null;
// Should create an interface to test if the component has a preferred scale
if (planView instanceof PlanComponent) {
preferredScale = ((PlanComponent)planView).getPrintPreferredScale(g, pageFormat);
} else if (planView instanceof MultipleLevelsPlanPanel) {
preferredScale = ((MultipleLevelsPlanPanel)planView).getPrintPreferredScale(g, pageFormat);
}
if (preferredScale != null) {
planScale = "1/" + Math.round(1 / preferredScale);
}
}
if (page == 0) {
this.printDate = new Date();
}
String homeName = this.home.getName();
if (homeName == null) {
homeName = "";
}
String levelName = "";
if (this.home.getSelectedLevel() != null) {
levelName = this.home.getSelectedLevel().getName();
}
String homePresentationName = this.controller.getContentManager().getPresentationName(
homeName, ContentManager.ContentType.SWEET_HOME_3D);
Object [] variableValues = new Object [] {
pageNumber, pageCount, planScale, this.printDate, homePresentationName, homeName, levelName};
// Create header text
String headerFormat = homePrint.getHeaderFormat();
if (headerFormat != null) {
header = Variable.getMessageFormat(headerFormat).format(variableValues).trim();
if (header.length() > 0) {
xHeader = ((float)pageFormat.getWidth() - fontMetrics.stringWidth(header)) / 2;
yHeader = imageableY + fontMetrics.getAscent();
imageableY += headerFooterHeight;
imageableHeight -= headerFooterHeight;
} else {
header = null;
}
}
// Create footer text
String footerFormat = homePrint.getFooterFormat();
if (footerFormat != null) {
footer = Variable.getMessageFormat(footerFormat).format(variableValues).trim();
if (footer.length() > 0) {
xFooter = ((float)pageFormat.getWidth() - fontMetrics.stringWidth(footer)) / 2;
yFooter = imageableY + imageableHeight - fontMetrics.getDescent();
imageableHeight -= headerFooterHeight;
} else {
footer = null;
}
}
}
// Update page format paper margins depending on paper orientation
Paper paper = pageFormat.getPaper();
switch (pageFormat.getOrientation()) {
case PageFormat.PORTRAIT:
paper.setImageableArea(paper.getImageableX(), imageableY,
paper.getImageableWidth(), imageableHeight);
break;
case PageFormat.LANDSCAPE :
paper.setImageableArea(paper.getWidth() - (imageableHeight + imageableY),
paper.getImageableY(),
imageableHeight, paper.getImageableHeight());
case PageFormat.REVERSE_LANDSCAPE:
paper.setImageableArea(imageableY, paper.getImageableY(),
imageableHeight, paper.getImageableHeight());
break;
}
pageFormat.setPaper(paper);
if (clipBounds == null) {
g2D.clipRect((int)pageFormat.getImageableX(), (int)pageFormat.getImageableY(),
(int)pageFormat.getImageableWidth(), (int)pageFormat.getImageableHeight());
} else {
g2D.clipRect(clipBounds.x, (int)pageFormat.getImageableY(),
clipBounds.width, (int)pageFormat.getImageableHeight());
}
}
View furnitureView = this.controller.getFurnitureController().getView();
if (furnitureView != null
&& (homePrint == null || homePrint.isFurniturePrinted())) {
FurnitureTable furnitureTable = null;
final FurnitureTable.FurnitureFilter furnitureFilter;
if (furnitureView instanceof FurnitureTable
&& (homePrint == null
|| homePrint.isPlanPrinted()
|| homePrint.isView3DPrinted())) {
final Level selectedLevel = home.getSelectedLevel();
furnitureTable = (FurnitureTable)furnitureView;
furnitureFilter = furnitureTable.getFurnitureFilter();
furnitureTable.setFurnitureFilter(new FurnitureTable.FurnitureFilter() {
public boolean include(Home home, HomePieceOfFurniture piece) {
// Print only furniture at selected level when the plan or the 3D view is printed
return (furnitureFilter == null || furnitureFilter.include(home, piece))
&& piece.isAtLevel(selectedLevel)
&& (piece.getLevel() == null || piece.getLevel().isViewable());
}
});
} else {
furnitureFilter = null;
}
// Try to print next furniture view page
pageExists = ((Printable)furnitureView).print(g2D, pageFormat, page);
if (furnitureTable != null) {
// Restore previous filter
((FurnitureTable)furnitureView).setFurnitureFilter(furnitureFilter);
}
if (pageExists == PAGE_EXISTS
&& !this.printablePages.contains(page)) {
this.printablePages.add(page);
this.furniturePageCount++;
}
}
if (pageExists == NO_SUCH_PAGE
&& planView != null
&& (homePrint == null || homePrint.isPlanPrinted())) {
// Try to print next plan view page
pageExists = ((Printable)planView).print(g2D, pageFormat, page - this.furniturePageCount);
if (pageExists == PAGE_EXISTS
&& !this.printablePages.contains(page)) {
this.printablePages.add(page);
this.planPageCount++;
}
}
View view3D = this.controller.getHomeController3D().getView();
if (pageExists == NO_SUCH_PAGE
&& view3D != null
&& (homePrint == null || homePrint.isView3DPrinted())) {
pageExists = ((Printable)view3D).print(g2D, pageFormat, page - this.planPageCount - this.furniturePageCount);
if (pageExists == PAGE_EXISTS
&& !this.printablePages.contains(page)) {
this.printablePages.add(page);
}
}
// Print header and footer
if (pageExists == PAGE_EXISTS) {
g2D.setTransform(oldTransform);
g2D.setClip(clipBounds);
g2D.setFont(this.headerFooterFont);
g2D.setColor(Color.BLACK);
if (fixedHeaderPageLabel != null) {
g2D.translate(xFixedHeader, yFixedHeader);
fixedHeaderPageLabel.print(g2D);
g2D.translate(-xFixedHeader, -yFixedHeader);
}
if (header != null) {
g2D.drawString(header, xHeader, yHeader);
}
if (footer != null) {
g2D.drawString(footer, xFooter, yFooter);
}
if (fixedFooterPageLabel != null) {
g2D.translate(xFixedFooter, yFixedFooter);
fixedFooterPageLabel.print(g2D);
g2D.translate(-xFixedFooter, -yFixedFooter);
}
}
pageFormat.setPaper(oldPaper);
return pageExists;
}
/**
* Returns the preferred size of this component according to paper orientation and size
* of home print attributes.
*/
@Override
public Dimension getPreferredSize() {
PageFormat pageFormat = getPageFormat(this.home.getPrint());
double maxSize = Math.max(pageFormat.getWidth(), pageFormat.getHeight());
Insets insets = getInsets();
int maxPreferredSize = Math.round(400 * SwingTools.getResolutionScale());
return new Dimension((int)(pageFormat.getWidth() / maxSize * maxPreferredSize) + insets.left + insets.right,
(int)(pageFormat.getHeight() / maxSize * maxPreferredSize) + insets.top + insets.bottom);
}
/**
* Paints the current page.
*/
@Override
protected void paintComponent(Graphics g) {
try {
Graphics2D g2D = (Graphics2D)g.create();
// Print printable object at component's scale
PageFormat pageFormat = getPageFormat(this.home.getPrint());
Insets insets = getInsets();
double scale = (getWidth() - insets.left - insets.right) / pageFormat.getWidth();
g2D.scale(scale, scale);
print(g2D, pageFormat, this.page);
g2D.dispose();
} catch (PrinterException ex) {
throw new RuntimeException(ex);
}
}
/**
* Sets the page currently painted by this component.
*/
public void setPage(int page) {
if (this.page != page) {
this.page = page;
repaint();
}
}
/**
* Returns the page currently painted by this component.
*/
public int getPage() {
return this.page;
}
/**
* Returns the page count of the home printed by this component.
*/
public int getPageCount() {
if (this.pageCount == -1) {
PageFormat pageFormat = getPageFormat(this.home.getPrint());
BufferedImage dummyImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Graphics dummyGraphics = dummyImage.getGraphics();
// Count pages by printing in a dummy image
this.pageCount = 0;
try {
while (print(dummyGraphics, pageFormat, this.pageCount) == Printable.PAGE_EXISTS) {
this.pageCount++;
}
} catch (PrinterException ex) {
// There should be no reason that print fails if print is done on a dummy image
throw new RuntimeException(ex);
}
dummyGraphics.dispose();
}
return this.pageCount;
}
/**
* Returns a PageFormat
object created from homePrint
.
*/
public static PageFormat getPageFormat(HomePrint homePrint) {
final PrinterJob printerJob = PrinterJob.getPrinterJob();
if (homePrint == null) {
return printerJob.defaultPage();
} else {
PageFormat pageFormat = new PageFormat();
switch (homePrint.getPaperOrientation()) {
case PORTRAIT :
pageFormat.setOrientation(PageFormat.PORTRAIT);
break;
case LANDSCAPE :
pageFormat.setOrientation(PageFormat.LANDSCAPE);
break;
case REVERSE_LANDSCAPE :
pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE);
break;
}
Paper paper = new Paper();
paper.setSize(homePrint.getPaperWidth(), homePrint.getPaperHeight());
paper.setImageableArea(homePrint.getPaperLeftMargin(), homePrint.getPaperTopMargin(),
homePrint.getPaperWidth() - homePrint.getPaperLeftMargin() - homePrint.getPaperRightMargin(),
homePrint.getPaperHeight() - homePrint.getPaperTopMargin() - homePrint.getPaperBottomMargin());
pageFormat.setPaper(paper);
pageFormat = printerJob.validatePage(pageFormat);
return pageFormat;
}
}
}