/**
* Copyright (C) 2001-2017 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License along with this program.
* If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.gui.tools;
import java.awt.Component;
import java.awt.Container;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.swing.JMenuItem;
import com.rapidminer.gui.Perspective;
import com.rapidminer.gui.RapidMinerGUI;
import com.rapidminer.gui.actions.export.PrintableComponent;
import com.rapidminer.gui.actions.export.PrintableComponentContainer;
import com.rapidminer.gui.actions.export.ShowPrintAndExportDialogAction;
import com.rapidminer.gui.actions.export.SimplePrintableComponent;
import com.rapidminer.gui.tools.dialogs.ConfirmDialog;
import com.rapidminer.tools.I18N;
import com.vlsolutions.swing.docking.Dockable;
import com.vlsolutions.swing.docking.DockableState;
/**
* This class has static references to a printer job and page format. It also serves as a factory
* for printer menus.
*
* @author Simon Fischer
*
*/
public class PrintingTools {
private static final PrinterJob PRINTER_JOB = PrinterJob.getPrinterJob();
private static PageFormat pageFormat = getPrinterJob().defaultPage();
private static PrintRequestAttributeSet printSettings = new HashPrintRequestAttributeSet();
public static PrinterJob getPrinterJob() {
return PRINTER_JOB;
}
public static PageFormat getPageFormat() {
return pageFormat;
}
public static void editPrintSettings() {
getPrinterJob().pageDialog(printSettings);
}
public static PrintRequestAttributeSet getPrintSettings() {
return printSettings;
}
/**
* @return <code>true</code> on success. <code>false</code> if user aborts printing.
*/
public static boolean print(Printable printable) throws PrinterException {
getPrinterJob().setPrintable(printable);
if (getPrinterJob().printDialog()) {
PrintingTools.getPrinterJob().print(printSettings);
return true;
} else {
return false;
}
}
/**
* @return <code>true</code> on success. <code>false</code> if user aborts printing.
*/
public static boolean print(Printable printable, PrintRequestAttributeSet printSettings) throws PrinterException {
getPrinterJob().setPrintable(printable);
if (getPrinterJob().printDialog(printSettings)) {
PrintingTools.getPrinterJob().print(printSettings);
return true;
} else {
return false;
}
}
/**
* Creates a export menu item for the provided component.
*
* @param component
* the component the menu should be created for
* @param componentName
* the name of the component
*/
public static JMenuItem makeExportPrintMenu(Component component, String componentName) {
JMenuItem menuItem = new JMenuItem(
new ShowPrintAndExportDialogAction(new SimplePrintableComponent(component, componentName), true));
return menuItem;
}
/**
* Prompt a file chooser dialog where the user selects a file location and returns a
* {@link File} at this location.
*
* @param i18nKey
* the i18n key for the dialog to be shown. The provided i18nKey must be contained in
* the GUI properties file (gui.dialog.i18nKey.[title|message|icon]).
* @param fileExtension
* the explicit file extension like "pdf" or "png".
* @param extensionDescription
* the description of the given format for this file extension
* @return the new File in the an object can be stored
* @throws IOException
*/
static public File promptForFileLocation(String i18nKey, String fileExtension, String extensionDescription)
throws IOException {
// check parameters
if ("".equals(fileExtension) || "".equals(extensionDescription)) {
throw new IllegalArgumentException("Empty file extension or exntension description are not allowed!");
}
if (fileExtension.startsWith(".")) {
fileExtension = fileExtension.substring(1);
}
return promptForFileLocation(i18nKey, new String[] { fileExtension }, new String[] { extensionDescription });
}
/**
* Prompt a file chooser dialog where the user selects a file location and returns a
* {@link File} at this location.
*
* @param i18nKey
* the i18n key for the dialog to be shown. The provided i18nKey must be contained in
* the GUI properties file (gui.dialog.i18nKey.[title|message|icon]).
* @param fileExtensions
* a list of explicit file extension like "pdf" or "png".
* @param extensionDescriptions
* a list of descriptions of the given format for this file extension
* @return the new File in the an object can be stored
* @throws IOException
*/
static public File promptForFileLocation(String i18nKey, String[] fileExtensions, String[] extensionDescriptions)
throws IOException {
// check parameters
for (int i = 0; i < fileExtensions.length; ++i) {
if ("".equals(fileExtensions[i]) || "".equals(extensionDescriptions[i])) {
throw new IllegalArgumentException("Empty file extension or exntension description are not allowed!");
}
if (fileExtensions[i].startsWith(".")) {
fileExtensions[i] = fileExtensions[i].substring(1);
}
}
// prompt user for file location
File file = SwingTools.chooseFile(RapidMinerGUI.getMainFrame(), i18nKey, null, false, false, fileExtensions,
extensionDescriptions, false);
if (file == null) {
return null;
}
// do not overwrite directories
if (file.isDirectory()) {
throw new IOException(I18N.getMessage(I18N.getErrorBundle(), "error.io.file_is_directory", file.getPath()));
}
// prompt for overwrite confirmation
if (file.exists()) {
int returnVal = SwingTools.showConfirmDialog("export_image", ConfirmDialog.YES_NO_OPTION, file.getName());
if (returnVal == ConfirmDialog.NO_OPTION) {
return null;
}
}
return file;
}
/**
* Returns a list of printable components below the root component. If the root component is a
* {@link PrintableComponent} itself, it will be first in the list. The first component in list
* is always showing. Other might not be visible on screen.
*
* @return the components that can be exported as an image.
*/
public static final List<PrintableComponent> findExportComponents(Component root) {
List<PrintableComponent> components = new LinkedList<>();
findExportComponents(root, components);
return components;
}
/**
* Returns a list of printable components from the currently visible perspective.
*
* @return the components that can be exported as an image.
*/
public static final List<PrintableComponent> findExportComponents() {
List<PrintableComponent> components = new LinkedList<>();
// otherwise search for all PrintableComponents in current perspective
for (DockableState state : RapidMinerGUI.getMainFrame().getDockingDesktop().getDockables()) {
if (state.isHidden()) {
continue;
}
Dockable dockable = state.getDockable();
// if dockable is visible, search for PrintableComponents
Component component = dockable.getComponent();
if (component.isShowing()) {
findExportComponents(component, components);
}
}
// at last add MainFrame as printable component
Perspective currentPerspective = RapidMinerGUI.getMainFrame().getPerspectiveController().getModel()
.getSelectedPerspective();
String perspectiveName = I18N.getGUIMessage("gui.action.workspace_" + currentPerspective.getName() + ".label");
components.add(new SimplePrintableComponent(RapidMinerGUI.getMainFrame(), perspectiveName,
I18N.getGUIMessage("gui.action.workspace_" + currentPerspective.getName() + ".icon")));
return components;
}
/**
* Recursive method: Traverses down the component hierarchy until a instance of
* {@link PrintableComponent} is found. After adding this instance to the list of result
* components the method returns. If component is not a {@link PrintableComponent} but a
* {@link Container} this method is invoked on all child components.
*/
private static final void findExportComponents(Component component, List<PrintableComponent> resultComponents) {
// if printable component found, add export component to list and return
if (component instanceof PrintableComponent) {
PrintableComponent printableComp = (PrintableComponent) component;
if (printableComp.getExportComponent() != null) {
resultComponents.add(printableComp);
}
// do not search any further in tree if printable component was found
return;
}
// if pageable component found, add printable components to list and return
if (component instanceof PrintableComponentContainer) {
PrintableComponentContainer pageable = (PrintableComponentContainer) component;
List<PrintableComponent> printableComponents = pageable.getPrintableComponents();
for (PrintableComponent printable : printableComponents) {
if (printable.getExportComponent() != null) {
resultComponents.add(printable);
}
}
// do not search any further in tree if pageable component was found
return;
}
// if container found, dig deeper
if (component instanceof Container) {
Container container = (Container) component;
for (Component comp : container.getComponents()) {
findExportComponents(comp, resultComponents);
}
}
}
}