/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.core.gui.widgets;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.net.URI;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.TreeSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.ScrollPaneConstants;
import javax.swing.filechooser.FileFilter;
import javax.swing.plaf.metal.MetalTabbedPaneUI;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
import javax.swing.text.html.HTMLEditorKit;

import lu.tudor.santec.gecamed.address.ejb.session.beans.AddressManagerBean;
import lu.tudor.santec.gecamed.address.ejb.session.interfaces.AddressManagerInterface;
import lu.tudor.santec.gecamed.core.ejb.session.beans.ListManagerBean;
import lu.tudor.santec.gecamed.core.ejb.session.interfaces.ListManagerInterface;
import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.utils.ImagePanel;
import lu.tudor.santec.gecamed.core.gui.utils.LogFileViewer;
import lu.tudor.santec.gecamed.core.gui.utils.xslfo.TransFOmer;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.core.utils.controller.utils.FileUtils;
import lu.tudor.santec.gecamed.core.utils.printing.ireport.UtilFormatter;
import lu.tudor.santec.gecamed.formeditor.gui.FormEditorModule;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Office;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedInfo;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.beans.LoginBean;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;


/**
 * shows a Dialog with Tabs for 
 *      Program version and infos
 *      used Libraries
 *      License
 *      SystemProperties
 * 
 * @author Johannes Hermen johannes.hermen(at)tudor.lu
 *
 * @Version
 * <br>$Log: AboutDialog.java,v $
 * <br>Revision 1.34  2013-12-27 18:07:50  donak
 * <br>Cleanup of imports
 * <br>
 * <br>Revision 1.33  2013-07-15 06:18:34  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.32  2013-04-11 14:42:46  troth
 * <br>Remove and Rename package for the xsl-fo transfer from lu.tudor.santec.gecamed.formeditor.gui.controller.fo to lu.tuodr.santec.gecamed.core.utils.xslfo .
 * <br>
 * <br>Revision 1.31  2013-01-14 11:01:29  ferring
 * <br>keep compatibility with java 1.5
 * <br>
 * <br>Revision 1.30  2012-05-23 08:31:57  ferring
 * <br>Escape chars corrected to UTF-8
 * <br>
 * <br>Revision 1.29  2012-05-11 05:53:00  ferring
 * <br>XSL printing fixed
 * <br>
 * <br>Revision 1.28  2012-05-10 13:36:36  ferring
 * <br>XSL print handling changed
 * <br>
 * <br>Revision 1.27  2012-04-10 08:12:50  ferring
 * <br>GECAMed about dialog updated:
 * <br>- information updated
 * <br>- separate tab for database information
 * <br>- option to open, save and mail the about information and the log files and
 * <br>
 * <br>Revision 1.26  2009-06-03 09:22:53  hermen
 * <br>show core.info table in about dialog
 * <br>
 * <br>Revision 1.25  2009-05-15 07:34:04  hermen
 * <br>show core.info in about dialog
 * <br>
 * <br>Revision 1.24  2008-12-15 12:40:12  hermen
 * <br>changed version to 1.0.8
 * <br>
 * <br>Revision 1.23  2008-09-25 09:43:06  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.22  2008-03-25 08:43:19  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.21  2008-03-25 07:13:15  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.20  2008-03-10 13:55:08  hermen
 * <br>updated about screen
 * <br>
 * <br>Revision 1.19  2008-03-10 13:49:29  hermen
 * <br>updated splash and about screen
 * <br>
 * <br>Revision 1.18  2008-02-26 12:46:47  hermen
 * <br>fixed reopen bug
 * <br>
 * <br>Revision 1.17  2008-01-15 09:29:38  hermen
 * <br>updated Javadoc and refactured code
 * <br>
 * <br>Revision 1.16  2007-12-04 15:28:00  hermen
 * <br>*** empty log message ***
 * <br>
 *
 */
public class AboutDialog extends JDialog implements ActionListener
{
	//~ Static fields/initializers =============================================
	
	private static final long		serialVersionUID	= 1L;
	
	// TODO: E-Mail-Adresse �ndern & �bersetzungen machen
	private static final String 	MAIL_ADDRESS 		= "guido.bosch@list.lu";
	private static final String 	MAIL_SUBJECT 		= "GECAMed%20Info%20of%20medical%20office%3A%20";
	private static final String 	MAIL_BODY 			= "This%20Email%20contains%20the%20GECAMed%20Infos%20of%20the%20medical%20office%20";
	
	/**
	 * file for infos about the used libraries.
	 * This file is generated by the ant script from the info.txt files in the lib dir.
	 */
	public static final String		LIBINFO_FILE		= "resources/LIBINFO.html";
	
	public static final ImageIcon	SPLASH_IMAGE		= GECAMedModule.getIcon(GECAMedIconNames.HELPSCREEN);
	public static final Color		SPLASH_TEXTCOLOR	= new Color(0, 67, 134);
	public static final Color		SPLASH_TRANSPARENCY	= new Color(255, 255, 255, 100);
	
	private static final String 	ZIP_EXTENSION 		= ".zip";
	private static final String 	PDF_EXTENSION 		= ".pdf";
	private static final String 	LOG_EXTENSION 		= ".log";
	
	
	//~ Instance fields ========================================================

	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(AboutDialog.class.getName());
	
	private JButton					closeButton;
	
	private JButton					saveInfoButton;
	
	private ImagePanel				backPanel;
	
	private Properties				serverProperties;
	
	private List<GecamedInfo>		coreInfos;
	
	private SaveAboutInfoDialog 	saveDialog;
	
	private JFileChooser 			fileChooser;
	
	private InfoFileFilter 			fileFilter = new InfoFileFilter();;
	
	
	
	//~ Constructors ===========================================================
	/**
	 * creates a new AboutDialog
	 *
	 * @param mainFrame a reference to the mainFrame of the Program to obtain all child-objects from
	 * @throws HeadlessException
	 */
	public AboutDialog(MainFrame mainFrame) throws HeadlessException
	{
		super(mainFrame, "About " + System.getProperty("APP_NAME") + " " + System.getProperty("APP_VERSION"));
		this.setModal(true);
		
		try
		{
			serverProperties = ((ListManagerInterface) ManagerFactory.getRemote(ListManagerBean.class)).getServerInfos();
			coreInfos = ((ListManagerInterface) ManagerFactory.getRemote(ListManagerBean.class)).getCoreInfos();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
		Object[][] infos;
		
		// Build dialog components 
		JTabbedPane tabbedPane = new JTabbedPane();
		tabbedPane.setForeground(SPLASH_TEXTCOLOR);
		tabbedPane.setUI(new TabbedPaneUITransparent());
		tabbedPane.setBackground(SPLASH_TRANSPARENCY);
		tabbedPane.setOpaque(false);
		// add the tabs
		tabbedPane.addTab("Program", this.getInfoPanel());
		tabbedPane.addTab("Credits", this.getCreditsPanel());
		tabbedPane.addTab("Libraries", this.getLibraryPanel());
		infos = getProperties(System.getProperties());
		tabbedPane.addTab("System", this.getSystemPropertyPanel(infos));
		infos = getProperties(serverProperties);
		tabbedPane.addTab("Server-Info", this.getSystemPropertyPanel(infos));
		infos = getDatabaseProperties();
		tabbedPane.addTab("Database-Info", this.getSystemPropertyPanel(infos));
		tabbedPane.addTab("License", this.getLicensePanel());
		
		// Layout dialog components
		FormLayout layout = new FormLayout("246dlu, 2dlu, 120dlu", "35dlu, 2dlu, 45dlu, 8dlu, fill:202:grow, 2dlu, pref");
		this.backPanel = new ImagePanel(SPLASH_IMAGE);
		this.backPanel.setLayout(layout);
		this.backPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		this.add(this.backPanel);
		
		CellConstraints cc = new CellConstraints();
		this.backPanel.add(getDescriptionLabel(), 	cc.xy(3, 3));
		this.backPanel.add(tabbedPane, 				cc.xyw(1, 5, 3));
		
		saveInfoButton = new JButton("Save info");
		saveInfoButton.addActionListener(this);
		saveInfoButton.setForeground(SPLASH_TEXTCOLOR);
		
		closeButton = new JButton("close");
		closeButton.addActionListener(this);
		closeButton.setForeground(SPLASH_TEXTCOLOR);
		
		JPanel buttonPanel = new JPanel(new FormLayout("f:p:g, 0px:, f:p, 5px, f:p", "f:p"));
		buttonPanel.add(getDBLabel(), 		cc.xy(1, 1));
		buttonPanel.add(saveInfoButton, 	cc.xy(3, 1));
		buttonPanel.add(closeButton, 		cc.xy(5, 1));
		buttonPanel.setOpaque(false);
		this.backPanel.add(buttonPanel, 	cc.xyw(1, 7, 3));
		
		this.setSize(800, 471);
//		this.pack();
//		this.setResizable(false);
		this.setLocationRelativeTo(mainFrame);
		this.setVisible(true);
		
	}


	//~ Methods ================================================================
	
	/* (non-Javadoc)
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent e)
	{
		if (e.getSource().equals(this.closeButton))
		{
			this.dispose();
		}
		else if (e.getSource() == this.saveInfoButton)
		{
			if (saveDialog == null)
				saveDialog = new SaveAboutInfoDialog();
			
			// show the dialog to select what to do
			saveDialog.setVisible(true);
			
			if (saveDialog.getButtonOption() == GECAMedBaseDialog.OK_OPTION)
				saveGECAMedInfos();
		}
	}


	/**
	 * creates a JLabel with general information about the client/server version
	 * and database connection
	 * @return
	 */
	protected JLabel getDescriptionLabel()
	{
		
		String gitRev = System.getProperty("APP_GIT_REV");
		if (gitRev != null && gitRev.length()>7) gitRev = gitRev.substring(0,  7);
		final String description = "<html>" + "<p>Release: " + System.getProperty("APP_VERSION") + " (" + System.getProperty("APP_RELEASENAME") + ")</p>" + "<p>Git Revision: " + gitRev + "</p>" + "<p>Client date: " + System.getProperty("APP_BUILD_DATE") + "</p>" + "<p>Server date: " + serverProperties.getProperty("SERVER_BUILD_DATE") + "</p>" ;
		//        		"<p>Database: " +  database + "</p>";
		JLabel desc = new JLabel(description);
		desc.setForeground(Color.WHITE);
		return desc;
	}
	
	
	/**
	 * creates a JLabel with general information about the client/server version
	 * and database connection
	 * @return
	 */
	protected JLabel getDBLabel()
	{
		String database = "";
		try
		{
			database = ((LoginInterface) ManagerFactory.getRemote(LoginBean.class)).getDatabaseInfo();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
		String databaseServer = "";
		try
		{
			databaseServer = ((LoginInterface) ManagerFactory.getRemote(LoginBean.class)).getDatabaseServerVersion();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
		final String description = "<html>" + "<p>Database: " + database + " on Postgresql "+databaseServer + " </p>";
		JLabel desc = new JLabel(description);
		desc.setForeground(SPLASH_TEXTCOLOR);
		desc.setFont(new Font("Arial", Font.PLAIN, 9));
		return desc;
	}
	
	
	/**
	 * creates a JLabel with the applications Icon
	 * @return
	 */
	protected JLabel getIconLabel()
	{
		return new JLabel(GECAMedModule.getIcon(GECAMedIconNames.LOGO));
	}
	
	
	/**
	 * creates a JPanel with the text from the resources/About_Program.html file
	 * @return
	 */
	protected JPanel getInfoPanel()
	{
		final JPanel panel = new JPanel(new BorderLayout());
		panel.setOpaque(false);
		String text = "";
		try
		{
			text = this.readFile(GECAMedModule.class.getResourceAsStream("resources/About_Program.html"));
		}
		catch (Exception e)
		{
		}
		final JEditorPane editor = new JEditorPane();
		editor.setOpaque(false);
		editor.setEditable(false);
		editor.setEditorKit(new HTMLEditorKit());
		try
		{
			editor.setText(text.replaceFirst(":release", GECAMedModule.class.getResource("resources/release.png").toString()));
		}
		catch (Exception e)
		{
			editor.setText(text.replaceFirst(":release", GECAMedModule.class.getResource("resources/icons/logo.png").toString()));
		}
		editor.setCaretPosition(0);
		final JScrollPane scrollPane = new JScrollPane(editor);
		scrollPane.setOpaque(false);
		scrollPane.getViewport().setOpaque(false);
		scrollPane.setBorder(BorderFactory.createEmptyBorder());
		scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
		panel.add(scrollPane, BorderLayout.CENTER);
		panel.setName("Program");
		return panel;
	}
	
	
	/**
	 * creates a JPanel with the text from the resources/LIBINFO.html file
	 * @return
	 */
	protected JPanel getLibraryPanel()
	{
		final String head = "<html><h2>This libraries have been used to build this program:</h2></html>";
		final String text = "<html>" + this.readFile(MainFrame.class.getResourceAsStream(LIBINFO_FILE));
		final JPanel panel = new JPanel(new BorderLayout());
		final JLabel headLabel = new JLabel(head);
		final JEditorPane editor = new JEditorPane();
		editor.setOpaque(false);
		editor.setEditable(false);
		editor.setEditorKit(new HTMLEditorKit());
		editor.setText(text);
		editor.setCaretPosition(0);
		final JScrollPane scrollPane = new JScrollPane(editor);
		scrollPane.setOpaque(false);
		scrollPane.getViewport().setOpaque(false);
		scrollPane.setBorder(BorderFactory.createEmptyBorder());
		scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
		panel.add(headLabel, BorderLayout.NORTH);
		panel.add(scrollPane, BorderLayout.CENTER);
		panel.setName("Libraries");
		panel.setOpaque(false);
		return panel;
	}
	
	
	/**
	 * creates a JPanel that shows all Java System Properties in a JTable
	 * @return
	 */
	protected JComponent getSystemPropertyPanel(Object[][] properties)
	{
		final TableModel model = new SystemPropertiesTableModel(properties);
		final JTable table = new JTable(model)
		{
			private static final long	serialVersionUID	= 1L;
			
			
			public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
			{
				Component c = super.prepareRenderer(renderer, row, column);
				if (c instanceof JComponent)
					((JComponent) c).setOpaque(false);
				return c;
			}
		};
		final JScrollPane scrollPane = new JScrollPane(table);
		table.setOpaque(false);
		scrollPane.setOpaque(false);
		scrollPane.getViewport().setOpaque(false);
		table.getColumnModel().getColumn(0).setHeaderValue("Property");
		table.getColumnModel().getColumn(1).setHeaderValue("Value");
		scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
		return scrollPane;
	}
	
	
	/**
	 * creates a JPanel with the text from the resources/License.html file
	 * @return
	 */
	protected JPanel getLicensePanel()
	{
		final JPanel panel = new JPanel(new BorderLayout());
		String text = "";
		try
		{
			text = this.readFile(GECAMedModule.class.getResourceAsStream("resources/License.html"));
		}
		catch (Exception e)
		{
		}
		final JEditorPane editor = new JEditorPane();
		editor.setEditable(false);
		//		editor.setEditorKit(new HTMLEditorKit());
		editor.setText(text);
		editor.setCaretPosition(0);
		editor.setOpaque(false);
		final JScrollPane scrollPane = new JScrollPane(editor);
		scrollPane.setOpaque(false);
		scrollPane.getViewport().setOpaque(false);
		scrollPane.setBorder(BorderFactory.createEmptyBorder());
		scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
		panel.add(scrollPane, BorderLayout.CENTER);
		panel.setName("License");
		panel.setOpaque(false);
		return panel;
	}
	
	
	/**
	 * creates a JPanel with the text from the resources/Credits.html file
	 * @return
	 */
	protected JPanel getCreditsPanel()
	{
		final JPanel panel = new JPanel(new BorderLayout());
		String text = "";
		try
		{
			text = this.readFile(GECAMedModule.class.getResourceAsStream("resources/Credits.html"));
		}
		catch (Exception e)
		{
		}
		final JEditorPane editor = new JEditorPane();
		editor.setEditable(false);
		editor.setEditorKit(new HTMLEditorKit());
		editor.setText(text);
		editor.setCaretPosition(0);
		editor.setOpaque(false);
		final JScrollPane scrollPane = new JScrollPane(editor);
		scrollPane.setOpaque(false);
		scrollPane.getViewport().setOpaque(false);
		scrollPane.setBorder(BorderFactory.createEmptyBorder());
		scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
		panel.add(scrollPane, BorderLayout.CENTER);
		panel.setOpaque(false);
		panel.setName("Credits");
		return panel;
	}
	
	
	
	/* **************************************** */
	// 		INFO EXPORT MANAGEMENT
	/* **************************************** */
	
	/**
	 * Calls the dialog and starts the procedure to 
	 * create, save & mail GECAMed information
	 */
	private void saveGECAMedInfos ()
	{
		List<File> 			infoFiles;
		List<String> 		infoFileNames;
		File 				resultFile;
		File 				file;
		String 				fileName;
		
		
		/* ---------------------------------------- */
		// 		create the files as selected
		/* ---------------------------------------- */
		
		infoFiles 		= new ArrayList<File>(3);
		infoFileNames 	= new ArrayList<String>(3);
		
		if (saveDialog.attachInfoPdf())
		{
			// create and add the info PDF
			file = createInfoPDF();
			if (file != null)
			{
				infoFiles.add(file);
				infoFileNames.add("info_document.pdf");
			}
		}
		
		if (saveDialog.attachClientLog())
		{
			// add the client log file
			file = copyClientLog();
			if (file != null)
			{
				infoFiles.add(file);
				infoFileNames.add("gecamed_client.log");
			}
		}
		
		if (saveDialog.attachServerLog())
		{
			// create and add the server log file
			file = copyServerLog();
			if (file != null)
			{
				infoFiles.add(file);
				infoFileNames.add("gecamed_server.log");
			}
		}
		
		/* -------------------------------------------------- */
		// 	set (or zip) the file(s) and set the file filter
		/* -------------------------------------------------- */
		
		if (infoFiles.size() == 1)
		{
			resultFile 	= infoFiles.get(0);
			fileName 	= infoFileNames.get(0);
			if (fileName.endsWith(PDF_EXTENSION))
				fileFilter.setFileExtension(PDF_EXTENSION);
			else if (fileName.endsWith(LOG_EXTENSION))
				fileFilter.setFileExtension(LOG_EXTENSION);
			else
				fileFilter.setFileExtension("");
		}
		else
		{
			// create a ZIP-file with containing all info files
			resultFile = zipFiles(infoFiles, infoFileNames);
			fileFilter.setFileExtension(ZIP_EXTENSION);
		}
		
		/* ---------------------------------------- */
		// 		handle the result file
		/* ---------------------------------------- */
		
		if (resultFile == null)
			// there seemed to be an error => cannot proceed
			return;
		
		if (saveDialog.saveFiles())
			// save the file, let the user decide where to save it.
			resultFile = saveFile(resultFile);
		
		if (saveDialog.mailFiles())
			// use the system default mail client to send the information
			sendMail(resultFile);
		
		if (saveDialog.openFiles())
			// open the PDF, if possible
			openFile(resultFile, !saveDialog.saveFiles());
	}


	private File createInfoPDF()
	{
		InputStream 	is;
		TransFOmer 		transfomer 	= TransFOmer.getInstance();
		byte[] 			fileData;
		File 			file;
		Document 		data;
		

		// 	load the XSL template
		data = createDataXML();
		
		// 	load the XSL template
		is = GECAMedModule.class.getResourceAsStream("resources/printInfo.xsl");
		
		try
		{
			// create the PDF data
			fileData = transfomer.transFO(
					transfomer.loadXMLFrom(data), 
					transfomer.loadXMLFrom(is), 
					"pdf");
			
			if (fileData == null)
				// something went wrong => exit
				return null;
			
			// save the PDF (a file chooser will open)
			file = File.createTempFile("gecamed_info", PDF_EXTENSION);
			return FileUtils.createFile(fileData, file);
		}
		catch (Exception e)
		{
			logger.log(Level.ERROR, e.getMessage(), e);
			return null;
		}
	}


	private File copyClientLog()
	{
		File 			tempFile;
		File 			clientLogfile;
		InputStream 	fis 	= null;
		OutputStream 	fos 	= null;
		byte[] 			buffer 	= new byte[0x1000];
		int 			size;
		
		
		try
		{
	 		tempFile 		= File.createTempFile("gecamed_client", LOG_EXTENSION);
	 		clientLogfile 	= LogFileViewer.getClientLogFile();
			fis 			= new FileInputStream(clientLogfile);
			fos 			= new FileOutputStream(tempFile);
			
			while ((size = fis.read(buffer)) >= 0)
				fos.write(buffer, 0, size);
			
			return tempFile;
		}
		catch (IOException e)
		{
			logger.log(Level.ERROR, e.getMessage(), e);
		}
		finally
		{
			if (fis != null) try { fis.close(); } catch (IOException e) {}
			if (fos != null) try { fos.close(); } catch (IOException e) {}
		}
		
		return null;
	}


	private File copyServerLog()
	{
		LoginInterface 		loginManager;
		String 				serverLog;
		OutputStream 		fos 	= null;
		File 				file 	= null;
		
		
		try
		{
			loginManager 	= (LoginInterface) ManagerFactory.getRemote(LoginBean.class);
			serverLog 		= loginManager.getServerLog();
			file 			= File.createTempFile("gecamed_server", LOG_EXTENSION);
			fos 			= new FileOutputStream(file);
			fos.write(serverLog.getBytes());
		}
		catch (Exception e) 
		{
			logger.log(Level.ERROR, e.getMessage(), e);
		}
		finally
		{
			if (fos != null) try { fos.close(); } catch (IOException e) {}
		}
		return file;
	}
	
	
	private Document createDataXML ()
	{
		Element 	root 		= new Element("gecamInfo");
		Element 	parentTag;
		Element 	info;
		Object 		key;
		Object 		value;
		Object[][] 	infos;
		
		
		UtilFormatter 	formatter 	= new UtilFormatter((AddressManagerInterface) ManagerFactory.getRemote(AddressManagerBean.class));
		Office 			gecamOffice = MainFrame.getCurrentOffice();
		
		
		info 		= new Element("date");
		info.setText(formatter.formatDate(new Date(), "yyyy-MM-dd"));
		root.addContent(info);
		
		// get the office infos
		parentTag 	= new Element("office");
		info = new Element("name");
		info.setText(gecamOffice.getName());
		parentTag.addContent(info);
		
		String[] formattedAddress = formatter.formatOfficeAddress(gecamOffice).split("\n");
		for (String addressLine : formattedAddress)
		{
			info 	= new Element("address");
			info.setText(addressLine);
			parentTag.addContent(info);
		}
		root.addContent(parentTag);
		
		// get the client infos
		parentTag 	= new Element("clientInfo");
		infos 		= getProperties(System.getProperties());
		for (int i = 0; i < infos.length; i++)
		{
			key 	= infos[i][0];
			value 	= infos[i][1];
			info 	= new Element("info");
			info.setAttribute("key", String.valueOf(key));
			info.setText(String.valueOf(value));
			parentTag.addContent(info);
		}
		root.addContent(parentTag);
		
		// get the server infos
		parentTag 	= new Element("serverInfo");
		infos 		= getProperties(serverProperties);
		for (int i = 0; i < infos.length; i++)
		{
			key 	= infos[i][0];
			value 	= infos[i][1];
			info 	= new Element("info");
			info.setAttribute("key", String.valueOf(key));
			info.setText(String.valueOf(value));
			parentTag.addContent(info);
		}
		root.addContent(parentTag);
		
		// get the core.info table data
		parentTag 	= new Element("databaseInfo");
		infos 		= getDatabaseProperties();
		for (int i = 0; i < infos.length; i++)
		{
			key 	= infos[i][0];
			value 	= infos[i][1];
			info 	= new Element("info");
			info.setAttribute("key", String.valueOf(key));
			info.setText(String.valueOf(value));
			parentTag.addContent(info);
		}
		root.addContent(parentTag);
		
		return new Document(root);
	}
	
	
	private File zipFiles(List<File> infoFiles, List<String> infoFileNames)
	{
		Iterator<File> 		fileIter;
		Iterator<String> 	nameIter;
		File 				resultFile;
		File 				file;
		String 				fileName;
		OutputStream 		fos 	= null;
		ZipOutputStream 	zos 	= null;
		FileInputStream 	is 		= null;
		ZipEntry 			entry;
		byte[] 				buffer;
		int 				length;
		
		
		try
		{
			resultFile 	= File.createTempFile("gecamedf_infos", ZIP_EXTENSION);
			fos 		= new FileOutputStream(resultFile);
			zos 		= new ZipOutputStream(fos);
			
			// write the PDF into the zip file
			buffer 		= new byte[0x1000];
			
			fileIter 	= infoFiles.iterator();
			nameIter 	= infoFileNames.iterator();
			while (fileIter.hasNext())
			{
				file 	= fileIter.next();
				if (nameIter.hasNext())
					 fileName = nameIter.next();
				else fileName = file.getName();
				
				try 
				{
					entry 	= new ZipEntry(fileName);
					is 		= new FileInputStream(file);
					zos.putNextEntry(entry);
					while ((length = is.read(buffer)) >= 0)
						zos.write(buffer, 0, length);
					is.close();
				}
				catch (Exception e)
				{
					logger.log(Level.ERROR, e.getMessage(), e);
				}
			}
		}
		catch (IOException e)
		{
			logger.log(Level.ERROR, e.getMessage(), e);
			resultFile = null;
		}
		finally
		{
			// close the streams
			if (zos != null) try { zos.close(); } catch (IOException e) {}
			if (is  != null) try { is.close(); }  catch (IOException e) {}
			
			// delete the template files
			for (File f : infoFiles)
			{
				f.delete();
			}
		}
		return resultFile;
	}


	private File saveFile(File resultFile)
	{
		boolean proceed;
		File 	file;
		
		// let the user save the file
		if (fileChooser == null)
		{
			fileChooser = new JFileChooser();
			fileChooser.setMultiSelectionEnabled(false);
			fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
			fileChooser.setFileFilter(fileFilter);
		}
		fileChooser.setSelectedFile(new File("gecamed_info" + fileFilter.getFileExtension()));
		
		if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION)
		{
			file 	= fileChooser.getSelectedFile();
			proceed = true;
			
			if (file.exists())
			{
				// ask to override the existing file
				proceed = GECAMedBaseDialogImpl.showMessageDialog(this, 
								Translatrix.getTranslationString("AboutDialog.OverrideFiles_title"), 
								Translatrix.getTranslationString("AboutDialog.OverrideFiles_message", 
										new String[] { file.getName() }), 
								GECAMedBaseDialog.YES_NO_BUTTON_MODE)
						== GECAMedBaseDialog.YES_OPTION;
				
				if (proceed)
					file.delete();
			}
				
			if (proceed)
			{
				if (resultFile.renameTo(file))
				{
					resultFile = file;
				}
				else 
				{
					// file was NOT successfully renamed
					GECAMedBaseDialogImpl.showMessageDialog(this, 
							Translatrix.getTranslationString("AboutDialog.CouldNotMoveFiles_title"), 
							Translatrix.getTranslationString("AboutDialog.CouldNotMoveFiles_message", 
									new String[] { resultFile.getAbsolutePath() }), 
							GECAMedBaseDialog.OK_BUTTON_MODE);
				}
			}
		}
		
		return resultFile;
	}


	private void openFile(File file, boolean deleteOnExit)
	{
		if (FormEditorModule.isJavaVersionOK()
				&& java.awt.Desktop.isDesktopSupported())
		{
			java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
			if (desktop.isSupported(java.awt.Desktop.Action.OPEN))
			{
				if (file != null && file.exists())
				{
					try
					{
						desktop.open(file);
						if (deleteOnExit)
							file.deleteOnExit();
					}
					catch (IOException e)
					{
						logger.log(Level.ERROR, e.getMessage(), e);
						GECAMedBaseDialogImpl.showMessageDialog(this, 
								Translatrix.getTranslationString("AboutDialog.CouldNotMoveFiles_title"), 
								Translatrix.getTranslationString("AboutDialog.CouldNotOpenFile_message", 
										new String[] { file.getName() }), 
								GECAMedBaseDialog.OK_BUTTON_MODE, 
								GECAMedModule.getIcon(GECAMedIconNames.ERROR));
						if (deleteOnExit)
							file.delete();
					}
				}
			}
		}
	}
	

	// desktop.mail("mailto:@gaga.de?subject=someSubject&cc=aa@bb.cc,dd@dd.ds&bcc=x@y.zz&body=someBodyText");
	private void sendMail (File attachment)
	{
		java.awt.Desktop 		desktop 	= java.awt.Desktop.getDesktop();
		String 			officeName 	= getEscapedStringForURI(MainFrame.getCurrentOffice().getName());
		StringBuilder 	mailUri;
		

		mailUri = new StringBuilder("mailto:")
				.append(MAIL_ADDRESS)
				.append("?subject=")
				.append(MAIL_SUBJECT)
				.append(officeName)
				.append("&body=")
				.append(MAIL_BODY)
				.append(officeName)
				.append("%2E&attach=")
				.append(getEscapedStringForURI(attachment.getAbsolutePath()));
		
		try
		{
			desktop.mail(new URI(mailUri.toString()));
		}
		catch (Exception e)
		{
			logger.log(Level.ERROR, e.getMessage(), e);
			GECAMedBaseDialogImpl.showMessageDialog(this, 
					Translatrix.getTranslationString("AboutDialog.CouldNotSendEmail_title"), 
					Translatrix.getTranslationString("AboutDialog.CouldNotSendEmail_message"), 
					GECAMedBaseDialog.OK_BUTTON_MODE, 
					GECAMedModule.getIcon(GECAMedIconNames.ERROR));
		}
	}


	private String getEscapedStringForURI (String s)
	{
		return s.replaceAll("%", 	"%25")
				.replaceAll(" ", 	"%20")
				.replaceAll("\\?", 	"%3F")
				.replaceAll("Ä", 	"%C4")
				.replaceAll("Ü", 	"%DC")
				.replaceAll("Ö", 	"%D6")
				.replaceAll("ä", 	"%E4")
				.replaceAll("ü", 	"%FC")
				.replaceAll("ö", 	"%F6")
				.replaceAll("ß", 	"%DF")
				.replaceAll("\n", 	"%0D")
				.replaceAll("/", 	"%2F")
				.replaceAll(";", 	"%3B")
				.replaceAll("=", 	"%3D")
				.replaceAll("\"", 	"%22")
				.replaceAll("\\(", 	"%28")
				.replaceAll("\\)", 	"%29")
				.replaceAll("'", 	"%2C")
				.replaceAll("\\.", 	"%2E")
				.replaceAll(":", 	"%3A")
				.replaceAll("\\<", 	"%3C")
				.replaceAll("\\>", 	"%3E")
				.replaceAll("@", 	"%40")
				.replaceAll("\\[", 	"%5B")
				.replaceAll("]", 	"%5D")
				.replaceAll("\\\\", "%5C")
				.replaceAll("\\^", 	"%5E")
				.replaceAll("\\{", 	"%7B")
				.replaceAll("}", 	"%7D")
				.replaceAll("\\|", 	"%7C")
				.replaceAll("&", 	"%26")
				.replaceAll("#", 	"%23");
	}
	
	
	/**
	 * returns all Properties as key-value pair
	 * @return
	 */
	private Object[][] getProperties (Properties properties)
	{
		if (properties == null)
			return new Object[0][2];
		
		TreeSet<Object> keys 	= new TreeSet<Object>(properties.keySet());
		Object[][] 		infos 	= new Object[keys.size()][];
		int 			index 	= 0;

		try
		{
			for (Object key : keys)
				infos[index++] = new Object[] { key, properties.get(key) };
		}
		catch (Exception e)
		{
			logger.log(Level.ERROR, e.getMessage(), e);
		}
		
		return infos;
	}
	
	
	/**
	 * @return the core.info table as key-value pair
	 */
	private Object[][] getDatabaseProperties()
	{
		if (coreInfos == null)
			return new Object[0][];
		
		Object[][] 	infos = new Object[coreInfos.size()][2];
		int 		index = 0;
		
		try
		{
			for (GecamedInfo info : coreInfos)
			{
				infos[index][0] = info.getKey();
				infos[index][1] = info.getValue() + " (" + info.getDate() + ")";
				index++;
			}
		}
		catch (Exception e)
		{
			logger.log(Level.ERROR, e.getMessage(), e);
		}
		
		return infos;
	}
	
	
	/**
	 * helper method to read a file into a String
	 * 
	 * @param stream
	 * @return
	 */
	private String readFile(InputStream stream)
	{
		
		StringBuffer text = new StringBuffer();
		try
		{
			Reader is = new InputStreamReader(stream);
			BufferedReader in = new BufferedReader(is);
			for (String s; (s = in.readLine()) != null;)
				text.append(s + "\n");
			in.close();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		return text.toString();
	}
	
	//~ Inner Classes ==========================================================
	
	/**
	 * Table model to display Systemproperties as key-value pair
	 * 
	 * @author Johannes Hermen johannes.hermen(at)tudor.lu
	 *
	 * @Version
	 * <br>$Log: AboutDialog.java,v $
	 * <br>Revision 1.34  2013-12-27 18:07:50  donak
	 * <br>Cleanup of imports
	 * <br>
	 * <br>Revision 1.33  2013-07-15 06:18:34  ferring
	 * <br>logging changed
	 * <br>
	 * <br>Revision 1.32  2013-04-11 14:42:46  troth
	 * <br>Remove and Rename package for the xsl-fo transfer from lu.tudor.santec.gecamed.formeditor.gui.controller.fo to lu.tuodr.santec.gecamed.core.utils.xslfo .
	 * <br>
	 * <br>Revision 1.31  2013-01-14 11:01:29  ferring
	 * <br>keep compatibility with java 1.5
	 * <br>
	 * <br>Revision 1.30  2012-05-23 08:31:57  ferring
	 * <br>Escape chars corrected to UTF-8
	 * <br>
	 * <br>Revision 1.29  2012-05-11 05:53:00  ferring
	 * <br>XSL printing fixed
	 * <br>
	 * <br>Revision 1.28  2012-05-10 13:36:36  ferring
	 * <br>XSL print handling changed
	 * <br>
	 * <br>Revision 1.27  2012-04-10 08:12:50  ferring
	 * <br>GECAMed about dialog updated:
	 * <br>- information updated
	 * <br>- separate tab for database information
	 * <br>- option to open, save and mail the about information and the log files and
	 * <br>
	 * <br>Revision 1.26  2009-06-03 09:22:53  hermen
	 * <br>show core.info table in about dialog
	 * <br>
	 * <br>Revision 1.25  2009-05-15 07:34:04  hermen
	 * <br>show core.info in about dialog
	 * <br>
	 * <br>Revision 1.24  2008-12-15 12:40:12  hermen
	 * <br>changed version to 1.0.8
	 * <br>
	 * <br>Revision 1.23  2008-09-25 09:43:06  heinemann
	 * <br>fixed copyrights
	 * <br>
	 * <br>Revision 1.22  2008-03-25 08:43:19  hermen
	 * <br>*** empty log message ***
	 * <br>
	 * <br>Revision 1.21  2008-03-25 07:13:15  hermen
	 * <br>*** empty log message ***
	 * <br>
	 * <br>Revision 1.20  2008-03-10 13:55:08  hermen
	 * <br>updated about screen
	 * <br>
	 * <br>Revision 1.19  2008-03-10 13:49:29  hermen
	 * <br>updated splash and about screen
	 * <br>
	 * <br>Revision 1.18  2008-02-26 12:46:47  hermen
	 * <br>fixed reopen bug
	 * <br>
	 * <br>Revision 1.17  2008-01-15 09:29:38  hermen
	 * <br>updated Javadoc and refactured code
	 * <br>
	 * <br>Revision 1.16  2007-12-04 15:28:00  hermen
	 * <br>*** empty log message ***
	 * <br>
	 *
	 */
	public final class SystemPropertiesTableModel extends AbstractTableModel
	{
		//~ Static fields/initializers =========================================
		
		private static final long	serialVersionUID	= 1L;
		
		//~ Instance fields ====================================================
		/** Das Array mit den Systemeigenschaften. */
		private final Object[][]	properties;
		
		
		//~ Constructors =======================================================
		
		public SystemPropertiesTableModel(final Object[][] properties)
		{
			super();
			this.properties = properties;
		}
		
		
		//~ Methods ============================================================
		
		/* (non-Javadoc)
		 * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int)
		 */
		public boolean isCellEditable(final int rowIndex, final int columnIndex)
		{
			return (0 <= rowIndex) && (rowIndex < getRowCount()) && (0 <= columnIndex) && (columnIndex < getColumnCount());
		}
		
		
		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#getColumnCount()
		 */
		public int getColumnCount()
		{
			return ((this.properties != null) && (this.properties.length > 0)) ? this.properties[0].length : 0;
		}
		
		
		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#getRowCount()
		 */
		public int getRowCount()
		{
			return (this.properties != null) ? this.properties.length : 0;
		}
		
		
		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#getValueAt(int, int)
		 */
		public Object getValueAt(final int rowIndex, final int columnIndex)
		{
			Object value = null;
			if ((0 <= rowIndex) && (rowIndex < getRowCount()) && (0 <= columnIndex) && (columnIndex < getColumnCount()))
			{
				value = this.properties[rowIndex][columnIndex];
				if (value != null)
				{
					value = value.toString().replaceAll("\\n", "\\\\n").replaceAll("\\r", "\\\\r");
				}
			}
			return value;
		}
	}
	
	public class TabbedPaneUITransparent extends MetalTabbedPaneUI
	{
		protected void paintContentBorder(Graphics g, int arg1, int arg2)
		{
			int tw = tabPane.getBounds().width;
			int th = tabPane.getBounds().height;
			g.setColor(SPLASH_TRANSPARENCY);
			g.fillRect(0, 20, tw, th);
			
			//			super.paintTabBackground(g, tabPlacement, tabIndex, x, y, w, h, isSelected)
		}
		
		
		/* (non-Javadoc)
		 * @see javax.swing.plaf.metal.MetalTabbedPaneUI#paintTabBackground(java.awt.Graphics, int, int, int, int, int, int, boolean)
		 */
		@Override
		protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected)
		{
			
//			int tw = tabPane.getBounds().width;
//			int th = tabPane.getBounds().height;
//			g.setColor(SPLASH_TRANSPARENCY);
//			g.fillRect(0, 0, tw, th);

//			super.paintTabBackground(g, tabPlacement, tabIndex, x, y, w, h, isSelected);
		}
	}
	
	
	
	/* ======================================== */
	// 		CLASS: ABOUT MAIL DIALOG
	/* ======================================== */
	
	public class SaveAboutInfoDialog extends GECAMedBaseDialogImpl implements ActionListener
	{
		/* ======================================== */
		// 		CONSTANTS
		/* ======================================== */
		
		private static final long	serialVersionUID	= 1L;
		
		
		
		/* ======================================== */
		// 		MEMBERS
		/* ======================================== */
		
		private JCheckBox attachInfoPdfBox;
		
		private JCheckBox attachClientLogBox;
		
		private JCheckBox attachServerLogBox;
		
		private JCheckBox saveFilesBox;
		
		private JCheckBox mailFilesBox;
		
		private JCheckBox openFilesBox;
		
		
		
		/* ======================================== */
		// 		CONSTRUCTOR
		/* ======================================== */
		
		public SaveAboutInfoDialog ()
		{
			super(AboutDialog.this, 
					Translatrix.getTranslationString("AboutDialog.SaveGECAMedInfos.title"), 
					OK_CANCEL_BUTTON_MODE);
			
			CellConstraints cc 			= new CellConstraints();
			JPanel 			subPanel 	= new JPanel();
			JLabel 			descriptionLabel;
			JLabel 			filesHeadlineLabel;
			JLabel 			actionHeadlineLabel;
			int 			row;
			
			descriptionLabel 	= new JLabel(
					Translatrix.getTranslationString("AboutDialog.SaveGECAMedInfos.description"));
			descriptionLabel.setOpaque(false);
			
			filesHeadlineLabel 	= new JLabel(
					Translatrix.getTranslationString("AboutDialog.SaveGECAMedInfos.labeling1"));
			filesHeadlineLabel.setOpaque(false);

			attachInfoPdfBox 	= new JCheckBox("<html><i>GECAMed info.pdf");
			attachInfoPdfBox.setOpaque(false);
			attachInfoPdfBox.addActionListener(this);
			
			attachClientLogBox 	= new JCheckBox("<html><i>GECAMed client.log");
			attachClientLogBox.setOpaque(false);
			attachClientLogBox.addActionListener(this);
			
			attachServerLogBox 	= new JCheckBox("<html><i>GECAMed server.log");
			attachServerLogBox.setOpaque(false);
			attachServerLogBox.addActionListener(this);
			
			actionHeadlineLabel = new JLabel(
					Translatrix.getTranslationString("AboutDialog.SaveGECAMedInfos.labeling2"));
			
			openFilesBox 		= new JCheckBox(
					Translatrix.getTranslationString("AboutDialog.SaveGECAMedInfos.labelingOpen"));
			openFilesBox.setOpaque(false);
			openFilesBox.addActionListener(this);
			
			saveFilesBox 		= new JCheckBox(
					Translatrix.getTranslationString("AboutDialog.SaveGECAMedInfos.labelingSave"));
			saveFilesBox.setOpaque(false);
			saveFilesBox.addActionListener(this);
			
			mailFilesBox 		= new JCheckBox(
					Translatrix.getTranslationString("AboutDialog.SaveGECAMedInfos.labelingSend"));
			mailFilesBox.setOpaque(false);
			mailFilesBox.addActionListener(this);

			
			/* ---------------------------------------- */
			// define the layout and 
			// add the components to the panels
			/* ---------------------------------------- */
			
			// define the subPanel
			subPanel.setLayout(new FormLayout("15px, f:p", 
					"0px, f:p, " + 	// files headline
					"0px, f:p, " + 	// info PDF check box
					"0px, f:p, " + 	// client log check box
					"0px, f:p, " + 	// server log check box
					"10px,f:p, " + 	// action headline
					"0px, f:p, " + 	// open check box
					"0px, f:p, " + 	// save check box
					"0px, f:p, " + 	// mail check box
					"0px"));
			subPanel.setOpaque(false);
			
			row = 0;
			subPanel.add(filesHeadlineLabel, 	cc.xyw(1, row+=2, 2));
			subPanel.add(attachInfoPdfBox, 		cc.xyw(2, row+=2, 1));
			subPanel.add(attachClientLogBox, 	cc.xyw(2, row+=2, 1));
			subPanel.add(attachServerLogBox, 	cc.xyw(2, row+=2, 1));
			subPanel.add(actionHeadlineLabel, 	cc.xyw(1, row+=2, 2));
			subPanel.add(saveFilesBox, 			cc.xyw(2, row+=2, 1));
			subPanel.add(openFilesBox, 			cc.xyw(2, row+=2, 1));
			subPanel.add(mailFilesBox, 			cc.xyw(2, row+=2, 1));
			
			// define the mainPanel
			mainPanel.setLayout(new FormLayout("5px, f:p, 5px", 
					"5px, f:p, " + 	// description text
					"10px,f:p, " + 	// subPanel
					"5px"));
			
			row = 0;
			mainPanel.add(descriptionLabel, 	cc.xy(2, row+=2));
			mainPanel.add(subPanel, 			cc.xy(2, row+=2));
		}
		
		
		
		/* ======================================== */
		// 		CLASS BODY
		/* ======================================== */
		
		@Override
		public void setVisible(boolean b)
		{
			boolean canMail = false;
			boolean canOpen = false;
			
			
			if (b)
			{
				attachInfoPdfBox.setSelected(true);
				attachServerLogBox.setSelected(true);
				attachClientLogBox.setSelected(true);
				saveFilesBox.setSelected(true);
				openFilesBox.setSelected(true);
				mailFilesBox.setSelected(false);
				
				if (FormEditorModule.isJavaVersionOK()
						&& java.awt.Desktop.isDesktopSupported())
				{
					if (java.awt.Desktop.getDesktop().isSupported(java.awt.Desktop.Action.OPEN))
						canOpen = true;
					if (java.awt.Desktop.getDesktop().isSupported(java.awt.Desktop.Action.MAIL))
						canMail = true;
				}
				
				openFilesBox.setEnabled(canOpen);
				if (canOpen)
					 openFilesBox.setToolTipText(null);
				else openFilesBox.setToolTipText(
						Translatrix.getTranslationString("AboutDialog.openNotSupported"));
				
				mailFilesBox.setEnabled(canMail);
				if (canMail)
					 mailFilesBox.setToolTipText(null);
				else mailFilesBox.setToolTipText(
						Translatrix.getTranslationString("AboutDialog.mailNotSupported"));
				
				saveFilesBox.setEnabled(canOpen || canMail);
				
				this.setLocationRelativeTo(getOwner());
				this.pack();
			}
			
			super.setVisible(b);
		}
		
		
		public boolean attachInfoPdf ()
		{
			return attachInfoPdfBox.isSelected();
		}
		
		
		public boolean attachClientLog ()
		{
			return attachClientLogBox.isSelected();
		}
		
		
		public boolean attachServerLog ()
		{
			return attachServerLogBox.isSelected();
		}
		
		
		public boolean mailFiles ()
		{
			return mailFilesBox.isSelected();
		}
		
		
		public boolean saveFiles ()
		{
			return saveFilesBox.isSelected();
		}
		
		
		public boolean openFiles ()
		{
			return openFilesBox.isSelected();
		}
		
		
		public void actionPerformed(ActionEvent e)
		{
			okButton.setEnabled(
					(	attachClientLogBox.isSelected()
					 || attachInfoPdfBox.isSelected()
					 || attachServerLogBox.isSelected()
					)&&(saveFilesBox.isSelected()
					 || mailFilesBox.isSelected()
					 || openFilesBox.isSelected()
					));
		}
	}
	
	
	
	/* ======================================== */
	// 		CLASS: INFO FILE FILTER
	/* ======================================== */
	
	public class InfoFileFilter extends FileFilter
	{
		/* ======================================== */
		// 		MEMBERS
		/* ======================================== */
		
		private String extension;
		
		
		
		/* ======================================== */
		// 		CLASS BODY
		/* ======================================== */
		
		@Override
		public boolean accept(File f)
		{
			return f.getName().toLowerCase().endsWith(extension)
					|| f.isDirectory();
		}

		@Override
		public String getDescription()
		{
			return extension;
		}
		
		
		public void setFileExtension (String fileExtension)
		{
			extension = fileExtension;
		}
		
		
		public String getFileExtension ()
		{
			return extension;
		}
	}
}
