From d3daded1770ba2187c01f9c99ce43a3e91031883 Mon Sep 17 00:00:00 2001 From: plaa Date: Sat, 14 May 2011 20:21:36 +0000 Subject: [PATCH] printing updates git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@124 180e2498-e6e9-4542-8430-84ac67f01cd8 --- build.xml | 4 +- .../gui/components/ColorChooserButton.java | 71 ++ .../openrocket/gui/components/ColorIcon.java | 35 + .../configdialog/RocketComponentConfig.java | 49 +- .../openrocket/gui/dialogs/PrintDialog.java | 559 ++++++++++------ .../sf/openrocket/gui/dialogs/PrintPanel.java | 445 ------------- .../gui/dialogs/PrintSettingsDialog.java | 111 ++++ .../sf/openrocket/gui/main/BasicFrame.java | 4 +- .../openrocket/gui/main/ExceptionHandler.java | 16 + .../gui/print/PaperOrientation.java | 42 ++ .../sf/openrocket/gui/print/PaperSize.java | 426 ++++++------ .../openrocket/gui/print/PrintController.java | 188 +++--- .../gui/print/PrintServiceDialog.java | 609 ------------------ .../openrocket/gui/print/PrintSettings.java | 89 +++ .../openrocket/gui/print/PrintUtilities.java | 228 +++---- .../gui/print/TemplateProperties.java | 101 +-- .../openrocket/util/AbstractChangeSource.java | 47 ++ src/net/sf/openrocket/util/Prefs.java | 103 ++- .../openrocket/gui/print/TestPaperSize.java | 36 ++ 19 files changed, 1351 insertions(+), 1812 deletions(-) create mode 100644 src/net/sf/openrocket/gui/components/ColorChooserButton.java create mode 100644 src/net/sf/openrocket/gui/components/ColorIcon.java delete mode 100644 src/net/sf/openrocket/gui/dialogs/PrintPanel.java create mode 100644 src/net/sf/openrocket/gui/dialogs/PrintSettingsDialog.java create mode 100644 src/net/sf/openrocket/gui/print/PaperOrientation.java delete mode 100644 src/net/sf/openrocket/gui/print/PrintServiceDialog.java create mode 100644 src/net/sf/openrocket/gui/print/PrintSettings.java create mode 100644 src/net/sf/openrocket/util/AbstractChangeSource.java create mode 100644 test/net/sf/openrocket/gui/print/TestPaperSize.java diff --git a/build.xml b/build.xml index 30f62d25..84462ba7 100644 --- a/build.xml +++ b/build.xml @@ -132,7 +132,7 @@ - Checking project for critical TODOs. + Checking project for FIXMEs. @@ -142,7 +142,7 @@ - + diff --git a/src/net/sf/openrocket/gui/components/ColorChooserButton.java b/src/net/sf/openrocket/gui/components/ColorChooserButton.java new file mode 100644 index 00000000..15e4adc6 --- /dev/null +++ b/src/net/sf/openrocket/gui/components/ColorChooserButton.java @@ -0,0 +1,71 @@ +package net.sf.openrocket.gui.components; + +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeListener; + +import javax.swing.JButton; +import javax.swing.JColorChooser; +import javax.swing.JDialog; +import javax.swing.JPanel; + +import net.sf.openrocket.logging.LogHelper; +import net.sf.openrocket.startup.Application; + +/** + * A color chooser button. The currently selected color can be queried or set using the + * {@link #getSelectedColor()} and {@link #setSelectedColor(Color)}, and changes listened + * to by listening to property events with property name {@link #COLOR_KEY}. + * + * @author Sampo Niskanen + */ +public class ColorChooserButton extends JButton { + private static final LogHelper log = Application.getLogger(); + + public static final String COLOR_KEY = "selectedColor"; + + + public ColorChooserButton(Color initial) { + + setSelectedColor(initial); + + // Add action listener that opens color chooser dialog + this.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + log.user("Activating color chooser"); + final JColorChooser chooser = new JColorChooser(getSelectedColor()); + chooser.setPreviewPanel(new JPanel()); + final JDialog dialog = JColorChooser.createDialog(ColorChooserButton.this, "Select color", true, + chooser, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e2) { + Color c = chooser.getColor(); + log.user("User selected color " + c); + setSelectedColor(chooser.getColor()); + } + }, null); + log.info("Closing color chooser"); + dialog.setVisible(true); + } + }); + + } + + + public void addColorPropertyChangeListener(PropertyChangeListener listener) { + this.addPropertyChangeListener(COLOR_KEY, listener); + } + + public void setSelectedColor(Color c) { + log.debug("Selecting color " + c); + this.setIcon(new ColorIcon(c)); + this.putClientProperty(COLOR_KEY, c); + } + + public Color getSelectedColor() { + return (Color) this.getClientProperty(COLOR_KEY); + } + +} diff --git a/src/net/sf/openrocket/gui/components/ColorIcon.java b/src/net/sf/openrocket/gui/components/ColorIcon.java new file mode 100644 index 00000000..747a4268 --- /dev/null +++ b/src/net/sf/openrocket/gui/components/ColorIcon.java @@ -0,0 +1,35 @@ +package net.sf.openrocket.gui.components; + +import java.awt.Color; + +import javax.swing.Icon; + +/** + * An Icon that displays a specific color, suitable for drawing into a button. + * + * @author Sampo Niskanen + */ +public class ColorIcon implements Icon { + private final Color color; + + public ColorIcon(Color c) { + this.color = c; + } + + @Override + public int getIconHeight() { + return 15; + } + + @Override + public int getIconWidth() { + return 25; + } + + @Override + public void paintIcon(java.awt.Component c, java.awt.Graphics g, int x, int y) { + g.setColor(color); + g.fill3DRect(x, y, getIconWidth(), getIconHeight(), false); + } + +} diff --git a/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java b/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java index d6d60746..44925a35 100644 --- a/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java @@ -2,8 +2,6 @@ package net.sf.openrocket.gui.configdialog; import java.awt.Color; -import java.awt.Component; -import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; @@ -13,7 +11,6 @@ import java.util.Iterator; import java.util.List; import javax.swing.BorderFactory; -import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JColorChooser; @@ -33,6 +30,7 @@ import net.sf.openrocket.gui.adaptors.DoubleModel; import net.sf.openrocket.gui.adaptors.EnumModel; import net.sf.openrocket.gui.adaptors.MaterialModel; import net.sf.openrocket.gui.components.BasicSlider; +import net.sf.openrocket.gui.components.ColorIcon; import net.sf.openrocket.gui.components.StyledLabel; import net.sf.openrocket.gui.components.StyledLabel.Style; import net.sf.openrocket.gui.components.UnitSelector; @@ -136,7 +134,7 @@ public class RocketComponentConfig extends JPanel { // Component color and "Use default color" checkbox if (colorButton != null && colorDefault != null) { - colorButton.setIcon(new ColorIcon(component.getColor())); + colorButton.setIcon(new ColorIcon(getColor())); if ((component.getColor() == null) != colorDefault.isSelected()) colorDefault.setSelected(component.getColor() == null); @@ -347,7 +345,7 @@ public class RocketComponentConfig extends JPanel { panel.add(new JLabel("Component color:"), "gapleft para, gapright 10lp"); - colorButton = new JButton(new ColorIcon(component.getColor())); + colorButton = new JButton(new ColorIcon(getColor())); colorButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -409,7 +407,15 @@ public class RocketComponentConfig extends JPanel { } - + private Color getColor() { + Color c = component.getColor(); + if (c == null) { + c = Prefs.getDefaultColor(component.getClass()); + } + return c; + } + + protected JPanel shoulderTab() { JPanel panel = new JPanel(new MigLayout("fill")); @@ -578,35 +584,6 @@ public class RocketComponentConfig extends JPanel { } - private class ColorIcon implements Icon { - private final Color color; - - public ColorIcon(Color c) { - this.color = c; - } - - @Override - public int getIconHeight() { - return 15; - } - - @Override - public int getIconWidth() { - return 25; - } - - @Override - public void paintIcon(Component c, Graphics g, int x, int y) { - if (color == null) { - g.setColor(Prefs.getDefaultColor(component.getClass())); - } else { - g.setColor(color); - } - g.fill3DRect(x, y, getIconWidth(), getIconHeight(), false); - } - - } - protected void register(Invalidatable model) { this.invalidatables.add(model); } @@ -617,4 +594,4 @@ public class RocketComponentConfig extends JPanel { } } -} +} \ No newline at end of file diff --git a/src/net/sf/openrocket/gui/dialogs/PrintDialog.java b/src/net/sf/openrocket/gui/dialogs/PrintDialog.java index cfd36be3..1d5556ba 100644 --- a/src/net/sf/openrocket/gui/dialogs/PrintDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/PrintDialog.java @@ -1,209 +1,370 @@ /* - * PrintDialog.java + * PrintPanel.java */ package net.sf.openrocket.gui.dialogs; -import net.sf.openrocket.document.OpenRocketDocument; -import net.sf.openrocket.gui.print.PDFPrintStreamDoc; -import net.sf.openrocket.gui.print.PrintServiceDialog; -import net.sf.openrocket.gui.print.PrintUtilities; - -import javax.print.DocFlavor; -import javax.print.DocPrintJob; -import javax.print.PrintService; -import javax.print.PrintServiceLookup; -import javax.print.attribute.Attribute; -import javax.print.attribute.AttributeSet; -import javax.print.attribute.HashPrintRequestAttributeSet; -import javax.print.attribute.PrintRequestAttributeSet; -import javax.print.attribute.standard.Destination; -import javax.print.attribute.standard.Fidelity; +import java.awt.Desktop; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Iterator; + +import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JDialog; -import java.awt.Dialog; -import java.awt.GraphicsEnvironment; -import java.awt.HeadlessException; -import java.io.ByteArrayOutputStream; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.filechooser.FileFilter; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.document.OpenRocketDocument; +import net.sf.openrocket.gui.main.ExceptionHandler; +import net.sf.openrocket.gui.print.PrintController; +import net.sf.openrocket.gui.print.PrintSettings; +import net.sf.openrocket.gui.print.PrintableContext; +import net.sf.openrocket.gui.print.TemplateProperties; +import net.sf.openrocket.gui.print.components.CheckTreeManager; +import net.sf.openrocket.gui.print.components.RocketPrintTree; +import net.sf.openrocket.logging.LogHelper; +import net.sf.openrocket.rocketcomponent.Rocket; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.util.GUIUtil; +import net.sf.openrocket.util.Prefs; /** - * This class is not a dialog by inheritance, but is by delegation. It front-ends a java print dialog by - * augmenting it with application specific (rocket) settings. + * This class isolates the Swing components used to create a panel that is added to a standard Java print dialog. */ -public class PrintDialog { - - /** - * The service UI dialog. - */ - private PrintServiceDialog dialog; - - /** - * A javax doc flavor specific for printing PDF documents. - */ - private static final DocFlavor.INPUT_STREAM PDF = DocFlavor.INPUT_STREAM.PDF; - - /** - * Construct a print dialog using an Open Rocket document - which contains the rocket data to ultimately be - * printed. - * - * @param orDocument the rocket container - */ - public PrintDialog(OpenRocketDocument orDocument) { - PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null); - PrintService svc = PrintServiceLookup.lookupDefaultPrintService(); - PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet(); - attrs.add(PrintUtilities.getDefaultMedia().getMediaSizeName()); - - final PrintPanel panel = new PrintPanel(orDocument, this); - try { - PrintService ps = printDialog(100, 100, services, svc, PDF, attrs, panel); - if (ps != null) { - DocPrintJob dpj = ps.createPrintJob(); - ByteArrayOutputStream baos = panel.generateReport(); - dpj.print(new PDFPrintStreamDoc(baos, null), attrs); - } - } - catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * Get the set of attributes from the service ui print dialog. - * - * @return a set of print attributes - */ - PrintRequestAttributeSet getAttributes() { - return dialog.getAttributes(); - } - - /** - * Get the service ui dialog. This is the actual dialog that gets displayed - we co-opt it for adding a rocket - * specific tab. - * - * @return the Java service ui print dialog - */ - JDialog getDialog() { - return dialog; - } - - /** - * Mimics the ServiceUI.printDialog method, but with enhancements for our own print settings tab. - * - * @param x location of dialog including border in screen coordinates - * @param y location of dialog including border in screen coordinates - * @param services to be browsable, must be non-null. - * @param defaultService - initial PrintService to display. - * @param flavor - the flavor to be printed, or null. - * @param attributes on input is the initial application supplied preferences. This cannot be null but may be - * empty. On output the attributes reflect changes made by the user. - * @param addnl a panel to be added, as a tab, to the internal tabbed pane of the resulting print dialog - * @return print service selected by the user, or null if the user cancelled the dialog. - * @throws HeadlessException if GraphicsEnvironment.isHeadless() returns true. - * @throws IllegalArgumentException if services is null or empty, or attributes is null, or the initial PrintService - * is not in the list of browsable services. - */ - private PrintService printDialog(int x, int y, - PrintService[] services, - PrintService defaultService, - DocFlavor flavor, - PrintRequestAttributeSet attributes, - PrintPanel addnl) - throws HeadlessException, IllegalArgumentException { - int defaultIndex = -1; - - if (GraphicsEnvironment.isHeadless()) { - throw new HeadlessException(); - } - else if (attributes == null) { - throw new IllegalArgumentException("attributes must be non-null"); - } - - if (defaultService != null && services != null) { - for (int i = 0; i < services.length; i++) { - if (services[i].equals(defaultService)) { - defaultIndex = i; - break; - } - } - - //If the default service is not found just go with the first in the list - if (defaultIndex < 0) { - defaultIndex = 0; - } - } - else { - defaultIndex = -1; - } - - dialog = new PrintServiceDialog( - x, - y, - services, defaultIndex, - flavor, attributes, - (Dialog) null, addnl); - dialog.setVisible(true); - - if (dialog.getStatus() == PrintServiceDialog.APPROVE) { - PrintRequestAttributeSet newas = dialog.getAttributes(); - Class dstCategory = Destination.class; - Class fdCategory = Fidelity.class; - - if (attributes.containsKey(dstCategory) && - !newas.containsKey(dstCategory)) { - attributes.remove(dstCategory); - } - - attributes.addAll(newas); - - Fidelity fd = (Fidelity) attributes.get(fdCategory); - if (fd != null) { - if (fd == Fidelity.FIDELITY_TRUE) { - removeUnsupportedAttributes(dialog.getPrintService(), - flavor, attributes); - } - } - return dialog.getPrintService(); - } - else { - return null; - } - } - - /** - * Removes any attributes from the given AttributeSet that are unsupported by the given PrintService/DocFlavor - * combination. - * - * @param ps the print service for which unsupported attributes will be determined - * @param flavor the document flavor; PDF in our case - * @param aset the set of attributes requested - */ - private static void removeUnsupportedAttributes(PrintService ps, - DocFlavor flavor, - AttributeSet aset) { - AttributeSet asUnsupported = ps.getUnsupportedAttributes(flavor, - aset); - - if (asUnsupported != null) { - Attribute[] usAttrs = asUnsupported.toArray(); - - for (Attribute usAttr : usAttrs) { - Class category = usAttr.getCategory(); - - if (ps.isAttributeCategorySupported(category)) { - Attribute attr = - (Attribute) ps.getDefaultAttributeValue(category); - - if (attr != null) { - aset.add(attr); - } - else { - aset.remove(category); - } - } - else { - aset.remove(category); - } - } - } - } +public class PrintDialog extends JDialog implements TreeSelectionListener { + + private static final LogHelper log = Application.getLogger(); + + private static final String SETTINGS_BUTTON_TEXT = "Settings"; + private static final String PREVIEW_BUTTON_TEXT = "Preview & Print"; + private static final String SAVE_AS_PDF_BUTTON_TEXT = "Save as PDF"; + private static final String SHOW_BY_STAGE = "Show By Stage"; + + private final RocketPrintTree stagedTree; + private final RocketPrintTree noStagedTree; + private OpenRocketDocument document; + private RocketPrintTree currentTree; + private Desktop desktop = null; + + private JButton previewButton; + private JButton saveAsPDF; + private JButton cancel; + + /** + * Constructor. + * + * @param orDocument the OR rocket container + */ + public PrintDialog(Window parent, OpenRocketDocument orDocument) { + super(parent, "Print or export", ModalityType.APPLICATION_MODAL); + + + JPanel panel = new JPanel(new MigLayout("fill, gap rel unrel")); + this.add(panel); + + + // before any Desktop APIs are used, first check whether the API is + // supported by this particular VM on this particular host + if (Desktop.isDesktopSupported()) { + desktop = Desktop.getDesktop(); + } + + document = orDocument; + Rocket rocket = orDocument.getRocket(); + + noStagedTree = RocketPrintTree.create(rocket.getName()); + noStagedTree.setShowsRootHandles(false); + CheckTreeManager ctm = new net.sf.openrocket.gui.print.components.CheckTreeManager(noStagedTree); + ctm.addTreeSelectionListener(this); + + final int stages = rocket.getStageCount(); + + + JLabel label = new JLabel("Select elements to include:"); + panel.add(label, "wrap unrel"); + + // Create the tree + if (stages > 1) { + stagedTree = RocketPrintTree.create(rocket.getName(), rocket.getChildren()); + ctm = new CheckTreeManager(stagedTree); + stagedTree.setShowsRootHandles(false); + ctm.addTreeSelectionListener(this); + } else { + stagedTree = noStagedTree; + } + currentTree = stagedTree; + + // Add the tree to the UI + final JScrollPane scrollPane = new JScrollPane(stagedTree); + panel.add(scrollPane, "width 400lp, height 200lp, grow, wrap para"); + + + // Checkboxes and buttons + final JCheckBox sortByStage = new JCheckBox(SHOW_BY_STAGE); + sortByStage.setEnabled(stages > 1); + sortByStage.setSelected(stages > 1); + sortByStage.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (sortByStage.isEnabled()) { + if (((JCheckBox) e.getSource()).isSelected()) { + scrollPane.setViewportView(stagedTree); + stagedTree.setExpandsSelectedPaths(true); + currentTree = stagedTree; + } + else { + scrollPane.setViewportView(noStagedTree); + noStagedTree.setExpandsSelectedPaths(true); + currentTree = noStagedTree; + } + } + } + }); + panel.add(sortByStage, "aligny top, split"); + + + panel.add(new JPanel(), "growx"); + + + JButton settingsButton = new JButton(SETTINGS_BUTTON_TEXT); + settingsButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + PrintSettings settings = Prefs.getPrintSettings(); + log.debug("settings=" + settings); + PrintSettingsDialog settingsDialog = new PrintSettingsDialog(PrintDialog.this, settings); + settingsDialog.setVisible(true); + Prefs.setPrintSettings(settings); + } + }); + panel.add(settingsButton, "wrap para"); + + + previewButton = new JButton(PREVIEW_BUTTON_TEXT); + previewButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + onPreview(); + PrintDialog.this.setVisible(false); + } + }); + panel.add(previewButton, "split, right, gap para"); + + + saveAsPDF = new JButton(SAVE_AS_PDF_BUTTON_TEXT); + saveAsPDF.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (onSavePDF()) { + PrintDialog.this.setVisible(false); + } + } + }); + panel.add(saveAsPDF, "right, gap para"); + + + cancel = new JButton("Cancel"); + cancel.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + PrintDialog.this.setVisible(false); + } + }); + panel.add(cancel, "right, gap para"); + + + expandAll(currentTree, true); + if (currentTree != noStagedTree) { + expandAll(noStagedTree, true); + } + + + GUIUtil.setDisposableDialogOptions(this, previewButton); + + } + + + @Override + public void valueChanged(final TreeSelectionEvent e) { + final TreePath path = e.getNewLeadSelectionPath(); + if (path != null) { + previewButton.setEnabled(true); + saveAsPDF.setEnabled(true); + } else { + previewButton.setEnabled(false); + saveAsPDF.setEnabled(false); + } + } + + /** + * If expand is true, expands all nodes in the tree. Otherwise, collapses all nodes in the theTree. + * + * @param theTree the tree to expand/contract + * @param expand expand if true, contract if not + */ + public void expandAll(RocketPrintTree theTree, boolean expand) { + TreeNode root = (TreeNode) theTree.getModel().getRoot(); + // Traverse theTree from root + expandAll(theTree, new TreePath(root), expand); + } + + /** + * Recursively walk a tree, and if expand is true, expands all nodes in the tree. Otherwise, collapses all nodes in + * the theTree. + * + * @param theTree the tree to expand/contract + * @param parent the node to iterate/recurse over + * @param expand expand if true, contract if not + */ + private void expandAll(RocketPrintTree theTree, TreePath parent, boolean expand) { + theTree.addSelectionPath(parent); + // Traverse children + TreeNode node = (TreeNode) parent.getLastPathComponent(); + if (node.getChildCount() >= 0) { + for (Enumeration e = node.children(); e.hasMoreElements();) { + TreeNode n = (TreeNode) e.nextElement(); + TreePath path = parent.pathByAddingChild(n); + expandAll(theTree, path, expand); + } + } + // Expansion or collapse must be done bottom-up + if (expand) { + theTree.expandPath(parent); + } else { + theTree.collapsePath(parent); + } + } + + + /** + * Generate a report using a temporary file. The file will be deleted upon JVM exit. + * + * @param paper the name of the paper size + * + * @return a file, populated with the "printed" output (the rocket info) + * + * @throws IOException thrown if the file could not be generated + */ + private File generateReport(PrintSettings settings) throws IOException { + final File f = File.createTempFile("openrocket-", ".pdf"); + f.deleteOnExit(); + return generateReport(f, settings); + } + + /** + * Generate a report to a specified file. + * + * @param f the file to which rocket data will be written + * @param paper the name of the paper size + * + * @return a file, populated with the "printed" output (the rocket info) + * + * @throws IOException thrown if the file could not be generated + */ + private File generateReport(File f, PrintSettings settings) throws IOException { + Iterator toBePrinted = currentTree.getToBePrinted(); + new PrintController().print(document, toBePrinted, new FileOutputStream(f), settings); + return f; + } + + + /** + * Handler for when the Preview button is clicked. + */ + private void onPreview() { + if (desktop != null) { + try { + PrintSettings settings = Prefs.getPrintSettings(); + // TODO: HIGH: Remove UIManager, and pass settings to the actual printing methods + TemplateProperties.setColors(settings); + File f = generateReport(settings); + desktop.open(f); + } catch (IOException e) { + log.error("Could not create temporary file for previewing.", e); + JOptionPane.showMessageDialog(this, "Could not create a temporary file for previewing.", + "Error creating file", JOptionPane.ERROR_MESSAGE); + } + } else { + JOptionPane.showMessageDialog(this, + "Your environment does not support automatically opening the default PDF viewer.", + "Error creating file", JOptionPane.INFORMATION_MESSAGE); + } + } + + /** + * Handler for when the "Save as PDF" button is clicked. + * + * @return true if the PDF was saved + */ + private boolean onSavePDF() { + + JFileChooser chooser = new JFileChooser(); + // Note: source for ExampleFileFilter can be found in FileChooserDemo, + // under the demo/jfc directory in the Java 2 SDK, Standard Edition. + FileFilter filter = new FileFilter() { + + //Accept all directories and all pdf files. + @Override + public boolean accept(File f) { + if (f.isDirectory()) + return true; + return f.getName().toLowerCase().endsWith(".pdf"); + } + + //The description of this filter + @Override + public String getDescription() { + return "PDF files"; + } + }; + chooser.setFileFilter(filter); + int returnVal = chooser.showSaveDialog(this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + + try { + String fname = chooser.getSelectedFile().getCanonicalPath(); + if (!getExtension(fname).equals("pdf")) { + fname = fname + ".pdf"; + } + File f = new File(fname); + PrintSettings settings = Prefs.getPrintSettings(); + // TODO: HIGH: Remove UIManager, and pass settings to the actual printing methods + TemplateProperties.setColors(settings); + generateReport(f, settings); + } catch (IOException e) { + ExceptionHandler.handleErrorCondition(e); + } + return true; + } else { + return false; + } + } + + /** + * Get the extension of a file. + */ + private static String getExtension(String s) { + String ext = null; + int i = s.lastIndexOf('.'); + + if (i > 0 && i < s.length() - 1) { + ext = s.substring(i + 1).toLowerCase(); + } + return ext != null ? ext : ""; + } } diff --git a/src/net/sf/openrocket/gui/dialogs/PrintPanel.java b/src/net/sf/openrocket/gui/dialogs/PrintPanel.java deleted file mode 100644 index 4bc748cd..00000000 --- a/src/net/sf/openrocket/gui/dialogs/PrintPanel.java +++ /dev/null @@ -1,445 +0,0 @@ -/* - * PrintPanel.java - */ -package net.sf.openrocket.gui.dialogs; - -import net.miginfocom.swing.MigLayout; -import net.sf.openrocket.document.OpenRocketDocument; -import net.sf.openrocket.gui.components.ColorChooser; -import net.sf.openrocket.gui.print.PrintController; -import net.sf.openrocket.gui.print.PrintUtilities; -import net.sf.openrocket.gui.print.PrintableContext; -import net.sf.openrocket.gui.print.TemplateProperties; -import net.sf.openrocket.gui.print.components.CheckTreeManager; -import net.sf.openrocket.gui.print.components.RocketPrintTree; -import net.sf.openrocket.logging.LogHelper; -import net.sf.openrocket.rocketcomponent.Rocket; -import net.sf.openrocket.startup.Application; - -import javax.print.attribute.PrintRequestAttributeSet; -import javax.print.attribute.standard.MediaSizeName; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JColorChooser; -import javax.swing.JComponent; -import javax.swing.JDialog; -import javax.swing.JFileChooser; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.UIManager; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.filechooser.FileFilter; -import javax.swing.tree.TreeNode; -import javax.swing.tree.TreePath; -import java.awt.Color; -import java.awt.Desktop; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Enumeration; -import java.util.Iterator; - -/** - * This class isolates the Swing components used to create a panel that is added to a standard Java print dialog. - */ -public class PrintPanel extends JPanel implements TreeSelectionListener { - - private static final LogHelper log = Application.getLogger(); - - private static final String TAB_TITLE = "Rocket"; - private static final String SETTINGS_BUTTON_TEXT = "Settings"; - private static final String PREVIEW_BUTTON_TEXT = "Preview"; - private static final String SAVE_AS_PDF_BUTTON_TEXT = "Save as PDF"; - private static final String SHOW_BY_STAGE = "Show By Stage"; - - private final RocketPrintTree stagedTree; - private final RocketPrintTree noStagedTree; - private OpenRocketDocument rocDoc; - private RocketPrintTree currentTree; - private boolean bDesktopSupported = false; - private Desktop desktop; - private PrintDialog printDialog; - - JButton previewButton; - JButton saveAsPDF; - - /** - * Constructor. - * - * @param orDocument the OR rocket container - * @param theParent the OR parent print dialog - */ - public PrintPanel (OpenRocketDocument orDocument, PrintDialog theParent) { - - super(new MigLayout("fill, gap rel unrel")); - - // before any Desktop APIs are used, first check whether the API is - // supported by this particular VM on this particular host - if (Desktop.isDesktopSupported()) { - bDesktopSupported = true; - desktop = Desktop.getDesktop(); - } - - printDialog = theParent; - rocDoc = orDocument; - Rocket rocket = orDocument.getRocket(); - - noStagedTree = RocketPrintTree.create(rocket.getName()); - noStagedTree.setShowsRootHandles(false); - CheckTreeManager ctm = new net.sf.openrocket.gui.print.components.CheckTreeManager(noStagedTree); - ctm.addTreeSelectionListener(this); - - final int stages = rocket.getStageCount(); - - if (stages > 1) { - stagedTree = RocketPrintTree.create(rocket.getName(), rocket.getChildren()); - ctm = new CheckTreeManager(stagedTree); - stagedTree.setShowsRootHandles(false); - ctm.addTreeSelectionListener(this); - } - else { - stagedTree = noStagedTree; - } - currentTree = stagedTree; - - final JScrollPane scrollPane = new JScrollPane(stagedTree); - add(scrollPane, "width 416!, wrap"); - - final JCheckBox sortByStage = new JCheckBox(SHOW_BY_STAGE); - sortByStage.setEnabled(stages > 1); - sortByStage.setSelected(stages > 1); - sortByStage.addActionListener(new ActionListener() { - public void actionPerformed (ActionEvent e) { - if (sortByStage.isEnabled()) { - if (((JCheckBox) e.getSource()).isSelected()) { - scrollPane.setViewportView(stagedTree); - stagedTree.setExpandsSelectedPaths(true); - currentTree = stagedTree; - } - else { - scrollPane.setViewportView(noStagedTree); - noStagedTree.setExpandsSelectedPaths(true); - currentTree = noStagedTree; - } - } - } - }); - add(sortByStage, "wrap"); - - saveAsPDF = new JButton(SAVE_AS_PDF_BUTTON_TEXT); - saveAsPDF.addActionListener(new ActionListener() { - @Override - public void actionPerformed (ActionEvent e) { - onSavePDF(PrintPanel.this); - } - }); - add(saveAsPDF, "span 2, tag save"); - - previewButton = new JButton(PREVIEW_BUTTON_TEXT); - previewButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed (ActionEvent e) { - onPreview(); - } - }); - add(previewButton, "x 150"); - - JButton settingsButton = new JButton(SETTINGS_BUTTON_TEXT); - settingsButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed (ActionEvent e) { - PrintSettingsDialog settingsDialog = new PrintSettingsDialog(printDialog.getDialog()); - settingsDialog.setVisible(true); - } - }); - add(settingsButton, "x 340"); - - expandAll(currentTree, true); - if (currentTree != noStagedTree) { - expandAll(noStagedTree, true); - } - setVisible(true); - } - - /** - * The title of the tab that gets displayed for this panel, when placed in the print dialog. - * - * @return a title - */ - public String getTitle () { - return TAB_TITLE; - } - - @Override - public String getName() { - return getTitle(); - } - - @Override - public void valueChanged (final TreeSelectionEvent e) { - final TreePath path = e.getNewLeadSelectionPath(); - if (path != null){ - previewButton.setEnabled(true); - saveAsPDF.setEnabled(true); - } - else { - previewButton.setEnabled(false); - saveAsPDF.setEnabled(false); - } - } - - /** - * If expand is true, expands all nodes in the tree. Otherwise, collapses all nodes in the theTree. - * - * @param theTree the tree to expand/contract - * @param expand expand if true, contract if not - */ - public void expandAll (RocketPrintTree theTree, boolean expand) { - TreeNode root = (TreeNode) theTree.getModel().getRoot(); - // Traverse theTree from root - expandAll(theTree, new TreePath(root), expand); - } - - /** - * Recursively walk a tree, and if expand is true, expands all nodes in the tree. Otherwise, collapses all nodes in - * the theTree. - * - * @param theTree the tree to expand/contract - * @param parent the node to iterate/recurse over - * @param expand expand if true, contract if not - */ - private void expandAll (RocketPrintTree theTree, TreePath parent, boolean expand) { - theTree.addSelectionPath(parent); - // Traverse children - TreeNode node = (TreeNode) parent.getLastPathComponent(); - if (node.getChildCount() >= 0) { - for (Enumeration e = node.children(); e.hasMoreElements();) { - TreeNode n = (TreeNode) e.nextElement(); - TreePath path = parent.pathByAddingChild(n); - expandAll(theTree, path, expand); - } - } - // Expansion or collapse must be done bottom-up - if (expand) { - theTree.expandPath(parent); - } - else { - theTree.collapsePath(parent); - } - } - - /** - * Get a media size name (the name of a paper size). If no page size is selected, it will default to the locale - * specific page size (LETTER in North America, A4 elsewhere). - * - * @return the name of a page size - */ - private MediaSizeName getMediaSize () { - MediaSizeName paperSize = getMediaSize(printDialog.getAttributes()); - if (paperSize == null) { - paperSize = PrintUtilities.getDefaultMedia().getMediaSizeName(); - } - return paperSize; - } - - /** - * Get the media size name (the name of a paper size) as selected by the user. - * - * @param atts the set of selected printer attributes - * - * @return a media size name, may be null - */ - private MediaSizeName getMediaSize (PrintRequestAttributeSet atts) { - return (MediaSizeName) atts.get(javax.print.attribute.standard.Media.class); - } - - /** - * Generate a report using a temporary file. The file will be deleted upon JVM exit. - * - * @param paper the name of the paper size - * - * @return a file, populated with the "printed" output (the rocket info) - * - * @throws IOException thrown if the file could not be generated - */ - private File generateReport (MediaSizeName paper) throws IOException { - final File f = File.createTempFile("oro", ".pdf"); - f.deleteOnExit(); - return generateReport(f, paper); - } - - /** - * Generate a report to a specified file. - * - * @param f the file to which rocket data will be written - * @param paper the name of the paper size - * - * @return a file, populated with the "printed" output (the rocket info) - * - * @throws IOException thrown if the file could not be generated - */ - private File generateReport (File f, MediaSizeName paper) throws IOException { - Iterator toBePrinted = currentTree.getToBePrinted(); - new PrintController().print(rocDoc, toBePrinted, new FileOutputStream(f), paper); - return f; - } - - /** - * Generate a report to a byte array output stream. - * - * @return a stream populated with the "printed" output (the rocket info) - */ - public ByteArrayOutputStream generateReport() { - Iterator toBePrinted = currentTree.getToBePrinted(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - new PrintController().print(rocDoc, toBePrinted, baos, getMediaSize ()); - return baos; - } - - /** - * Handler for when the Preview button is clicked. - */ - private void onPreview () { - if (bDesktopSupported) { - try { - MediaSizeName paperSize = getMediaSize(); - File f = generateReport(paperSize); - desktop.open(f); - } - catch (IOException e) { - log.error("Could not create temporary file for previewing.", e); - JOptionPane.showMessageDialog(this, "Could not create a temporary file for previewing.", - "Error creating file", JOptionPane.ERROR_MESSAGE); - } - } - else { - JOptionPane.showMessageDialog(this, - "Your environment does not support automatically opening the default PDF viewer.", - "Error creating file", JOptionPane.INFORMATION_MESSAGE); - } - } - - /** - * Handler for when the "Save as PDF" button is clicked. - * - * @param p the component to parent the save dialog to - */ - private void onSavePDF (JComponent p) { - - JFileChooser chooser = new JFileChooser(); - // Note: source for ExampleFileFilter can be found in FileChooserDemo, - // under the demo/jfc directory in the Java 2 SDK, Standard Edition. - FileFilter filter = new FileFilter() { - - //Accept all directories and all pdf files. - public boolean accept (File f) { - return true; - } - - //The description of this filter - public String getDescription () { - return "pdf"; - } - }; - chooser.setFileFilter(filter); - int returnVal = chooser.showSaveDialog(p); - if (returnVal == JFileChooser.APPROVE_OPTION) { - - try { - String fname = chooser.getSelectedFile().getCanonicalPath(); - if (!getExtension(fname).equals("pdf")) { - fname = fname + ".pdf"; - } - File f = new File(fname); - generateReport(f, getMediaSize()); - } - catch (IOException e) { - e.printStackTrace(); - } - } - } - - /** - * Get the extension of a file. - */ - private static String getExtension (String s) { - String ext = null; - int i = s.lastIndexOf('.'); - - if (i > 0 && i < s.length() - 1) { - ext = s.substring(i + 1).toLowerCase(); - } - return ext != null ? ext : ""; - } -} - -/** - * This class is a dialog for displaying advanced settings for printing rocket related info. - */ -class PrintSettingsDialog extends JDialog { - - /** - * The fill color chooser. - */ - private ColorChooser fill; - - /** - * The line color chooser. - */ - private ColorChooser line; - - /** - * Construct a dialog for setting the advanced rocket print settings. - * - * @param parent the owning dialog - */ - public PrintSettingsDialog (JDialog parent) { - super(parent, "Advanced Settings", true); - setLayout(new MigLayout("fill")); - - JPanel settingsPanel = new JPanel(); - settingsPanel.setLayout(new MigLayout("gap rel")); - - fill = addColorChooser(settingsPanel, "Template Fill", TemplateProperties.getFillColor()); - line = addColorChooser(settingsPanel, "Template Line", TemplateProperties.getLineColor()); - - settingsPanel.add(fill); - settingsPanel.add(line); - - add(settingsPanel, "wrap"); - - JButton closeButton = new JButton("Close"); - closeButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed (ActionEvent e) { - UIManager.put(TemplateProperties.TEMPLATE_FILL_COLOR_PROPERTY, fill.getCurrentColor()); - UIManager.put(TemplateProperties.TEMPLATE_LINE_COLOR_PROPERTY, line.getCurrentColor()); - dispose(); - } - }); - add(closeButton, "right, gapright para"); - - setSize(400, 200); - } - - /** - * Add a color chooser to a panel. - * - * @param panel the parent panel to add the color chooser. - * @param label the label that indicates which color property is being changed - * @param initialColor the initial, or current, color to display - * - * @return a swing component containing a label, a colorized field, and a button that when clicked opens a color - * chooser dialog - */ - private ColorChooser addColorChooser (JPanel panel, String label, Color initialColor) { - final JColorChooser colorChooser = new JColorChooser(initialColor); - return new ColorChooser(panel, colorChooser, label); - } - -} diff --git a/src/net/sf/openrocket/gui/dialogs/PrintSettingsDialog.java b/src/net/sf/openrocket/gui/dialogs/PrintSettingsDialog.java new file mode 100644 index 00000000..66286ab2 --- /dev/null +++ b/src/net/sf/openrocket/gui/dialogs/PrintSettingsDialog.java @@ -0,0 +1,111 @@ +package net.sf.openrocket.gui.dialogs; + +import java.awt.Color; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.gui.adaptors.EnumModel; +import net.sf.openrocket.gui.components.ColorChooserButton; +import net.sf.openrocket.gui.print.PaperOrientation; +import net.sf.openrocket.gui.print.PaperSize; +import net.sf.openrocket.gui.print.PrintSettings; +import net.sf.openrocket.logging.LogHelper; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.util.GUIUtil; + +/** + * This class is a dialog for displaying advanced settings for printing rocket related info. + */ +public class PrintSettingsDialog extends JDialog { + private static final LogHelper log = Application.getLogger(); + + + /** + * Construct a dialog for setting the advanced rocket print settings. + * + * @param parent the owning dialog + */ + public PrintSettingsDialog(Window parent, final PrintSettings settings) { + super(parent, "Print settings", ModalityType.APPLICATION_MODAL); + + + JPanel panel = new JPanel(new MigLayout("fill")); + + + panel.add(new JLabel("Template fill color:")); + final ColorChooserButton fillColorButton = new ColorChooserButton(settings.getTemplateFillColor()); + fillColorButton.addColorPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + Color c = (Color) evt.getNewValue(); + log.info("Template fill color changed to " + c); + settings.setTemplateFillColor(c); + } + }); + panel.add(fillColorButton, "wrap para"); + + + panel.add(new JLabel("Template border color:")); + final ColorChooserButton borderColorButton = new ColorChooserButton(settings.getTemplateBorderColor()); + borderColorButton.addColorPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + Color c = (Color) evt.getNewValue(); + log.info("Template border color changed to " + c); + settings.setTemplateBorderColor(c); + } + }); + panel.add(borderColorButton, "wrap para*2"); + + + + JComboBox combo = new JComboBox(new EnumModel(settings, "PaperSize")); + panel.add(new JLabel("Paper size:")); + panel.add(combo, "growx, wrap para"); + + + combo = new JComboBox(new EnumModel(settings, "PaperOrientation")); + panel.add(new JLabel("Paper orientation:")); + panel.add(combo, "growx, wrap para*2"); + + + + + + JButton button = new JButton("Reset"); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + log.user("Resetting print setting values to defaults"); + PrintSettings defaults = new PrintSettings(); + settings.loadFrom(defaults); + } + }); + panel.add(button, "spanx, split, right"); + + + JButton closeButton = new JButton("Close"); + closeButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + PrintSettingsDialog.this.setVisible(false); + } + }); + panel.add(closeButton, "right"); + + this.add(panel); + GUIUtil.setDisposableDialogOptions(this, closeButton); + } + + +} diff --git a/src/net/sf/openrocket/gui/main/BasicFrame.java b/src/net/sf/openrocket/gui/main/BasicFrame.java index d7fd4ec1..2605dc7d 100644 --- a/src/net/sf/openrocket/gui/main/BasicFrame.java +++ b/src/net/sf/openrocket/gui/main/BasicFrame.java @@ -483,7 +483,7 @@ public class BasicFrame extends JFrame { menu.add(item); - item = new JMenuItem("Print...", KeyEvent.VK_P); + item = new JMenuItem("Print / Export PDF...", KeyEvent.VK_P); item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.CTRL_MASK)); item.getAccessibleContext().setAccessibleDescription("Print parts list and fin template"); item.setIcon(Icons.FILE_PRINT); @@ -1310,7 +1310,7 @@ public class BasicFrame extends JFrame { "Experimental feature", JOptionPane.WARNING_MESSAGE); Prefs.putBoolean("printing.experimental.communicated", true); } - new PrintDialog(document); + new PrintDialog(this, document).setVisible(true); } /** diff --git a/src/net/sf/openrocket/gui/main/ExceptionHandler.java b/src/net/sf/openrocket/gui/main/ExceptionHandler.java index cd4af70b..15e0cbf0 100644 --- a/src/net/sf/openrocket/gui/main/ExceptionHandler.java +++ b/src/net/sf/openrocket/gui/main/ExceptionHandler.java @@ -338,6 +338,22 @@ public class ExceptionHandler implements Thread.UncaughtExceptionHandler { } } + + /* + * Detect and ignore bug 6933331 in Sun JRE 1.6.0_18 and others + */ + if (t instanceof IllegalStateException) { + StackTraceElement[] trace = t.getStackTrace(); + + if (trace.length > 1 && + trace[0].getClassName().equals("sun.awt.windows.WComponentPeer") && + trace[0].getMethodName().equals("getBackBuffer")) { + log.warn("Ignoring Sun JRE bug 6933331 " + + "(see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6933331): " + t); + return true; + } + } + /* * Detect and ignore bug in Sun JRE 1.6.0_19 */ diff --git a/src/net/sf/openrocket/gui/print/PaperOrientation.java b/src/net/sf/openrocket/gui/print/PaperOrientation.java new file mode 100644 index 00000000..0e973e0f --- /dev/null +++ b/src/net/sf/openrocket/gui/print/PaperOrientation.java @@ -0,0 +1,42 @@ +package net.sf.openrocket.gui.print; + +import com.itextpdf.text.Rectangle; +import com.itextpdf.text.RectangleReadOnly; + +public enum PaperOrientation { + + PORTRAIT("Portrait") { + @Override + public Rectangle orient(Rectangle rect) { + return new RectangleReadOnly(rect); + } + }, + LANDSCAPE("Landscape") { + @Override + public Rectangle orient(Rectangle rect) { + return new RectangleReadOnly(new Rectangle(rect).rotate()); + } + }; + + + private final String name; + + private PaperOrientation(String name) { + this.name = name; + } + + /** + * Change the orientation of a portrait paper to the orientation represented by this + * orientation. + * + * @param rect the original paper size rectangle + * @return the oriented paper size rectangle + */ + public abstract Rectangle orient(Rectangle rect); + + + @Override + public String toString() { + return name; + } +} diff --git a/src/net/sf/openrocket/gui/print/PaperSize.java b/src/net/sf/openrocket/gui/print/PaperSize.java index 63930e2a..d3d07410 100644 --- a/src/net/sf/openrocket/gui/print/PaperSize.java +++ b/src/net/sf/openrocket/gui/print/PaperSize.java @@ -1,247 +1,193 @@ -/* - * PaperSize.java - */ package net.sf.openrocket.gui.print; -import com.itextpdf.text.PageSize; -import com.itextpdf.text.Rectangle; -import com.itextpdf.text.RectangleReadOnly; - -import javax.print.attribute.standard.MediaSizeName; -import java.util.HashMap; -import java.util.Map; - -/** - * Various mappings of paper sizes and their names. - */ -public class PaperSize { - - /** Map of name to MediaSizeName instance. */ - private static Map paperNames = new HashMap(); - /** Map of identifying name to displayable name. */ - private static Map displayableNames = new HashMap(); - /** Map of MediaSizeName to rectangle, which defines the paper size. */ - private static Map paperItext = new HashMap(); - - /** - * Init. - */ - static { - populateNameMap(); - populateITextSizeMap(); - populateDisplayableNameMap(); - } +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.Locale; - /** Disallow construction. */ - private PaperSize() {} +import net.sf.openrocket.logging.LogHelper; +import net.sf.openrocket.startup.Application; - /** - * Map an identifying paper name to it's corresponding MediaSizeName. - * - * @param name a paper name - * - * @return the associated MediaSizeName (or null if not found). - */ - public static MediaSizeName convert(String name) { - return paperNames.get(name); - } - - /** - * Map a MediaSizeName to it's size Rectangle. - * - * @param name a paper name - * - * @return a Rectangle or null - */ - public static Rectangle convert(MediaSizeName name) { - return paperItext.get(name); - } - - /** - * Map an identifying paper name to a displayable name (usually it's common name). - * - * @param name a paper name - * - * @return a displayable name - */ - public static String toDisplayable(String name) { - return displayableNames.get(name); - } - - private static void populateNameMap() { - paperNames.put("iso-a0", MediaSizeName.ISO_A0); - paperNames.put("iso-a1", MediaSizeName.ISO_A1); - paperNames.put("iso-a2", MediaSizeName.ISO_A2); - paperNames.put("iso-a3", MediaSizeName.ISO_A3); - paperNames.put("iso-a4", MediaSizeName.ISO_A4); - paperNames.put("iso-a5", MediaSizeName.ISO_A5); - paperNames.put("iso-a6", MediaSizeName.ISO_A6); - paperNames.put("iso-a7", MediaSizeName.ISO_A7); - paperNames.put("iso-a8", MediaSizeName.ISO_A8); - paperNames.put("iso-a9", MediaSizeName.ISO_A9); - paperNames.put("iso-a10", MediaSizeName.ISO_A10); - paperNames.put("iso-b0", MediaSizeName.ISO_B0); - paperNames.put("iso-b1", MediaSizeName.ISO_B1); - paperNames.put("iso-b2", MediaSizeName.ISO_B2); - paperNames.put("iso-b3", MediaSizeName.ISO_B3); - paperNames.put("iso-b4", MediaSizeName.ISO_B4); - paperNames.put("iso-b5", MediaSizeName.ISO_B5); - paperNames.put("iso-b6", MediaSizeName.ISO_B6); - paperNames.put("iso-b7", MediaSizeName.ISO_B7); - paperNames.put("iso-b8", MediaSizeName.ISO_B8); - paperNames.put("iso-b9", MediaSizeName.ISO_B9); - paperNames.put("iso-b10", MediaSizeName.ISO_B10); - paperNames.put("na-letter", MediaSizeName.NA_LETTER); - paperNames.put("na-legal", MediaSizeName.NA_LEGAL); - paperNames.put("na-8x10", MediaSizeName.NA_8X10); - paperNames.put("na-5x7", MediaSizeName.NA_5X7); - paperNames.put("executive", MediaSizeName.EXECUTIVE); - paperNames.put("folio", MediaSizeName.FOLIO); - paperNames.put("invoice", MediaSizeName.INVOICE); - paperNames.put("tabloid", MediaSizeName.TABLOID); - paperNames.put("ledger", MediaSizeName.LEDGER); - paperNames.put("quarto", MediaSizeName.QUARTO); - paperNames.put("iso-c0", MediaSizeName.ISO_C0); - paperNames.put("iso-c1", MediaSizeName.ISO_C1); - paperNames.put("iso-c2", MediaSizeName.ISO_C2); - paperNames.put("iso-c3", MediaSizeName.ISO_C3); - paperNames.put("iso-c4", MediaSizeName.ISO_C4); - paperNames.put("iso-c5", MediaSizeName.ISO_C5); - paperNames.put("iso-c6", MediaSizeName.ISO_C6); - paperNames.put("iso-designated-long", MediaSizeName.ISO_DESIGNATED_LONG); - paperNames.put("jis-b0", MediaSizeName.JIS_B0); - paperNames.put("jis-b1", MediaSizeName.JIS_B1); - paperNames.put("jis-b2", MediaSizeName.JIS_B2); - paperNames.put("jis-b3", MediaSizeName.JIS_B3); - paperNames.put("jis-b4", MediaSizeName.JIS_B4); - paperNames.put("jis-b5", MediaSizeName.JIS_B5); - paperNames.put("jis-b6", MediaSizeName.JIS_B6); - paperNames.put("jis-b7", MediaSizeName.JIS_B7); - paperNames.put("jis-b8", MediaSizeName.JIS_B8); - paperNames.put("jis-b9", MediaSizeName.JIS_B9); - paperNames.put("jis-b10", MediaSizeName.JIS_B10); - paperNames.put("a", MediaSizeName.A); - paperNames.put("b", MediaSizeName.B); - paperNames.put("c", MediaSizeName.C); - paperNames.put("d", MediaSizeName.D); - paperNames.put("e", MediaSizeName.E); - } - - private static void populateITextSizeMap() { - paperItext.put(MediaSizeName.ISO_A0, PageSize.A0); - paperItext.put(MediaSizeName.ISO_A1, PageSize.A1); - paperItext.put(MediaSizeName.ISO_A2, PageSize.A2); - paperItext.put(MediaSizeName.ISO_A3, PageSize.A3); - paperItext.put(MediaSizeName.ISO_A4, PageSize.A4); - paperItext.put(MediaSizeName.ISO_A5, PageSize.A5); - paperItext.put(MediaSizeName.ISO_A6, PageSize.A6); - paperItext.put(MediaSizeName.ISO_A7, PageSize.A7); - paperItext.put(MediaSizeName.ISO_A8, PageSize.A8); - paperItext.put(MediaSizeName.ISO_A9, PageSize.A9); - paperItext.put(MediaSizeName.ISO_A10, PageSize.A10); - paperItext.put(MediaSizeName.ISO_B0, PageSize.B0); - paperItext.put(MediaSizeName.ISO_B1, PageSize.B1); - paperItext.put(MediaSizeName.ISO_B2, PageSize.B2); - paperItext.put(MediaSizeName.ISO_B3, PageSize.B3); - paperItext.put(MediaSizeName.ISO_B4, PageSize.B4); - paperItext.put(MediaSizeName.ISO_B5, PageSize.B5); - paperItext.put(MediaSizeName.ISO_B6, PageSize.B6); - paperItext.put(MediaSizeName.ISO_B7, PageSize.B7); - paperItext.put(MediaSizeName.ISO_B8, PageSize.B8); - paperItext.put(MediaSizeName.ISO_B9, PageSize.B9); - paperItext.put(MediaSizeName.ISO_B10, PageSize.B10); - paperItext.put(MediaSizeName.NA_LETTER, PageSize.LETTER); - paperItext.put(MediaSizeName.NA_LEGAL, PageSize.LEGAL); - paperItext.put(MediaSizeName.EXECUTIVE, PageSize.EXECUTIVE); - paperItext.put(MediaSizeName.A, PageSize.LETTER); - paperItext.put(MediaSizeName.B, PageSize._11X17); - paperItext.put(MediaSizeName.C, new RectangleReadOnly(PrintUnit.INCHES.toPoints(17), PrintUnit.INCHES.toPoints(22))); - paperItext.put(MediaSizeName.D, new RectangleReadOnly(PrintUnit.INCHES.toPoints(22), PrintUnit.INCHES.toPoints(34))); - paperItext.put(MediaSizeName.E, new RectangleReadOnly(PrintUnit.INCHES.toPoints(34), PrintUnit.INCHES.toPoints(44))); - } +import com.itextpdf.text.PageSize; +import com.itextpdf.text.Rectangle; - /** - * Create a name map from standard to displayable names - */ - private static void populateDisplayableNameMap() { - displayableNames.put("iso-a0", "A0"); - displayableNames.put("iso-a1", "A1"); - displayableNames.put("iso-a2", "A2"); - displayableNames.put("iso-a3", "A3"); - displayableNames.put("iso-a4", "A4"); - displayableNames.put("iso-a5", "A5"); - displayableNames.put("iso-a6", "A6"); - displayableNames.put("iso-a7", "A7"); - displayableNames.put("iso-a8", "A8"); - displayableNames.put("iso-a9", "A9"); - displayableNames.put("iso-a10", "A10"); - displayableNames.put("iso-b0", "B0"); - displayableNames.put("iso-b1", "B1"); - displayableNames.put("iso-b2", "B2"); - displayableNames.put("iso-b3", "B3"); - displayableNames.put("iso-b4", "B4"); - displayableNames.put("iso-b5", "B5"); - displayableNames.put("iso-b6", "B6"); - displayableNames.put("iso-b7", "B7"); - displayableNames.put("iso-b8", "B8"); - displayableNames.put("iso-b9", "B9"); - displayableNames.put("iso-b10", "B10"); - displayableNames.put("na-letter", "US Letter"); - displayableNames.put("na-legal", "US Legal"); - displayableNames.put("na-8x10", "US 8x10 inch"); - displayableNames.put("na-5x7", "US 5x7 inch"); - displayableNames.put("executive", "Executive"); - displayableNames.put("folio", "Folio"); - displayableNames.put("invoice", "Invoice"); - displayableNames.put("tabloid", "Tabloid"); - displayableNames.put("ledger", "Ledger"); - displayableNames.put("quarto", "Quarto"); - displayableNames.put("iso-c0", "C0"); - displayableNames.put("iso-c1", "C1"); - displayableNames.put("iso-c2", "C2"); - displayableNames.put("iso-c3", "C3"); - displayableNames.put("iso-c4", "C4"); - displayableNames.put("iso-c5", "C5"); - displayableNames.put("iso-c6", "C6"); - displayableNames.put("iso-designated-long", "ISO Designated Long Size"); - displayableNames.put("jis-b0", "Japanese B0"); - displayableNames.put("jis-b1", "Japanese B1"); - displayableNames.put("jis-b2", "Japanese B2"); - displayableNames.put("jis-b3", "Japanese B3"); - displayableNames.put("jis-b4", "Japanese B4"); - displayableNames.put("jis-b5", "Japanese B5"); - displayableNames.put("jis-b6", "Japanese B6"); - displayableNames.put("jis-b7", "Japanese B7"); - displayableNames.put("jis-b8", "Japanese B8"); - displayableNames.put("jis-b9", "Japanese B9"); - displayableNames.put("jis-b10", "Japanese B10"); - displayableNames.put("a", "US Letter"); - displayableNames.put("b", "Engineering ANSI B"); - displayableNames.put("c", "Engineering ANSI C"); - displayableNames.put("d", "Engineering ANSI D"); - displayableNames.put("e", "Engineering ANSI E"); - displayableNames.put("arch-a", "Architectural A"); - displayableNames.put("arch-b", "Architectural B"); - displayableNames.put("arch-c", "Architectural C"); - displayableNames.put("arch-d", "Architectural D"); - displayableNames.put("arch-e", "Architectural E"); - displayableNames.put("japanese-postcard", "Japanese Postcard"); - displayableNames.put("oufuko-postcard", "Oufuko Postcard"); - displayableNames.put("italian-envelope", "Italian Envelope"); - displayableNames.put("personal-envelope", "Personal Envelope"); - displayableNames.put("na-number-11-envelope", "#11 Envelope"); - displayableNames.put("na-number-12-envelope", "#12 Envelope"); - displayableNames.put("na-number-14-envelope", "#14 Envelope"); - displayableNames.put("na-10x13-envelope", "10\"x13\" Envelope"); - displayableNames.put("na-9x12-envelope", "9\"x12\" Envelope"); - displayableNames.put("na-number-10-envelope", "#10 Envelope"); - displayableNames.put("na-7x9-envelope", "7\"x9\" Envelope"); - displayableNames.put("na-9x11-envelope", "9\"x11\" Envelope"); - displayableNames.put("na-10x14-envelope", "10\"x14\" Envelope"); - displayableNames.put("na-number-9-envelope", "#9 Envelope"); - displayableNames.put("na-6x9-envelope", "6\"x9\" Envelope"); - displayableNames.put("na-10x15-envelope", "10\"x15\" Envelope"); - displayableNames.put("monarch-envelope", "Monarch Envelope"); - } +public enum PaperSize { + A3("A3", PageSize.A3), + A4("A4", PageSize.A4), + A5("A5", PageSize.A5), + LETTER("Letter", PageSize.LETTER), + LEGAL("Legal", PageSize.LEGAL); + + private final String name; + private final Rectangle size; + + private PaperSize(String name, Rectangle size) { + this.name = name; + this.size = size; + } + + public Rectangle getSize() { + return size; + } + + @Override + public String toString() { + return name; + } + + + ////////////////////////// + + private static final LogHelper log = Application.getLogger(); + private static PaperSize defaultSize = null; + + /** + * Return the default paper size for the current system. + * @return the default paper size + */ + public static PaperSize getDefault() { + if (defaultSize == null) { + + // Test environment variable "PAPERSIZE" (Unix) + defaultSize = getDefaultFromEnvironmentVariable(); + if (defaultSize != null) { + log.info("Selecting default paper size from PAPERSIZE environment variable: " + defaultSize); + return defaultSize; + } + + // Test /etc/papersize (Unix) + defaultSize = getDefaultFromEtcPapersize(); + if (defaultSize != null) { + log.info("Selecting default paper size from /etc/papersize: " + defaultSize); + return defaultSize; + } + + // Test user.country + defaultSize = getDefaultForCountry(System.getProperty("user.country")); + if (defaultSize != null) { + log.info("Selecting default paper size based on user.country: " + defaultSize); + return defaultSize; + } + + // Test locale country + defaultSize = getDefaultForCountry(Locale.getDefault().getCountry()); + if (defaultSize != null) { + log.info("Selecting default paper size based on locale country: " + defaultSize); + return defaultSize; + } + + // Fallback to A4 + defaultSize = A4; + log.info("Selecting default paper size fallback: " + defaultSize); + } + + return defaultSize; + } + + + /** + * Attempt to read the default paper size from the "PAPERSIZE" environment variable. + * + * @return the default paper size if successful, or null if unable to read/parse file. + */ + private static PaperSize getDefaultFromEnvironmentVariable() { + String str = System.getenv("PAPERSIZE"); + return getSizeFromString(str); + } + + /** + * Attempt to read the default paper size from the file defined by the environment variable + * PAPERCONF or from /etc/papersize. + * + * @return the default paper size if successful, or null if unable to read/parse file. + */ + private static PaperSize getDefaultFromEtcPapersize() { + + // Find file to read + String file = System.getenv("PAPERCONF"); + if (file == null) { + file = "/etc/papersize"; + } + + // Attempt to read the file + BufferedReader in = null; + try { + + String str; + in = new BufferedReader(new FileReader(file)); + while ((str = in.readLine()) != null) { + if (str.matches("^\\s*(#.*|$)")) { + continue; + } + break; + } + + return getSizeFromString(str); + + } catch (IOException e) { + + // Could not read file + return null; + + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + } + } + } + } + + + /** + * Get a paper size based on a string. The string is trimmed and case-insensitively + * compared to the base names of the paper sizes. + * + * @param size the size string (may be null) + * @return the corresponding paper size, or null if unknown + */ + static PaperSize getSizeFromString(String size) { + if (size == null) { + return null; + } + + size = size.trim(); + for (PaperSize p : PaperSize.values()) { + if (p.name.equalsIgnoreCase(size)) { + return p; + } + } + return null; + } + + + /** + * Get default paper size for a specific country. This method falls back to A4 for + * any country not known to use Letter. + * + * @param country the 2-char country code (may be null) + * @return the paper size, or null if country is not a country code + */ + static PaperSize getDefaultForCountry(String country) { + /* + * List is based on info from http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/territory_language_information.html + * OpenOffice.org agrees with this: http://wiki.services.openoffice.org/wiki/DefaultPaperSize#Summary + */ + final String[] letterCountries = { "BZ", "CA", "CL", "CO", "CR", "SV", "GT", "MX", "NI", "PA", "PH", "PR", "US", "VE" }; + + if (country == null || !country.matches("^[a-zA-Z][a-zA-Z]$")) { + return null; + } + + country = country.toUpperCase(); + for (String c : letterCountries) { + if (c.equals(country)) { + return LETTER; + } + } + return A4; + } + } diff --git a/src/net/sf/openrocket/gui/print/PrintController.java b/src/net/sf/openrocket/gui/print/PrintController.java index 1ff040bb..0a71bbbe 100644 --- a/src/net/sf/openrocket/gui/print/PrintController.java +++ b/src/net/sf/openrocket/gui/print/PrintController.java @@ -4,6 +4,15 @@ */ package net.sf.openrocket.gui.print; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.Set; + +import net.sf.openrocket.document.OpenRocketDocument; +import net.sf.openrocket.gui.print.visitor.FinSetVisitorStrategy; +import net.sf.openrocket.gui.print.visitor.PartsDetailVisitorStrategy; + import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.ExceptionConverter; @@ -11,107 +20,92 @@ import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.PdfBoolean; import com.itextpdf.text.pdf.PdfName; import com.itextpdf.text.pdf.PdfWriter; -import net.sf.openrocket.document.OpenRocketDocument; -import net.sf.openrocket.gui.print.visitor.FinSetVisitorStrategy; -import net.sf.openrocket.gui.print.visitor.PartsDetailVisitorStrategy; - -import javax.print.attribute.standard.MediaSizeName; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Iterator; -import java.util.Set; /** * This is the main active object for printing. It performs all actions necessary to create and populate the print * file. */ public class PrintController { - - /** - * Print the selected components to a PDF document. - * - * @param doc the OR document - * @param toBePrinted the user chosen items to print - * @param outputFile the file being written to - * @param msn the paper size - */ - public void print(OpenRocketDocument doc, Iterator toBePrinted, OutputStream outputFile, - MediaSizeName msn) { - - Document idoc = new Document(convertWithDefault(msn)); - PdfWriter writer = null; - try { - writer = PdfWriter.getInstance(idoc, outputFile); - writer.setStrictImageSequence(true); - - writer.addViewerPreference(PdfName.PRINTSCALING, PdfName.NONE); - writer.addViewerPreference(PdfName.PICKTRAYBYPDFSIZE, PdfBoolean.PDFTRUE); - try { - idoc.open(); - Thread.sleep(1000); - } - catch (InterruptedException e) { - } - while (toBePrinted.hasNext()) { - PrintableContext printableContext = toBePrinted.next(); - - Set stages = printableContext.getStageNumber(); - - switch (printableContext.getPrintable()) { - case DESIGN_REPORT: - DesignReport dp = new DesignReport(doc, idoc); - dp.writeToDocument(writer); - idoc.newPage(); - break; - case FIN_TEMPLATE: - final FinSetVisitorStrategy finWriter = new FinSetVisitorStrategy(idoc, - writer, - stages); - finWriter.writeToDocument(doc.getRocket()); - break; - case PARTS_DETAIL: - final PartsDetailVisitorStrategy detailVisitor = new PartsDetailVisitorStrategy(idoc, - writer, - stages); - detailVisitor.writeToDocument(doc.getRocket()); - detailVisitor.close(); - idoc.newPage(); - break; - } - } - //Stupid iText throws a really nasty exception if there is no data when close is called. - if (writer.getCurrentDocumentSize() <= 140) { - writer.setPageEmpty(false); - } - writer.close(); - idoc.close(); - } - catch (DocumentException e) { - } - catch (ExceptionConverter ec) { - } - finally { - if (outputFile != null) { - try { - outputFile.close(); - } - catch (IOException e) { - } - } - } - } - - /** - * Convert a media size name to a rectangle that defines the bounds of the corresponding paper size. - * - * @param msn the MediaSizeName to convert - * @return the corresponding Rectangle - */ - private Rectangle convertWithDefault(final MediaSizeName msn) { - Rectangle result = PaperSize.convert(msn); - if (result == null) { - result = PaperSize.convert(PrintUtilities.getDefaultMedia().getMediaSizeName()); - } - return result; - } + + /** + * Print the selected components to a PDF document. + * + * @param doc the OR document + * @param toBePrinted the user chosen items to print + * @param outputFile the file being written to + * @param msn the paper size + */ + public void print(OpenRocketDocument doc, Iterator toBePrinted, OutputStream outputFile, + PrintSettings settings) { + + Document idoc = new Document(getSize(settings)); + PdfWriter writer = null; + try { + writer = PdfWriter.getInstance(idoc, outputFile); + writer.setStrictImageSequence(true); + + writer.addViewerPreference(PdfName.PRINTSCALING, PdfName.NONE); + writer.addViewerPreference(PdfName.PICKTRAYBYPDFSIZE, PdfBoolean.PDFTRUE); + try { + idoc.open(); + Thread.sleep(1000); + } catch (InterruptedException e) { + } + while (toBePrinted.hasNext()) { + PrintableContext printableContext = toBePrinted.next(); + + Set stages = printableContext.getStageNumber(); + + switch (printableContext.getPrintable()) { + case DESIGN_REPORT: + DesignReport dp = new DesignReport(doc, idoc); + dp.writeToDocument(writer); + idoc.newPage(); + break; + case FIN_TEMPLATE: + final FinSetVisitorStrategy finWriter = new FinSetVisitorStrategy(idoc, + writer, + stages); + finWriter.writeToDocument(doc.getRocket()); + break; + case PARTS_DETAIL: + final PartsDetailVisitorStrategy detailVisitor = new PartsDetailVisitorStrategy(idoc, + writer, + stages); + detailVisitor.writeToDocument(doc.getRocket()); + detailVisitor.close(); + idoc.newPage(); + break; + } + } + //Stupid iText throws a really nasty exception if there is no data when close is called. + if (writer.getCurrentDocumentSize() <= 140) { + writer.setPageEmpty(false); + } + writer.close(); + idoc.close(); + } catch (DocumentException e) { + } catch (ExceptionConverter ec) { + } finally { + if (outputFile != null) { + try { + outputFile.close(); + } catch (IOException e) { + } + } + } + } + + /** + * Get the correct paper size from the print settings. + * + * @param settings the print settings + * @return the paper size + */ + private Rectangle getSize(PrintSettings settings) { + PaperSize size = settings.getPaperSize(); + PaperOrientation orientation = settings.getPaperOrientation(); + return orientation.orient(size.getSize()); + } + } diff --git a/src/net/sf/openrocket/gui/print/PrintServiceDialog.java b/src/net/sf/openrocket/gui/print/PrintServiceDialog.java deleted file mode 100644 index 4aedabac..00000000 --- a/src/net/sf/openrocket/gui/print/PrintServiceDialog.java +++ /dev/null @@ -1,609 +0,0 @@ -/* - * PrintServiceDialog.java - * - */ -package net.sf.openrocket.gui.print; - -import net.miginfocom.swing.MigLayout; - -import javax.print.DocFlavor; -import javax.print.PrintService; -import javax.print.ServiceUIFactory; -import javax.print.attribute.HashPrintRequestAttributeSet; -import javax.print.attribute.PrintRequestAttribute; -import javax.print.attribute.PrintRequestAttributeSet; -import javax.print.attribute.standard.Destination; -import javax.print.attribute.standard.Media; -import javax.print.attribute.standard.MediaSizeName; -import javax.print.attribute.standard.MediaTray; -import javax.swing.AbstractAction; -import javax.swing.ActionMap; -import javax.swing.BorderFactory; -import javax.swing.InputMap; -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JTabbedPane; -import javax.swing.KeyStroke; -import javax.swing.border.EmptyBorder; -import javax.swing.event.PopupMenuEvent; -import javax.swing.event.PopupMenuListener; -import java.awt.Container; -import java.awt.Dialog; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Set; -import java.util.TreeSet; - -public class PrintServiceDialog extends JDialog implements ActionListener { - - public static final int APPROVE = 1; - private JButton btnCancel, btnPrint; - private boolean pdfFlavorSupported = true; - private PrintService services[]; - private int defaultServiceIndex = -1; - private int status; - private PrintRequestAttributeSet asOriginal; - private HashPrintRequestAttributeSet asCurrent; - private PrintService psCurrent; - private DocFlavor docFlavor; - private GeneralPanel pnlGeneral; - private static final String GENERAL_TAB_TITLE = "General"; - private static final String PRINT_BUTTON_LABEL = "Print"; - private static final String CANCEL_BUTTON_LABEL = "Cancel"; - - private class MediaPanel extends JPanel - implements ItemListener { - - private static final String strTitle = "Media"; - private static final String SOURCE = "Source:"; - private static final String SIZE = "Size:"; - - private JLabel lblSize, lblSource; - private JComboBox cbSize, cbSource; - private ArrayList sizes; - private ArrayList sources; - - private String getMediaName(String s) { - String s1 = s.replace(' ', '-'); - s1 = s1.replace('#', 'n'); - return PaperSize.toDisplayable(s1); - } - - public void itemStateChanged(ItemEvent itemevent) { - Object obj = itemevent.getSource(); - if (itemevent.getStateChange() == ItemEvent.SELECTED) { - if (obj == cbSize) { - int i = cbSize.getSelectedIndex(); - if (i >= 0 && i < sizes.size()) { - if (cbSource.getItemCount() > 1 && cbSource.getSelectedIndex() >= 1) { - int k = cbSource.getSelectedIndex() - 1; - MediaTray mediatray = (MediaTray) sources.get(k); - asCurrent.add(new MediaWrapper(mediatray)); - } - asCurrent.add(sizes.get(i)); - } - } - else if (obj == cbSource) { - int j = cbSource.getSelectedIndex(); - if (j >= 1 && j < sources.size() + 1) { - asCurrent.remove(MediaWrapper.class); - asCurrent.add((MediaTray) sources.get(j - 1)); - } - else if (j == 0) { - asCurrent.remove(MediaWrapper.class); - if (cbSize.getItemCount() > 0) { - int l = cbSize.getSelectedIndex(); - asCurrent.add(sizes.get(l)); - } - } - } - } - } - - - public void updateInfo() { - boolean flag = false; - cbSize.removeItemListener(this); - cbSize.removeAllItems(); - cbSource.removeItemListener(this); - cbSource.removeAllItems(); - cbSource.addItem(getMediaName("auto-select")); - sizes.clear(); - sources.clear(); - if (psCurrent != null && psCurrent.isAttributeCategorySupported(Media.class)) { - flag = true; - Object obj = null; - try { - obj = psCurrent.getSupportedAttributeValues(Media.class, docFlavor, asCurrent); - } - catch (IllegalArgumentException iae) { - pdfFlavorSupported = false; - //dgp - } - if (obj instanceof Media[]) { - Media amedia[] = (Media[]) obj; - Set sizeSet = new TreeSet(); - - for (int i = 0; i < amedia.length; i++) { - Media media = amedia[i]; - if (media instanceof MediaSizeName) { - sizeSet.add(new SortableMediaSizeName((MediaSizeName) media)); - } - else if (media instanceof MediaTray) { - sources.add(media); - cbSource.addItem(getMediaName(media.toString())); - } - } - - //The set eliminates duplicates. - for (Iterator mediaSizeNameIterator = sizeSet.iterator(); mediaSizeNameIterator - .hasNext();) { - SortableMediaSizeName media = mediaSizeNameIterator.next(); - - sizes.add(media.getMediaSizeName()); - cbSize.addItem(media.toString()); - } - - } - } - boolean flag1 = flag && sizes.size() > 0; - lblSize.setEnabled(flag1); - cbSize.setEnabled(flag1); - cbSource.setEnabled(false); - lblSource.setEnabled(false); - if (flag && psCurrent != null) { - Media media = (Media) asCurrent.get(Media.class); - boolean attributeValueSupported = false; - try { - attributeValueSupported = media == null ? false : psCurrent.isAttributeValueSupported(media, - docFlavor, - asCurrent); - } - catch (IllegalArgumentException iae) { - pdfFlavorSupported = false; - } - if (media == null || !attributeValueSupported) { - media = (Media) psCurrent.getDefaultAttributeValue(Media.class); - if (media == null && sizes.size() > 0) { - media = sizes.get(0); - } - if (media != null) { - asCurrent.add(media); - } - } - if (media != null) { - if (media instanceof MediaSizeName) { - MediaSizeName mediasizename = (MediaSizeName) media; - cbSize.setSelectedIndex(sizes.indexOf(mediasizename)); - } - else if (media instanceof MediaTray) { - MediaTray mediatray = (MediaTray) media; - cbSource.setSelectedIndex(sources.indexOf(mediatray) + 1); - } - } - else { - cbSize.setSelectedIndex(sizes.size() <= 0 ? -1 : 0); - cbSource.setSelectedIndex(0); - } - int j = cbSize.getSelectedIndex(); - if (j >= 0 && j < sizes.size()) { - asCurrent.add(sizes.get(j)); - } - j = cbSource.getSelectedIndex(); - if (j >= 1 && j < sources.size() + 1) { - asCurrent.add((MediaTray) sources.get(j - 1)); - } - } - cbSize.addItemListener(this); - cbSource.addItemListener(this); - } - - public MediaPanel() { - super(new MigLayout("fill, gap rel unrel")); - sizes = new ArrayList(); - sources = new ArrayList(); - setBorder(BorderFactory.createTitledBorder(strTitle)); - cbSize = new JComboBox(); - cbSource = new JComboBox(); - lblSize = new JLabel(SIZE, 11); - lblSize.setDisplayedMnemonic(PrintServiceDialog.getMnemonic(SIZE)); - lblSize.setLabelFor(cbSize); - add(lblSize); - add(cbSize, "wrap"); - lblSource = new JLabel(SOURCE, 11); - lblSource.setDisplayedMnemonic(PrintServiceDialog.getMnemonic(SOURCE)); - lblSource.setLabelFor(cbSource); - add(lblSource); - add(cbSource); - } - - class SortableMediaSizeName implements Comparable { - MediaSizeName delegate; - - String displayableName; - - SortableMediaSizeName(MediaSizeName msn) { - delegate = msn; - displayableName = getMediaName(delegate.toString()); - if (displayableName == null) { - displayableName = delegate.toString(); - } - } - - /** - * Returns a string value corresponding to this enumeration value. - */ - @Override - public String toString() { - return displayableName; - } - - @Override - public int compareTo(final Object o) { - String name = displayableName; - if (name != null) { - return name.compareTo(o.toString()); - } - return 1; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - final SortableMediaSizeName that = (SortableMediaSizeName) o; - - return displayableName.equals(that.displayableName); - } - - @Override - public int hashCode() { - return displayableName.hashCode(); - } - - MediaSizeName getMediaSizeName() { - return delegate; - } - } - } - - private class PrintServicePanel extends JPanel - implements ActionListener, ItemListener, PopupMenuListener { - - private final String strTitle = "Print Service"; - private JButton btnProperties; - private JComboBox cbName; - private ServiceUIFactory uiFactory; - private boolean changedService; - - public PrintServicePanel() { - super(new MigLayout("fill, gap rel unrel")); - changedService = false; - if (psCurrent != null) { - uiFactory = psCurrent.getServiceUIFactory(); - } - setBorder(BorderFactory.createTitledBorder(strTitle)); - String as[] = new String[services.length]; - for (int i = 0; i < as.length; i++) { - as[i] = services[i].getName(); - } - - cbName = new JComboBox(as); - if (defaultServiceIndex != -1 && defaultServiceIndex < services.length) { - cbName.setSelectedIndex(defaultServiceIndex); - } - cbName.addItemListener(this); - cbName.addPopupMenuListener(this); - JLabel jlabel = new JLabel(("Name:"), 11); - jlabel.setDisplayedMnemonic(PrintServiceDialog.getMnemonic("Name")); - jlabel.setLabelFor(cbName); - add(jlabel); - add(cbName); - btnProperties = PrintServiceDialog.createButton("Properties...", this); - add(btnProperties, "wrap"); - } - - public void actionPerformed(ActionEvent actionevent) { - Object obj = actionevent.getSource(); - if (obj == btnProperties && uiFactory != null) { - JDialog jdialog = (JDialog) uiFactory.getUI(ServiceUIFactory.MAIN_UIROLE, "javax.swing.JDialog"); - if (jdialog != null) { - jdialog.show(); - } - else { - btnProperties.setEnabled(false); - } - } - } - - /** - * {@inheritDoc} - * - * @param itemevent the event that indicates what changed - */ - @Override - public void itemStateChanged(ItemEvent itemevent) { - if (itemevent.getStateChange() == ItemEvent.SELECTED) { - int i = cbName.getSelectedIndex(); - if (services != null && i >= 0 && i < services.length && !services[i].equals(psCurrent)) { - psCurrent = services[i]; - uiFactory = psCurrent.getServiceUIFactory(); - changedService = true; - if (asOriginal != null) { - Destination destination = (Destination) asOriginal.get( - Destination.class); - if ((destination != null) && psCurrent.isAttributeCategorySupported( - Destination.class)) { - asCurrent.add(destination); - } - else { - asCurrent.remove(Destination.class); - } - } - } - } - } - - /** - * {@inheritDoc} - * - * @param popupmenuevent - */ - @Override - public void popupMenuWillBecomeVisible(PopupMenuEvent popupmenuevent) { - changedService = false; - } - - /** - * {@inheritDoc} - * - * @param popupmenuevent - */ - @Override - public void popupMenuWillBecomeInvisible(PopupMenuEvent popupmenuevent) { - if (changedService) { - changedService = false; - updatePanels(); - } - } - - /** - * {@inheritDoc} - * - * @param popupmenuevent - */ - @Override - public void popupMenuCanceled(PopupMenuEvent popupmenuevent) { - } - - /** - * Modify the enablement of the properties button. - */ - public void updateInfo() { - btnProperties.setEnabled(uiFactory != null); - } - - } - - /** - * The panel for general print services info. - */ - private class GeneralPanel extends JPanel { - - private PrintServicePanel pnlPrintService; - private MediaPanel pnlMedia; - - public GeneralPanel() { - super(new MigLayout("fill, gap rel unrel")); - pnlPrintService = new PrintServicePanel(); - add(pnlPrintService, "wrap"); - pnlMedia = new MediaPanel(); - add(pnlMedia, "wrap"); - } - - public void updateInfo() { - pnlPrintService.updateInfo(); - pnlMedia.updateInfo(); - } - } - - /** - * Constructor. - * - * @param x the x-coordinate of the new location's - * top-left corner in the parent's coordinate space - * @param y the y-coordinate of the new location's - * top-left corner in the parent's coordinate space - * @param aPrintService the array of installed print services - * @param defaultServiceIndex the default service index (index into aPrintService) - * @param docflavor the document flavor (i.e. PDF) - * @param attributeSet the set of required attributes - * @param dialog the parent - * @param additional other panels to add in tabs - */ - public PrintServiceDialog(int x, int y, PrintService[] aPrintService, - int defaultServiceIndex, DocFlavor docflavor, PrintRequestAttributeSet attributeSet, - Dialog dialog, JPanel... additional) { - super(dialog, PRINT_BUTTON_LABEL, true); - setLayout(new MigLayout("fill, gap rel unrel")); - services = aPrintService; - this.defaultServiceIndex = defaultServiceIndex; - asOriginal = attributeSet; - asCurrent = new HashPrintRequestAttributeSet(attributeSet); - - if (services != null && defaultServiceIndex < services.length && defaultServiceIndex >= 0) { - psCurrent = services[defaultServiceIndex]; - } - docFlavor = docflavor; - Container container = getContentPane(); - container.setLayout(new MigLayout("fill, gap rel unrel")); -// container.setLayout(new BorderLayout()); - final JTabbedPane tpTabs = new JTabbedPane(); - tpTabs.setBorder(new EmptyBorder(5, 5, 5, 5)); - - if (additional != null) { - for (JPanel anAdditional : additional) { - tpTabs.add(anAdditional, anAdditional.getName(), 0); - } - } - if (psCurrent != null) { - pnlGeneral = new GeneralPanel(); - tpTabs.add(GENERAL_TAB_TITLE, pnlGeneral); - } - - container.add(tpTabs, "growx"); - updatePanels(); - - JPanel jpanel = new JPanel(new MigLayout()); - btnPrint = createExitButton(PRINT_BUTTON_LABEL, this); - jpanel.add(btnPrint, "x 300"); - getRootPane().setDefaultButton(btnPrint); - btnPrint.setEnabled(pdfFlavorSupported && psCurrent != null); - - btnCancel = createExitButton(CANCEL_BUTTON_LABEL, this); - handleEscKey(btnCancel); - jpanel.add(btnCancel, "x 380"); - container.add(jpanel, "South"); - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent windowevent) { - dispose(2); - } - } - ); - setResizable(false); - setLocation(x, y); - pack(); - } - - private void handleEscKey(JButton jbutton) { - AbstractAction abstractaction = new AbstractAction() { - - public void actionPerformed(ActionEvent actionevent) { - dispose(2); - } - - }; - KeyStroke keystroke = KeyStroke.getKeyStroke('\033', false); - InputMap inputmap = jbutton.getInputMap(2); - ActionMap actionmap = jbutton.getActionMap(); - if (inputmap != null && actionmap != null) { - inputmap.put(keystroke, "cancel"); - actionmap.put("cancel", abstractaction); - } - } - - public int getStatus() { - return status; - } - - public PrintRequestAttributeSet getAttributes() { - if (status == 1) { - return asCurrent; - } - else { - return asOriginal; - } - } - - public PrintService getPrintService() { - if (status == 1) { - return psCurrent; - } - else { - return null; - } - } - - public void dispose(int i) { - status = i; - super.dispose(); - } - - public void actionPerformed(ActionEvent actionevent) { - Object obj = actionevent.getSource(); - boolean flag = false; - if (obj == btnPrint) { - flag = true; - if (pnlGeneral != null) { - asCurrent.remove(Destination.class); - } - } - dispose(flag ? 1 : 2); - } - - - private void updatePanels() { - if (pnlGeneral != null) { - pnlGeneral.updateInfo(); - } - } - - private static char getMnemonic(String s) { - if (s != null && s.length() > 0) { - return s.charAt(0); - } - else { - return '\0'; - } - } - - private static JButton createButton(String s, ActionListener actionlistener) { - JButton jbutton = new JButton(s); - jbutton.setMnemonic(getMnemonic(s)); - jbutton.addActionListener(actionlistener); - return jbutton; - } - - private static JButton createExitButton(String s, ActionListener actionlistener) { - JButton jbutton = new JButton(s); - jbutton.addActionListener(actionlistener); - jbutton.getAccessibleContext().setAccessibleDescription(s); - return jbutton; - } - - static class MediaWrapper - implements PrintRequestAttribute { - - private Media media; - - MediaWrapper(Media theMedia) { - media = theMedia; - } - - Media getMedia() { - return media; - } - - public final Class getCategory() { - return this.getClass(); - } - - public final String getName() { - return "mw"; - } - - public String toString() { - return media.toString(); - } - - public int hashCode() { - return media.hashCode(); - } - - } - -} diff --git a/src/net/sf/openrocket/gui/print/PrintSettings.java b/src/net/sf/openrocket/gui/print/PrintSettings.java new file mode 100644 index 00000000..6537f400 --- /dev/null +++ b/src/net/sf/openrocket/gui/print/PrintSettings.java @@ -0,0 +1,89 @@ +package net.sf.openrocket.gui.print; + +import java.awt.Color; + +import net.sf.openrocket.util.AbstractChangeSource; + +/** + * A class containing all printing settings. + */ +public class PrintSettings extends AbstractChangeSource { + + private Color templateFillColor = Color.LIGHT_GRAY; + private Color templateBorderColor = Color.DARK_GRAY; + + private PaperSize paperSize = PaperSize.getDefault(); + private PaperOrientation paperOrientation = PaperOrientation.PORTRAIT; + + + public Color getTemplateFillColor() { + return templateFillColor; + } + + public void setTemplateFillColor(Color templateFillColor) { + // Implicitly tests against setting null + if (templateFillColor.equals(this.templateFillColor)) { + return; + } + this.templateFillColor = templateFillColor; + fireChangeEvent(); + } + + public Color getTemplateBorderColor() { + return templateBorderColor; + } + + public void setTemplateBorderColor(Color templateBorderColor) { + // Implicitly tests against setting null + if (templateBorderColor.equals(this.templateBorderColor)) { + return; + } + this.templateBorderColor = templateBorderColor; + fireChangeEvent(); + } + + public PaperSize getPaperSize() { + return paperSize; + } + + public void setPaperSize(PaperSize paperSize) { + if (paperSize.equals(this.paperSize)) { + return; + } + this.paperSize = paperSize; + fireChangeEvent(); + } + + public PaperOrientation getPaperOrientation() { + return paperOrientation; + } + + public void setPaperOrientation(PaperOrientation orientation) { + if (orientation.equals(paperOrientation)) { + return; + } + this.paperOrientation = orientation; + fireChangeEvent(); + } + + + + /** + * Load settings from the specified print settings. + * @param settings the settings to load + */ + public void loadFrom(PrintSettings settings) { + this.templateFillColor = settings.templateFillColor; + this.templateBorderColor = settings.templateBorderColor; + this.paperSize = settings.paperSize; + this.paperOrientation = settings.paperOrientation; + fireChangeEvent(); + } + + + @Override + public String toString() { + return "PrintSettings [templateFillColor=" + templateFillColor + ", templateBorderColor=" + templateBorderColor + ", paperSize=" + paperSize + ", paperOrientation=" + paperOrientation + "]"; + } + +} diff --git a/src/net/sf/openrocket/gui/print/PrintUtilities.java b/src/net/sf/openrocket/gui/print/PrintUtilities.java index a7efd907..7f096efc 100644 --- a/src/net/sf/openrocket/gui/print/PrintUtilities.java +++ b/src/net/sf/openrocket/gui/print/PrintUtilities.java @@ -4,151 +4,101 @@ package net.sf.openrocket.gui.print; -import com.itextpdf.text.*; -import com.itextpdf.text.Font; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.print.PageFormat; +import java.awt.print.Printable; + +import javax.swing.RepaintManager; + import net.sf.openrocket.logging.LogHelper; import net.sf.openrocket.startup.Application; -import javax.print.DocFlavor; -import javax.print.PrintService; -import javax.print.PrintServiceLookup; -import javax.print.ServiceUI; -import javax.print.attribute.HashPrintRequestAttributeSet; -import javax.print.attribute.PrintRequestAttributeSet; -import javax.print.attribute.standard.MediaSize; -import javax.swing.*; -import java.awt.*; -import java.awt.print.PageFormat; -import java.awt.print.Printable; -import java.awt.print.PrinterException; -import java.awt.print.PrinterJob; -import java.util.Locale; +import com.itextpdf.text.Chunk; +import com.itextpdf.text.Document; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.Font; +import com.itextpdf.text.Paragraph; /** * Utilities methods and fonts used for printing. */ public class PrintUtilities implements Printable { - - /** - * The logger. - */ - private static final LogHelper log = Application.getLogger(); - - public static final int NORMAL_FONT_SIZE = Font.DEFAULTSIZE - 3; - public static final int SMALL_FONT_SIZE = NORMAL_FONT_SIZE - 3; - - public static final Font BOLD = new Font(Font.FontFamily.HELVETICA, NORMAL_FONT_SIZE, Font.BOLD); - public static final Font BIG_BOLD = new Font(Font.FontFamily.HELVETICA, NORMAL_FONT_SIZE + 3, Font.BOLD); - public static final Font BOLD_UNDERLINED = new Font(Font.FontFamily.HELVETICA, NORMAL_FONT_SIZE, - Font.BOLD | Font.UNDERLINE); - public static final Font NORMAL = new Font(Font.FontFamily.HELVETICA, NORMAL_FONT_SIZE); - public static final Font SMALL = new Font(Font.FontFamily.HELVETICA, SMALL_FONT_SIZE); - - - private Component componentToBePrinted; - - public static void printComponent (Component c) { - new PrintUtilities(c).print(); - } - - public PrintUtilities (Component componentToBePrinted) { - this.componentToBePrinted = componentToBePrinted; - } - - public void print () { - PrinterJob printJob = PrinterJob.getPrinterJob(); - printJob.setPrintable(this); - if (printJob.printDialog()) { - try { - printJob.print(); - } - catch (PrinterException pe) { - System.out.println("Error printing: " + pe); - } - } - } - - public int print (Graphics g, PageFormat pageFormat, int pageIndex) { - if (pageIndex > 0) { - return (NO_SUCH_PAGE); - } - else { - Graphics2D g2d = (Graphics2D) g; - translateToJavaOrigin(g2d, pageFormat); - disableDoubleBuffering(componentToBePrinted); - componentToBePrinted.paint(g2d); - enableDoubleBuffering(componentToBePrinted); - return (PAGE_EXISTS); - } - } - - public static void disableDoubleBuffering (Component c) { - RepaintManager currentManager = RepaintManager.currentManager(c); - currentManager.setDoubleBufferingEnabled(false); - } - - public static void enableDoubleBuffering (Component c) { - RepaintManager currentManager = RepaintManager.currentManager(c); - currentManager.setDoubleBufferingEnabled(true); - } - - public static PrintService askUserForPDFPrintService () { - return askUserForPrintService(DocFlavor.INPUT_STREAM.PDF); - } - - public static PrintService askUserForPrintService (DocFlavor flavor) { - PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null); - PrintService svc = PrintServiceLookup.lookupDefaultPrintService(); - PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet(); - attrs.add(getDefaultMedia().getMediaSizeName()); - - return ServiceUI.printDialog(null, 100, 100, services, svc, flavor, attrs); - } - - /** - * Sets the paper size for pages using these attributes to the default size for the default locale. The default size - * for locales in the United States and Canada is MediaType.NA_LETTER. The default size for all other locales is - * MediaType.ISO_A4. - */ - public static MediaSize getDefaultMedia () { - String defaultCountry = Locale.getDefault().getCountry(); - if (defaultCountry != null && - (defaultCountry.equals(Locale.US.getCountry()) || - defaultCountry.equals(Locale.CANADA.getCountry()))) { - return MediaSize.NA.LETTER; - } - else { - return MediaSize.ISO.A4; - } - } - - /** - * Translate the page format coordinates onto the graphics object using Java's origin (top left). - * - * @param g2d the graphics object - * @param pageFormat the print page format - */ - public static void translateToJavaOrigin (Graphics2D g2d, PageFormat pageFormat) { - g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); - } - - /** - * Add text as a new paragraph in a given font to the document. - * - * @param document the document - * @param font the font - * @param title the title - */ - public static void addText (Document document, com.itextpdf.text.Font font, String title) { - Chunk sectionHeader = new Chunk(title); - sectionHeader.setFont(font); - try { - Paragraph p = new Paragraph(); - p.add(sectionHeader); - document.add(p); - } - catch (DocumentException e) { - log.error("Could not add paragraph.", e); - } - } + + /** + * The logger. + */ + private static final LogHelper log = Application.getLogger(); + + public static final int NORMAL_FONT_SIZE = Font.DEFAULTSIZE - 3; + public static final int SMALL_FONT_SIZE = NORMAL_FONT_SIZE - 3; + + public static final Font BOLD = new Font(Font.FontFamily.HELVETICA, NORMAL_FONT_SIZE, Font.BOLD); + public static final Font BIG_BOLD = new Font(Font.FontFamily.HELVETICA, NORMAL_FONT_SIZE + 3, Font.BOLD); + public static final Font BOLD_UNDERLINED = new Font(Font.FontFamily.HELVETICA, NORMAL_FONT_SIZE, + Font.BOLD | Font.UNDERLINE); + public static final Font NORMAL = new Font(Font.FontFamily.HELVETICA, NORMAL_FONT_SIZE); + public static final Font SMALL = new Font(Font.FontFamily.HELVETICA, SMALL_FONT_SIZE); + + + private Component componentToBePrinted; + + public PrintUtilities(Component componentToBePrinted) { + this.componentToBePrinted = componentToBePrinted; + } + + @Override + public int print(Graphics g, PageFormat pageFormat, int pageIndex) { + if (pageIndex > 0) { + return (NO_SUCH_PAGE); + } else { + Graphics2D g2d = (Graphics2D) g; + translateToJavaOrigin(g2d, pageFormat); + disableDoubleBuffering(componentToBePrinted); + componentToBePrinted.paint(g2d); + enableDoubleBuffering(componentToBePrinted); + return (PAGE_EXISTS); + } + } + + public static void disableDoubleBuffering(Component c) { + RepaintManager currentManager = RepaintManager.currentManager(c); + currentManager.setDoubleBufferingEnabled(false); + } + + public static void enableDoubleBuffering(Component c) { + RepaintManager currentManager = RepaintManager.currentManager(c); + currentManager.setDoubleBufferingEnabled(true); + } + + + /** + * Translate the page format coordinates onto the graphics object using Java's origin (top left). + * + * @param g2d the graphics object + * @param pageFormat the print page format + */ + public static void translateToJavaOrigin(Graphics2D g2d, PageFormat pageFormat) { + g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); + } + + /** + * Add text as a new paragraph in a given font to the document. + * + * @param document the document + * @param font the font + * @param title the title + */ + public static void addText(Document document, com.itextpdf.text.Font font, String title) { + Chunk sectionHeader = new Chunk(title); + sectionHeader.setFont(font); + try { + Paragraph p = new Paragraph(); + p.add(sectionHeader); + document.add(p); + } catch (DocumentException e) { + log.error("Could not add paragraph.", e); + } + } } diff --git a/src/net/sf/openrocket/gui/print/TemplateProperties.java b/src/net/sf/openrocket/gui/print/TemplateProperties.java index f98f7ea3..6f88e576 100644 --- a/src/net/sf/openrocket/gui/print/TemplateProperties.java +++ b/src/net/sf/openrocket/gui/print/TemplateProperties.java @@ -3,47 +3,74 @@ */ package net.sf.openrocket.gui.print; -import javax.swing.UIManager; import java.awt.Color; +import javax.swing.UIManager; + /** * This class is responsible for managing various properties of print templates (fin, nose cone, transitions, etc.). + * + * TODO: HIGH: Remove this entire class, and instead pass the PrintSettings object to the print methods. */ public class TemplateProperties { - - /** - * The property that defines the fill color. - */ - public static final String TEMPLATE_FILL_COLOR_PROPERTY = "template.fill.color"; - - /** - * The property that defines the line color. - */ - public static final String TEMPLATE_LINE_COLOR_PROPERTY = "template.line.color"; - - /** - * Get the current fill color. - * - * @return a color to be used as the fill in template shapes - */ - public static Color getFillColor () { - Color fillColor = UIManager.getColor(TemplateProperties.TEMPLATE_FILL_COLOR_PROPERTY); - if (fillColor == null) { - fillColor = Color.lightGray; - } - return fillColor; - } - - /** - * Get the current line color. - * - * @return a color to be used as the line in template shapes - */ - public static Color getLineColor () { - Color lineColor = UIManager.getColor(TemplateProperties.TEMPLATE_LINE_COLOR_PROPERTY); - if (lineColor == null) { - lineColor = Color.darkGray; - } - return lineColor; - } + + /** + * The property that defines the fill color. + */ + public static final String TEMPLATE_FILL_COLOR_PROPERTY = "template.fill.color"; + + /** + * The property that defines the line color. + */ + public static final String TEMPLATE_LINE_COLOR_PROPERTY = "template.line.color"; + + /** + * Get the current fill color. + * + * @return a color to be used as the fill in template shapes + */ + public static Color getFillColor() { + Color fillColor = UIManager.getColor(TemplateProperties.TEMPLATE_FILL_COLOR_PROPERTY); + if (fillColor == null) { + fillColor = Color.lightGray; + } + return fillColor; + } + + + /** + * Set the template fill color. + */ + public static void setFillColor(Color c) { + UIManager.put(TemplateProperties.TEMPLATE_FILL_COLOR_PROPERTY, c); + } + + + /** + * Get the current line color. + * + * @return a color to be used as the line in template shapes + */ + public static Color getLineColor() { + Color lineColor = UIManager.getColor(TemplateProperties.TEMPLATE_LINE_COLOR_PROPERTY); + if (lineColor == null) { + lineColor = Color.darkGray; + } + return lineColor; + } + + /** + * Set the template line color. + */ + public static void setLineColor(Color c) { + UIManager.put(TemplateProperties.TEMPLATE_LINE_COLOR_PROPERTY, c); + } + + /** + * Set the template colors from the print settings. + */ + public static void setColors(PrintSettings settings) { + setFillColor(settings.getTemplateFillColor()); + setLineColor(settings.getTemplateBorderColor()); + } } diff --git a/src/net/sf/openrocket/util/AbstractChangeSource.java b/src/net/sf/openrocket/util/AbstractChangeSource.java new file mode 100644 index 00000000..14109da0 --- /dev/null +++ b/src/net/sf/openrocket/util/AbstractChangeSource.java @@ -0,0 +1,47 @@ +package net.sf.openrocket.util; + +import java.util.List; + +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import net.sf.openrocket.logging.LogHelper; +import net.sf.openrocket.startup.Application; + +/** + * Abstract implementation of a ChangeSource. + * + * @author Sampo Niskanen + */ +public abstract class AbstractChangeSource implements ChangeSource { + private static final LogHelper log = Application.getLogger(); + + private final List listeners = new ArrayList(); + + private final ChangeEvent event = new ChangeEvent(this); + + + @Override + public final void addChangeListener(ChangeListener listener) { + listeners.add(listener); + log.verbose(1, "Adding change listeners, listener count is now " + listeners.size()); + } + + @Override + public final void removeChangeListener(ChangeListener listener) { + listeners.remove(listener); + log.verbose(1, "Removing change listeners, listener count is now " + listeners.size()); + } + + + /** + * Fire a change event to all listeners. + */ + protected void fireChangeEvent() { + ChangeListener[] array = listeners.toArray(new ChangeListener[0]); + + for (ChangeListener l : array) { + l.stateChanged(event); + } + } +} diff --git a/src/net/sf/openrocket/util/Prefs.java b/src/net/sf/openrocket/util/Prefs.java index ac3144e2..9cd9e7ab 100644 --- a/src/net/sf/openrocket/util/Prefs.java +++ b/src/net/sf/openrocket/util/Prefs.java @@ -22,6 +22,7 @@ import net.sf.openrocket.arch.SystemInfo; import net.sf.openrocket.database.Databases; import net.sf.openrocket.document.Simulation; import net.sf.openrocket.gui.main.ExceptionHandler; +import net.sf.openrocket.gui.print.PrintSettings; import net.sf.openrocket.logging.LogHelper; import net.sf.openrocket.material.Material; import net.sf.openrocket.rocketcomponent.BodyComponent; @@ -306,6 +307,47 @@ public class Prefs { storeVersion(); } + + /** + * Retrieve an enum value from the user preferences. + * + * @param the enum type + * @param key the key + * @param def the default value, cannot be null + * @return the value in the preferences, or the default value + */ + public static > T getEnum(String key, T def) { + if (def == null) { + throw new BugException("Default value cannot be null"); + } + + String value = getString(key, null); + if (value == null) { + return def; + } + + try { + return Enum.valueOf(def.getDeclaringClass(), value); + } catch (IllegalArgumentException e) { + return def; + } + } + + /** + * Store an enum value to the user preferences. + * + * @param key the key + * @param value the value to store, or null to remove the value + */ + public static void putEnum(String key, Enum value) { + if (value == null) { + putString(key, null); + } else { + putString(key, value.name()); + } + } + + /** * Return a boolean preference. * @@ -443,6 +485,26 @@ public class Prefs { if (color == null) return Color.BLACK; + Color clr = parseColor(color); + if (clr != null) { + return clr; + } else { + return Color.BLACK; + } + } + + public static void setDefaultColor(Class c, Color color) { + if (color == null) + return; + set("componentColors", c, stringifyColor(color)); + } + + + private static Color parseColor(String color) { + if (color == null) { + return null; + } + String[] rgb = color.split(","); if (rgb.length == 3) { try { @@ -453,17 +515,17 @@ public class Prefs { } catch (NumberFormatException ignore) { } } - - return Color.BLACK; + return null; } - public static void setDefaultColor(Class c, Color color) { - if (color == null) - return; + + private static String stringifyColor(Color color) { String string = color.getRed() + "," + color.getGreen() + "," + color.getBlue(); - set("componentColors", c, string); + return string; } + + public static Color getMotorBorderColor() { // TODO: MEDIUM: Motor color (settable?) return new Color(0, 0, 0, 200); @@ -623,6 +685,35 @@ public class Prefs { } + //// Printing + + public static PrintSettings getPrintSettings() { + PrintSettings settings = new PrintSettings(); + Color c; + + c = parseColor(getString("print.template.fillColor", null)); + if (c != null) { + settings.setTemplateFillColor(c); + } + + c = parseColor(getString("print.template.borderColor", null)); + if (c != null) { + settings.setTemplateBorderColor(c); + } + + settings.setPaperSize(getEnum("print.paper.size", settings.getPaperSize())); + settings.setPaperOrientation(getEnum("print.paper.orientation", settings.getPaperOrientation())); + + return settings; + } + + public static void setPrintSettings(PrintSettings settings) { + putString("print.template.fillColor", stringifyColor(settings.getTemplateFillColor())); + putString("print.template.borderColor", stringifyColor(settings.getTemplateBorderColor())); + putEnum("print.paper.size", settings.getPaperSize()); + putEnum("print.paper.orientation", settings.getPaperOrientation()); + } + //// Background flight data computation public static boolean computeFlightInBackground() { diff --git a/test/net/sf/openrocket/gui/print/TestPaperSize.java b/test/net/sf/openrocket/gui/print/TestPaperSize.java new file mode 100644 index 00000000..82677cdc --- /dev/null +++ b/test/net/sf/openrocket/gui/print/TestPaperSize.java @@ -0,0 +1,36 @@ +package net.sf.openrocket.gui.print; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class TestPaperSize { + + @Test + public void testGetDefaultForCountry() { + assertEquals(PaperSize.LETTER, PaperSize.getDefaultForCountry("US")); + assertEquals(PaperSize.LETTER, PaperSize.getDefaultForCountry("cA")); + assertEquals(PaperSize.LETTER, PaperSize.getDefaultForCountry("mx")); + + assertEquals(PaperSize.A4, PaperSize.getDefaultForCountry("FI")); + assertEquals(PaperSize.A4, PaperSize.getDefaultForCountry("xy")); + + assertNull(PaperSize.getDefaultForCountry("FIN")); + assertNull(PaperSize.getDefaultForCountry("a")); + assertNull(PaperSize.getDefaultForCountry("A4")); + assertNull(PaperSize.getDefaultForCountry(null)); + } + + @Test + public void testGetSizeFromString() { + assertEquals(PaperSize.LETTER, PaperSize.getSizeFromString("Letter")); + assertEquals(PaperSize.LEGAL, PaperSize.getSizeFromString(" legal\t")); + assertEquals(PaperSize.A4, PaperSize.getSizeFromString(" A4\n")); + assertEquals(PaperSize.A3, PaperSize.getSizeFromString("A3")); + + assertNull(PaperSize.getSizeFromString("#A4")); + assertNull(PaperSize.getSizeFromString("")); + assertNull(PaperSize.getSizeFromString(null)); + } + +} -- 2.47.2