/*
Violet - A program for editing UML diagrams.
Copyright (C) 2007 Cay S. Horstmann (http://horstmann.com)
Alexandre de Pellegrin (http://alexdp.free.fr);
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.horstmann.violet.framework.printer;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.print.Book;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import com.horstmann.violet.framework.injection.resources.ResourceBundleInjector;
import com.horstmann.violet.framework.injection.resources.annotation.ResourceBundleBean;
import com.horstmann.violet.framework.swingextension.RolloverButtonUI;
import com.horstmann.violet.framework.theme.ITheme;
import com.horstmann.violet.framework.theme.ThemeManager;
import com.horstmann.violet.product.diagram.abstracts.IGraph;
/**
* This class implements a dialog for previewing and printing a graph.
*/
public class PrintPanel extends JPanel
{
/**
* Constructs a print dialog.
*
* @param gr the graph to be printed
*/
public PrintPanel(IGraph gr)
{
ResourceBundleInjector.getInjector().inject(this);
this.graph = gr;
PrinterJob job = PrinterJob.getPrinterJob();
pageFormat = job.defaultPage();
attributes = new HashPrintRequestAttributeSet();
layoutUI();
}
/**
* Lays out the UI of the dialog.
*/
public void layoutUI()
{
setLayout(new BorderLayout());
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
buttonPanel.setBorder(new EmptyBorder(1, 1, 1, 1));
ITheme cLAF = ThemeManager.getInstance().getTheme();
buttonPanel.setBackground(cLAF.getRolloverButtonDefaultColor());
RolloverButtonUI buttonUI = new RolloverButtonUI(cLAF.getRolloverButtonRolloverColor(), cLAF
.getRolloverButtonRolloverBorderColor(), cLAF.getRolloverButtonDefaultColor());
this.moreButton.setUI(buttonUI);
buttonPanel.add(this.moreButton);
this.moreButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
scaleGraph *= Math.sqrt(2);
canvas.repaint();
}
});
this.fewerButton.setUI(buttonUI);
buttonPanel.add(this.fewerButton);
this.fewerButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
scaleGraph /= Math.sqrt(2);
canvas.repaint();
}
});
this.onePageButton.setUI(buttonUI);
buttonPanel.add(this.onePageButton);
this.onePageButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
while (getRows() * getCols() > 1)
scaleGraph /= Math.sqrt(2);
canvas.repaint();
}
});
this.pageSetupButton.setUI(buttonUI);
buttonPanel.add(this.pageSetupButton);
this.pageSetupButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
PrinterJob job = PrinterJob.getPrinterJob();
PageFormat newPageFormat = job.pageDialog(attributes);
if (newPageFormat != null) pageFormat = newPageFormat;
canvas.repaint();
}
});
this.printButton.setUI(buttonUI);
this.printButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
PrinterJob job = PrinterJob.getPrinterJob();
job.setPageable(makeBook());
if (job.printDialog(attributes))
{
pageFormat = job.validatePage(pageFormat);
job.print(attributes);
}
}
catch (PrinterException e2)
{
// TODO = display error
}
}
});
buttonPanel.add(this.printButton);
add(buttonPanel, BorderLayout.NORTH);
canvas = new PrintPreviewCanvas();
JPanel canvasPanel = new JPanel();
canvasPanel.setBorder(new EmptyBorder(10, 0, 0, 0));
canvasPanel.setOpaque(false);
canvasPanel.setLayout(new BorderLayout());
canvasPanel.add(canvas, BorderLayout.CENTER);
add(canvasPanel, BorderLayout.CENTER);
}
/**
* Makes a book consisting of the pages to be printed.
*
* @return the book to be printed
*/
private Book makeBook()
{
Book book = new Book();
final int pageCount = getRows() * getCols();
Printable printable = new Printable()
{
public int print(Graphics g, PageFormat pf, int page) throws PrinterException
{
Graphics2D g2 = (Graphics2D) g;
if (page > pageCount) return Printable.NO_SUCH_PAGE;
g2.translate(pf.getImageableX(), pf.getImageableY());
drawPage(g2, pf, page);
return Printable.PAGE_EXISTS;
}
public void drawPage(Graphics2D g2, PageFormat pf, int page)
{
int cols = getCols();
int row = page / cols;
int col = page % cols;
double px = pageFormat.getImageableWidth();
double py = pageFormat.getImageableHeight();
g2.clip(new Rectangle2D.Double(0, 0, px, py));
g2.translate(-col * px, -row * py);
g2.scale((float) scaleGraph, (float) scaleGraph);
g2.translate((float) -bounds.getX(), (float) -bounds.getY());
g2.setColor(Color.BLACK);
g2.setBackground(Color.WHITE);
graph.draw(g2);
}
};
book.append(printable, pageFormat, pageCount);
return book;
}
/**
* Gets the number of columns currently required for the printout
*
* @return the number of columns (>= 1)
*/
private int getCols()
{
return (int) Math.max(1, Math.ceil(bounds.getWidth() * scaleGraph / pageFormat.getImageableWidth()));
}
/**
* Gets the number of rows currently required for the printout
*
* @return the number of rows (>= 1)
*/
private int getRows()
{
return (int) Math.max(1, Math.ceil(bounds.getHeight() * scaleGraph / pageFormat.getImageableHeight()));
}
/**
* The component for displaying the print preview.
*/
class PrintPreviewCanvas extends JComponent
{
public Dimension getPreferredSize()
{
return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT);
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
bounds = graph.getClipBounds();
double xoff; // x offset of page start in window
double yoff; // y offset of page start in window
double scalePagesToCanvas; // scale factor to fit pages in canvas
double px = pageFormat.getImageableWidth();
double py = pageFormat.getImageableHeight();
int cols = getCols();
int rows = getRows();
double dx = px * getCols();
double dy = py * getRows();
double sx = getWidth() - 1;
double sy = getHeight() - 1;
if (dx / dy < sx / sy) // center horizontally
{
scalePagesToCanvas = sy / dy;
xoff = 0.5 * (sx - scalePagesToCanvas * dx);
yoff = 0;
}
else
// center vertically
{
scalePagesToCanvas = sx / dx;
xoff = 0;
yoff = 0.5 * (sy - scalePagesToCanvas * dy);
}
g2.translate((float) xoff, (float) yoff);
g2.scale((float) scalePagesToCanvas, (float) scalePagesToCanvas);
// draw page backgrounds
Rectangle2D pages = new Rectangle2D.Double(0, 0, px * cols, py * rows);
g2.setPaint(Color.WHITE);
g2.fill(pages);
g2.setPaint(Color.BLACK);
AffineTransform oldTransform = g2.getTransform();
g2.scale((float) scaleGraph, (float) scaleGraph);
g2.translate((float) -bounds.getX(), (float) -bounds.getY());
graph.draw(g2);
g2.setTransform(oldTransform);
// draw page outlines (ignoring margins)
g2.setPaint(Color.LIGHT_GRAY);
for (int i = 0; i < cols; i++)
for (int j = 0; j < rows; j++)
{
Rectangle2D page = new Rectangle2D.Double(i * px, j * py, px, py);
g2.draw(page);
}
}
private static final int DEFAULT_WIDTH = 450;
private static final int DEFAULT_HEIGHT = 300;
}
private PrintPreviewCanvas canvas;
private PageFormat pageFormat;
private PrintRequestAttributeSet attributes;
private IGraph graph;
private Rectangle2D bounds;
private double scaleGraph = 1;
@ResourceBundleBean(key = "dialog.print.more")
private JButton moreButton;
@ResourceBundleBean(key = "dialog.print.fewer")
private JButton fewerButton;
@ResourceBundleBean(key = "dialog.print.one")
private JButton onePageButton;
@ResourceBundleBean(key = "dialog.print.page")
private JButton pageSetupButton;
@ResourceBundleBean(key = "dialog.print.print")
private JButton printButton;
}