package org.chesmapper.view.gui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Arrays; import javax.swing.DefaultListModel; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.chesmapper.map.main.ScreenSetup; import org.chesmapper.view.cluster.Cluster; import org.chesmapper.view.cluster.ClusterController; import org.chesmapper.view.cluster.Clustering; import org.chesmapper.view.cluster.ClusteringImpl; import org.chesmapper.view.cluster.Clustering.SelectionListener; import org.chesmapper.view.gui.swing.ComponentFactory; import org.chesmapper.view.gui.swing.TransparentViewPanel; import org.chesmapper.view.gui.swing.ComponentFactory.ClickableLabel; import org.mg.javalib.gui.DoubleNameListCellRenderer; import org.mg.javalib.gui.MouseOverList; import org.mg.javalib.gui.DoubleNameListCellRenderer.DoubleNameElement; import org.mg.javalib.util.ImageLoader; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; public class ClusterListPanel extends JPanel { JPanel clusterPanel; DefaultListModel<DoubleNameElement> listModel; DoubleNameListCellRenderer listRenderer; MouseOverList clusterList; JScrollPane scroll; boolean selfBlock = false; CompoundListPanel compoundListPanel; Clustering clustering; ClusterController clusterControler; ViewControler viewControler; GUIControler guiControler; ControlPanel controlPanel; JPanel filterPanel; JLabel filterLabel; ClickableLabel filterRemoveButton; public ClusterListPanel(Clustering clustering, ClusterController clusterControler, ViewControler viewControler, GUIControler guiControler) { this.clustering = clustering; this.clusterControler = clusterControler; this.viewControler = viewControler; this.guiControler = guiControler; buildLayout(); installListeners(); } private void installListeners() { clustering.addSelectionListener(new SelectionListener() { @Override public void clusterWatchedChanged(Cluster c) { updateCluster(c); } @Override public void clusterActiveChanged(Cluster c) { updateCluster(c); } }); viewControler.addViewListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(ViewControler.PROPERTY_COMPOUND_FILTER_CHANGED)) { updateFilter(); } } }); clusterList.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { if (selfBlock) return; selfBlock = true; if (clusterList.getSelectedValue() == AllCompounds || clusterList.getSelectedIndex() == -1) viewControler.clearMouseMoveWatchUpdates(true); else { final Cluster watchCluster = (Cluster) clusterList.getSelectedValue(); viewControler.doMouseMoveWatchUpdates(new Runnable() { public void run() { clusterControler.setClusterWatched(watchCluster); } }); } SwingUtilities.invokeLater(new Runnable() { public void run() { selfBlock = false; } }); } }); clusterList.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (selfBlock) return; guiControler.block("click cluster"); selfBlock = true; viewControler.clearMouseMoveWatchUpdates(false); Thread th = new Thread(new Runnable() { public void run() { try { //clear only if there is a single zoomed in compound boolean clearCompound = clustering.getActiveCompounds().length == 1 && View.instance.getZoomTarget() == clustering.getActiveCompound(); if (clusterList.getSelectedValue() == AllCompounds) { if (clustering.isClusterActive()) clusterControler.clearClusterActive(true, clearCompound); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { viewControler.setSingleCompoundSelection(true); } }); } else { Cluster c = (Cluster) clusterList.getSelectedValue(); if (c != clustering.getActiveCluster()) clusterControler.setClusterActive(c, true, clearCompound); else if (clearCompound) clusterControler.clearCompoundActive(true); } } finally { selfBlock = false; SwingUtilities.invokeLater(new Runnable() { public void run() { guiControler.unblock("click cluster"); } }); } } }); th.start(); } }); clustering.addListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(ClusteringImpl.CLUSTER_ADDED) || evt.getPropertyName().equals(ClusteringImpl.CLUSTER_REMOVED) || evt.getPropertyName().equals(ClusteringImpl.CLUSTER_CLEAR)) { selfBlock = true; updateList(); updateFilter(); selfBlock = false; } } }); viewControler.addViewListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(ViewControler.PROPERTY_COMPOUND_DESCRIPTOR_CHANGED) || evt.getPropertyName().equals(ViewControler.PROPERTY_HIGHLIGHT_CHANGED) || evt.getPropertyName().equals(ViewControler.PROPERTY_FEATURE_SORTING_CHANGED) || evt.getPropertyName().equals(ViewControler.PROPERTY_COMPOUND_FILTER_CHANGED)) { selfBlock = true; updateList(); selfBlock = false; } else if (evt.getPropertyName().equals(ViewControler.PROPERTY_FONT_SIZE_CHANGED) || evt.getPropertyName().equals(ViewControler.PROPERTY_COMPOUND_FILTER_CHANGED)) updateListSize(); } }); guiControler.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(GUIControler.PROPERTY_VIEWER_SIZE_CHANGED)) updateListSize(); } }); } public DoubleNameElement AllCompounds = new DoubleNameElement() { @Override public String getFirstName() { return "All Compounds"; } @Override public String getSecondName() { if (viewControler.getHighlightedProperty() != null) return clustering.getFormattedValue(viewControler.getHighlightedProperty()); else return null; } }; private void updateList() { if (!SwingUtilities.isEventDispatchThread()) throw new IllegalStateException("GUI updates only in event dispatch thread plz"); listModel.clear(); if (clustering.getNumClusters() < 2) { scroll.setVisible(false); return; } listModel.addElement(AllCompounds); Cluster clusters[] = new Cluster[clustering.numClusters()]; clustering.getClusters().toArray(clusters); if (viewControler.getHighlightedProperty() != null) Arrays.sort(clusters); for (Cluster c : clusters) if (c.getNumCompounds() > 0) listModel.addElement(c); updateListSize(); scroll.setVisible(listModel.size() > 1); updateListSize(); revalidate(); if (clustering.isClusterActive()) updateCluster(clustering.getActiveCluster()); } private void updateListSize() { // System.err.println("row height " + listRenderer.getRowHeight()); int rowCount = (guiControler.getComponentMaxHeight(1) / listRenderer.getRowHeight()) / 3; // System.err.println("row count " + rowCount); double ratioVisible = rowCount / (double) listModel.getSize(); if (ratioVisible <= 0.5) { // if less then 50% of elements is visible increase by up to 50% double ratioIncrease = 0.5 - ratioVisible; rowCount += (int) (ratioIncrease * rowCount); } clusterList.setVisibleRowCount(rowCount); scroll.setPreferredSize(null); int width = guiControler.getComponentMaxWidth(ComponentSize.CLUSTER_LIST.getValue() * 0.01); if (!guiControler.isAccentuateComponents()) width = Math.min(width, scroll.getPreferredSize().width); scroll.setPreferredSize(new Dimension(width, scroll.getPreferredSize().height)); scroll.revalidate(); scroll.repaint(); } @SuppressWarnings("unchecked") private void buildLayout() { listModel = new DefaultListModel<DoubleNameElement>(); clusterList = new MouseOverList(listModel); clusterList.setClearOnExit(false); clusterList.setFocusable(false); clusterList.setOpaque(false); listRenderer = new DoubleNameListCellRenderer(listModel) { @Override public void updateUI() { super.updateUI(); if (getFontLabel1() != null) { setFontLabel1(getFontLabel1().deriveFont((float) ScreenSetup.INSTANCE.getFontSize())); setFontLabel2(getFontLabel2().deriveFont((float) ScreenSetup.INSTANCE.getFontSize())); clusterList.setFixedCellHeight(getRowHeight()); // clusterList.setPreferredSize(null); } } @SuppressWarnings("rawtypes") public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); Cluster c = value == AllCompounds ? null : (Cluster) value; setOpaque(isSelected || c == clustering.getActiveCluster()); setForeground(ComponentFactory.FOREGROUND); setBackground(ComponentFactory.BACKGROUND); if ((c != null && clustering.isClusterActive() && c == clustering.getActiveCluster()) || (c == null && viewControler.isSingleCompoundSelection())) { setBackground(ComponentFactory.LIST_ACTIVE_BACKGROUND); setForeground(ComponentFactory.LIST_SELECTION_FOREGROUND); } else if (isSelected) { setBackground(ComponentFactory.LIST_WATCH_BACKGROUND); setForeground(ComponentFactory.LIST_SELECTION_FOREGROUND); } else if (c != null) { setForegroundLabel2(c.getHighlightColorText()); } else if (c == null) { setForegroundLabel2(clustering.getHighlightColorText()); } return this; } }; listRenderer.setFontLabel2(listRenderer.getFontLabel2().deriveFont(Font.ITALIC)); clusterList.setCellRenderer(listRenderer); compoundListPanel = new CompoundListPanel(clustering, clusterControler, viewControler, guiControler); setLayout(new BorderLayout(0, 0)); FormLayout layout = new FormLayout("pref,6,pref", "fill:pref"); JPanel panel = new JPanel(); panel.setOpaque(false); panel.setLayout(layout); CellConstraints cc = new CellConstraints(); scroll = ComponentFactory.createViewScrollpane(clusterList); guiControler.registerSizeComponent(ComponentSize.CLUSTER_LIST, scroll); clusterPanel = new TransparentViewPanel(new BorderLayout(5, 5)); clusterPanel.add(scroll); panel.add(clusterPanel, cc.xy(1, 1)); panel.add(compoundListPanel, cc.xy(3, 1)); add(panel, BorderLayout.WEST); controlPanel = new ControlPanel(viewControler, clusterControler, clustering, guiControler); add(controlPanel, BorderLayout.SOUTH); filterLabel = ComponentFactory.createViewLabel("Filter applied:", ImageLoader.getImage(ImageLoader.Image.filter14_black), ImageLoader.getImage(ImageLoader.Image.filter14)); filterRemoveButton = ComponentFactory.createCrossViewButton(); filterRemoveButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Thread th = new Thread(new Runnable() { public void run() { clusterControler.setCompoundFilter(null, true); } }); th.start(); } }); filterPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));//new BorderLayout()); filterPanel.setOpaque(false); filterPanel.add(filterLabel);//, BorderLayout.WEST); filterPanel.add(filterRemoveButton);//, BorderLayout.EAST); filterPanel.setVisible(false); add(filterPanel, BorderLayout.NORTH); setBorder(new EmptyBorder(25, 25, 25, 25)); setOpaque(false); } private void updateFilter() { if (clusterControler.getCompoundFilter() == null || clustering.getNumClusters() == 0) { filterPanel.setVisible(false); } else { filterPanel.setIgnoreRepaint(true); filterLabel.setText(clusterControler.getCompoundFilter().toString()); filterPanel.setIgnoreRepaint(false); filterPanel.setVisible(true); } } private void updateCluster(Cluster c) { if (selfBlock) return; selfBlock = true; if (c == null) clusterList.clearSelection(); else clusterList.setSelectedValue(c, true); selfBlock = false; } }