<commit_before>package fi.csc.microarray.client.visualisation;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.SwingConstants;

import org.apache.log4j.Logger;

import fi.csc.microarray.client.ClientApplication;
import fi.csc.microarray.client.Session;
import fi.csc.microarray.client.visualisation.Visualisation.Variable;
import fi.csc.microarray.client.visualisation.VisualisationFrameManager.FrameType;
import fi.csc.microarray.databeans.DataBean;
import fi.csc.microarray.databeans.DataChangeEvent;
import fi.csc.microarray.databeans.DataChangeListener;
import fi.csc.microarray.databeans.DataItemCreatedEvent;
import fi.csc.microarray.databeans.DataItemRemovedEvent;

public abstract class VisualisationFrame implements DataChangeListener {

	public abstract void setContent(JComponent visualisationComponent);

	private static final Color BG = Color.white;

	protected ClientApplication application = Session.getSession().getApplication();

	private static final String WAIT_PANEL_NAME = "wait";
	private static final String VISUALISATION_PANEL_NAME = "visualisation";

	private CardLayout viewChangerLayout = new CardLayout();
	private JPanel viewChangerPanel = new JPanel(viewChangerLayout);
	private JSplitPane paramSplit;

	private VisualisationMethod method;

	private List<Variable> variables;

	private List<DataBean> datas;

	protected FrameType type;

	private Visualisation visualiser;

	private JPanel waitPanel;

	private Vector<Component> focusComponents;

	private static final Logger logger = Logger.getLogger(VisualisationFrame.class);

	/**
	 * Creates a new VisualisationFrame with a CardLayout-powered view changer.
	 * 
	 * @throws IOException
	 */
	public VisualisationFrame(FrameType type) {
		this.type = type;

		// initialise panels
		viewChangerPanel.setBackground(BG);

		// initialise wait panel
		waitPanel = new JPanel(new BorderLayout());
		JLabel waitLabel = new JLabel("Visualising, please wait...");
		waitLabel.setFont(waitLabel.getFont().deriveFont(Font.BOLD));
		waitLabel.setHorizontalAlignment(SwingConstants.CENTER);
		waitPanel.add(waitLabel, BorderLayout.CENTER);
		viewChangerPanel.add(waitPanel, WAIT_PANEL_NAME);

		// show empty panel
		try {
			this.showVisualisationComponent(VisualisationMethod.NONE.getVisualiser(this).getVisualisation(new ArrayList<DataBean>()));
		} catch (Exception e) {
			application.reportException(e);
		}
		this.setContent(viewChangerPanel);
		viewChangerLayout.show(viewChangerPanel, VISUALISATION_PANEL_NAME);

		application.getDataManager().addDataChangeListener(this);
	}

	private class SplitSizeHandler implements PropertyChangeListener {
		public void propertyChange(PropertyChangeEvent e) {
			int leftLimit = (int) paramSplit.getWidth() - (int) Visualisation.PARAMETER_SIZE.getWidth();
			if (paramSplit.getDividerLocation() < leftLimit) {
				paramSplit.setDividerLocation(leftLimit);
			}
		}
	}

	public JComponent createVisualisation(VisualisationMethodChangedEvent e) {
		
		JComponent componentToReturn = null;

		// Create new visualiser only if needed to keep the settings made in settings panel
		try {
			if (this.datas != e.getDatas() || this.method != e.getNewMethod()) {
				this.datas = e.getDatas();
				this.method = e.getNewMethod();

				removeVisualiser();
				visualiser = method.getVisualiser(this);
			}
			this.variables = e.getVariables();

			// parameter panel has to be first one to make it initialised before the
			// data is set (scatterplot)
			JPanel parametersPanel = visualiser.getParameterPanel();
			logger.debug("parametersPanel for method " + method + " contains: " + parametersPanel);
			if (parametersPanel != null) {
				paramSplit = new JSplitPane();
				parametersPanel.setMinimumSize(new Dimension(0, 0));
				paramSplit.setRightComponent(parametersPanel);
				// To show the width limit of parameter panel
				paramSplit.setContinuousLayout(true);
				// To keep the parameter panel size constant
				paramSplit.setResizeWeight(1.0);

				SplitSizeHandler sizeHandler = new SplitSizeHandler();
				paramSplit.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, sizeHandler);
			} else {
				//Do not keep references to old visualization to avoid memory leak
				if (paramSplit != null) {
					paramSplit.removeAll();
				}
			}

			JComponent visualisationComponent = null;


			if (visualiser.isForMultipleDatas()) {
				visualisationComponent = visualiser.getVisualisation(datas);
			} else if (visualiser.isForSingleData()) {
				DataBean data = datas.size() > 0 ? datas.get(0) : null;
				visualisationComponent = visualiser.getVisualisation(data);
			}

			if (parametersPanel != null) {
				paramSplit.setLeftComponent(visualisationComponent);
				componentToReturn = paramSplit;
			} else {
				componentToReturn = visualisationComponent;
			}
			
			if (logger.isDebugEnabled()) {
				logger.debug("visualisationpanel contains following components:");
				for (Component component : paramSplit.getComponents()) {
					logger.debug("\t" + component);
				}
			}
		} catch (Exception e1) {
			application.reportException(e1);
			componentToReturn = visualiser.getDefaultVisualisation();
		}

		return componentToReturn;
	}

	/**
	 * Is not explicitly synchronised, should be called only from EDT.
	 */
	public void showVisualisationComponent(JComponent panel) {
		// Clean
		removeVisualisationComponent();

		if (panel == null) {
			try {
				panel = VisualisationMethod.NONE.getVisualiser(this).getVisualisation(new ArrayList<DataBean>());
			} catch (Exception e) {
				application.reportException(e);
			}
		}

		String title = "Visualisation";
		if (datas != null && datas.size() > 0) {
			title += " of ";
			for (int i = 0; i < datas.size(); i++) {
				title += datas.get(i);<commit_msg>Fix NPE in VisualisationFrame when in debug logging is enabled<commit_after>package fi.csc.microarray.client.visualisation;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.SwingConstants;

import org.apache.log4j.Logger;

import fi.csc.microarray.client.ClientApplication;
import fi.csc.microarray.client.Session;
import fi.csc.microarray.client.visualisation.Visualisation.Variable;
import fi.csc.microarray.client.visualisation.VisualisationFrameManager.FrameType;
import fi.csc.microarray.databeans.DataBean;
import fi.csc.microarray.databeans.DataChangeEvent;
import fi.csc.microarray.databeans.DataChangeListener;
import fi.csc.microarray.databeans.DataItemCreatedEvent;
import fi.csc.microarray.databeans.DataItemRemovedEvent;

public abstract class VisualisationFrame implements DataChangeListener {

	public abstract void setContent(JComponent visualisationComponent);

	private static final Color BG = Color.white;

	protected ClientApplication application = Session.getSession().getApplication();

	private static final String WAIT_PANEL_NAME = "wait";
	private static final String VISUALISATION_PANEL_NAME = "visualisation";

	private CardLayout viewChangerLayout = new CardLayout();
	private JPanel viewChangerPanel = new JPanel(viewChangerLayout);
	private JSplitPane paramSplit;

	private VisualisationMethod method;

	private List<Variable> variables;

	private List<DataBean> datas;

	protected FrameType type;

	private Visualisation visualiser;

	private JPanel waitPanel;

	private Vector<Component> focusComponents;

	private static final Logger logger = Logger.getLogger(VisualisationFrame.class);

	/**
	 * Creates a new VisualisationFrame with a CardLayout-powered view changer.
	 * 
	 * @throws IOException
	 */
	public VisualisationFrame(FrameType type) {
		this.type = type;

		// initialise panels
		viewChangerPanel.setBackground(BG);

		// initialise wait panel
		waitPanel = new JPanel(new BorderLayout());
		JLabel waitLabel = new JLabel("Visualising, please wait...");
		waitLabel.setFont(waitLabel.getFont().deriveFont(Font.BOLD));
		waitLabel.setHorizontalAlignment(SwingConstants.CENTER);
		waitPanel.add(waitLabel, BorderLayout.CENTER);
		viewChangerPanel.add(waitPanel, WAIT_PANEL_NAME);

		// show empty panel
		try {
			this.showVisualisationComponent(VisualisationMethod.NONE.getVisualiser(this).getVisualisation(new ArrayList<DataBean>()));
		} catch (Exception e) {
			application.reportException(e);
		}
		this.setContent(viewChangerPanel);
		viewChangerLayout.show(viewChangerPanel, VISUALISATION_PANEL_NAME);

		application.getDataManager().addDataChangeListener(this);
	}

	private class SplitSizeHandler implements PropertyChangeListener {
		public void propertyChange(PropertyChangeEvent e) {
			int leftLimit = (int) paramSplit.getWidth() - (int) Visualisation.PARAMETER_SIZE.getWidth();
			if (paramSplit.getDividerLocation() < leftLimit) {
				paramSplit.setDividerLocation(leftLimit);
			}
		}
	}

	public JComponent createVisualisation(VisualisationMethodChangedEvent e) {
		
		JComponent componentToReturn = null;

		// Create new visualiser only if needed to keep the settings made in settings panel
		try {
			if (this.datas != e.getDatas() || this.method != e.getNewMethod()) {
				this.datas = e.getDatas();
				this.method = e.getNewMethod();

				removeVisualiser();
				visualiser = method.getVisualiser(this);
			}
			this.variables = e.getVariables();

			// parameter panel has to be first one to make it initialised before the
			// data is set (scatterplot)
			JPanel parametersPanel = visualiser.getParameterPanel();
			logger.debug("parametersPanel for method " + method + " contains: " + parametersPanel);
			if (parametersPanel != null) {
				paramSplit = new JSplitPane();
				parametersPanel.setMinimumSize(new Dimension(0, 0));
				paramSplit.setRightComponent(parametersPanel);
				// To show the width limit of parameter panel
				paramSplit.setContinuousLayout(true);
				// To keep the parameter panel size constant
				paramSplit.setResizeWeight(1.0);

				SplitSizeHandler sizeHandler = new SplitSizeHandler();
				paramSplit.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, sizeHandler);
			} else {
				//Do not keep references to old visualization to avoid memory leak
				if (paramSplit != null) {
					paramSplit.removeAll();
				}
			}

			JComponent visualisationComponent = null;


			if (visualiser.isForMultipleDatas()) {
				visualisationComponent = visualiser.getVisualisation(datas);
			} else if (visualiser.isForSingleData()) {
				DataBean data = datas.size() > 0 ? datas.get(0) : null;
				visualisationComponent = visualiser.getVisualisation(data);
			}

			if (parametersPanel != null) {
				paramSplit.setLeftComponent(visualisationComponent);
				componentToReturn = paramSplit;
			} else {
				componentToReturn = visualisationComponent;
			}
			
		} catch (Exception e1) {
			application.reportException(e1);
			componentToReturn = visualiser.getDefaultVisualisation();
		}

		return componentToReturn;
	}

	/**
	 * Is not explicitly synchronised, should be called only from EDT.
	 */
	public void showVisualisationComponent(JComponent panel) {
		// Clean
		removeVisualisationComponent();

		if (panel == null) {
			try {
				panel = VisualisationMethod.NONE.getVisualiser(this).getVisualisation(new ArrayList<DataBean>());
			} catch (Exception e) {
				application.reportException(e);
			}
		}

		String title = "Visualisation";
		if (datas != null && datas.size() > 0) {
			title += " of ";
			for (int i = 0; i < datas.size(); i++) {
				title += datas.get(i);
{'fraction_non_alphanumeric': 0.09958165860060701, 'fraction_numerical': 0.00180460995816586, 'mean_word_length': 4.783681214421252, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1091620', 'n_tokens_mistral': 3985, 'n_tokens_neox': 3470, 'n_words': 804}