Skip to content
Permalink
0824490119
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
546 lines (507 sloc) 21 KB
/*
* HomePrintableComponent.java 27 aout 07
*
* Sweet Home 3D, Copyright (c) 2007 Emmanuel PUYBARET / eTeks <info@eteks.com>
*
* 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.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
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<Integer> printablePages = new HashSet<Integer>();
private int furniturePageCount;
private int planPageCount;
private Date printDate;
private JLabel fixedHeaderLabel;
private JLabel fixedFooterLabel;
/**
* Creates a printable component that will print or display the
* furniture view, the plan view and 3D view of the <code>home</code>
* managed by <code>controller</code>.
*/
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");
} 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 <code>page</code>.
*/
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;
if (this.fixedHeaderLabel != null) {
this.fixedHeaderLabel.setSize((int)pageFormat.getImageableWidth(), this.fixedHeaderLabel.getPreferredSize().height);
imageableHeight -= this.fixedHeaderLabel.getHeight() + HEADER_FOOTER_MARGIN;
imageableY += this.fixedHeaderLabel.getHeight() + HEADER_FOOTER_MARGIN;
xFixedHeader = (float)pageFormat.getImageableX();
yFixedHeader = (float)pageFormat.getImageableY();
}
if (this.fixedFooterLabel != null) {
this.fixedFooterLabel.setSize((int)pageFormat.getImageableWidth(), this.fixedFooterLabel.getPreferredSize().height);
imageableHeight -= this.fixedFooterLabel.getHeight() + HEADER_FOOTER_MARGIN;
xFixedFooter = (float)pageFormat.getImageableX();
yFixedFooter = (float)(pageFormat.getImageableY() + pageFormat.getImageableHeight()) - this.fixedFooterLabel.getHeight();
}
Rectangle clipBounds = g2D.getClipBounds();
AffineTransform oldTransform = g2D.getTransform();
final PlanView planView = this.controller.getPlanController().getView();
if (homePrint != null
|| this.fixedHeaderLabel != null
|| this.fixedFooterLabel != 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) {
final Level selectedLevel = home.getSelectedLevel();
furnitureTable = (FurnitureTable)furnitureView;
furnitureFilter = furnitureTable.getFurnitureFilter();
furnitureTable.setFurnitureFilter(new FurnitureTable.FurnitureFilter() {
public boolean include(Home home, HomePieceOfFurniture piece) {
// Print furniture at selected levels
List<Boolean> furnitureLevels = home.getPrint().getFurnitureList();
Boolean includePiece = false;
for (int i = 0; i < furnitureLevels.size(); i++) {
if (furnitureLevels.get(i) && piece.isAtLevel(home.getLevels().get(i)))
includePiece = true;
}
return (furnitureFilter == null || furnitureFilter.include(home, piece))
&& includePiece
&& (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++;
}
}
Level tempLevel = home.getSelectedLevel();
List<Boolean> planLevels = homePrint.getPlanViewList();
PlanView planToPrint;
// Loop through levels to be printed
for (int i = 0; i < planLevels.size(); i++) {
if (planLevels.get(i)) {
home.setSelectedLevel(home.getLevels().get(i));
planToPrint = this.controller.getPlanController().getView();
if (pageExists == NO_SUCH_PAGE ) {
// Try to print next plan view page
pageExists = ((Printable)planToPrint).print(g2D, pageFormat, page - this.furniturePageCount);
if (pageExists == PAGE_EXISTS
&& !this.printablePages.contains(page)) {
this.printablePages.add(page);
this.planPageCount++;
}
}
}
}
home.setSelectedLevel(tempLevel);
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);
}
}
System.out.println("Test here");
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 + 1);
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 (this.fixedHeaderLabel != null) {
g2D.translate(xFixedHeader, yFixedHeader);
this.fixedHeaderLabel.print(g2D);
g2D.translate(-xFixedHeader, -yFixedHeader);
}
if (header != null) {
g2D.drawString(header, xHeader, yHeader);
}
if (footer != null) {
g2D.drawString(footer, xFooter, yFooter);
}
if (this.fixedFooterLabel != null) {
g2D.translate(xFixedFooter, yFixedFooter);
this.fixedFooterLabel.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();
return new Dimension((int)(pageFormat.getWidth() / maxSize * 400) + insets.left + insets.right,
(int)(pageFormat.getHeight() / maxSize * 400) + 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 <code>PageFormat</code> object created from <code>homePrint</code>.
*/
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;
}
}
}