org.mongkie.ui.context.VisibilityContextPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.mongkie.ui.context.VisibilityContextPanel.java

Source

/*
 * This file is part of MONGKIE. Visit <http://www.mongkie.org/> for details.
 * Visit <http://www.mongkie.org> for details about MONGKIE.
 * Copyright (C) 2013 Korean Bioinformation Center (KOBIC)
 *
 * MONGKIE 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.
 *
 * MONGKIE 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 org.mongkie.ui.context;

import java.awt.BorderLayout;
import java.awt.Color;
import java.text.AttributedString;
import java.util.Iterator;
import java.util.Set;
import javax.swing.Icon;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import kobic.prefuse.Constants;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import org.mongkie.context.spi.ContextUI;
import org.mongkie.filter.FilterController;
import org.mongkie.filter.FilterModelListener;
import org.mongkie.filter.spi.Filter;
import org.mongkie.util.AccumulativeEventsProcessor;
import org.mongkie.visualization.MongkieDisplay;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.lookup.ServiceProvider;
import prefuse.data.Graph;
import prefuse.data.event.EventConstants;
import prefuse.data.event.GraphListener;

/**
 *
 * @author Yeongjun Jang <yjjang@kribb.re.kr>
 */
@ServiceProvider(service = ContextUI.class, position = 1)
public class VisibilityContextPanel extends javax.swing.JPanel
        implements ContextUI, FilterModelListener, GraphListener {

    private final VisibilityDataSet nodesVisibility, edgesVisibility;
    private static final String NA = "NA";

    /**
     * Creates new form VisibilityContextPanel
     */
    public VisibilityContextPanel() {
        Lookup.getDefault().lookup(FilterController.class); // Bootstrap the filter controller instance
        initComponents();
        nodesPiePanel.add(new VisibilityPie("Nodes", nodesVisibility = new VisibilityDataSet(Constants.NODES)),
                BorderLayout.CENTER);
        edgesPiePanel.add(new VisibilityPie("Edges", edgesVisibility = new VisibilityDataSet(Constants.EDGES)),
                BorderLayout.CENTER);
    }

    @Override
    public String getName() {
        return "Visibility";
    }

    @Override
    public void graphChanged(Graph g, String table, int start, int end, int col, int type) {
        if (!currentDisplay.isLoading() && col == EventConstants.ALL_COLUMNS) {
            // refreshLazy(currentDisplay);
            currentDisplay.getVisualization().invokeAfterDataProcessing(this, new Runnable() {
                @Override
                public void run() {
                    refresh(currentDisplay);
                }
            });
        }
    }

    private void refreshLazy(final MongkieDisplay display) {
        if (refreshQ != null && refreshQ.isAccumulating()) {
            refreshQ.eventAttended();
        } else {
            refreshQ = new AccumulativeEventsProcessor(new Runnable() {
                @Override
                public void run() {
                    refresh(display);
                }
            });
            refreshQ.start();
        }
    }

    private AccumulativeEventsProcessor refreshQ;

    @Override
    public void refresh(final MongkieDisplay display) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                nodesVisibility.update(display);
                int nodesFullCount = nodesVisibility.getFullCount();
                nodesCountInfoLabel.setText(
                        nodesFullCount == 0 ? NA : nodesVisibility.getVisibleCount() + "/" + nodesFullCount);
                edgesVisibility.update(display);
                int edgesFullCount = edgesVisibility.getFullCount();
                edgesCountInfoLabel.setText(
                        edgesFullCount == 0 ? NA : edgesVisibility.getVisibleCount() + "/" + edgesFullCount);
                if (currentDisplay != display) {
                    if (currentDisplay != null) {
                        Lookup.getDefault().lookup(FilterController.class).getModel(currentDisplay)
                                .removeModelListener(VisibilityContextPanel.this);
                        currentDisplay.getGraph().removeGraphModelListener(VisibilityContextPanel.this);
                    }
                    currentDisplay = display;
                    Lookup.getDefault().lookup(FilterController.class).getModel(currentDisplay)
                            .addModelListener(VisibilityContextPanel.this);
                    currentDisplay.getGraph().addGraphModelListener(VisibilityContextPanel.this);
                }
                if (!isVisible()) {
                    setVisible(true);
                }
            }
        });
    }

    private MongkieDisplay currentDisplay;

    @Override
    public void unload() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                if (currentDisplay != null) {
                    Lookup.getDefault().lookup(FilterController.class).getModel(currentDisplay)
                            .removeModelListener(VisibilityContextPanel.this);
                    currentDisplay.getGraph().removeGraphModelListener(VisibilityContextPanel.this);
                    currentDisplay = null;
                }
                setVisible(false);
            }
        });
    }

    @Override
    public void fitersApplied(Set<Filter> nodeFilters, Set<Filter> edgeFilters) {
        assert currentDisplay != null;
        refreshLazy(currentDisplay);
    }

    @Override
    public Icon getIcon() {
        return ImageUtilities.loadImageIcon("org/mongkie/ui/context/resources/context.png", false);
    }

    @Override
    public String getTooltip() {
        return null;
    }

    @Override
    public JPanel getPanel() {
        return this;
    }

    /**
     * This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        nodesTitledSeparator = new org.jdesktop.swingx.JXTitledSeparator();
        nodesPiePanel = new javax.swing.JPanel();
        edgesTitledSeparator = new org.jdesktop.swingx.JXTitledSeparator();
        edgesPiePanel = new javax.swing.JPanel();
        nodesCountInfoLabel = new javax.swing.JLabel();
        edgesCountInfoLabel = new javax.swing.JLabel();

        nodesTitledSeparator.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        nodesTitledSeparator.setTitle(org.openide.util.NbBundle.getMessage(VisibilityContextPanel.class,
                "VisibilityContextPanel.nodesTitledSeparator.title")); // NOI18N

        nodesPiePanel.setLayout(new java.awt.BorderLayout());

        edgesTitledSeparator.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        edgesTitledSeparator.setTitle(org.openide.util.NbBundle.getMessage(VisibilityContextPanel.class,
                "VisibilityContextPanel.edgesTitledSeparator.title")); // NOI18N

        edgesPiePanel.setLayout(new java.awt.BorderLayout());

        nodesCountInfoLabel.setFont(new java.awt.Font("Tahoma", 1, 10)); // NOI18N
        nodesCountInfoLabel.setLabelFor(nodesPiePanel);
        org.openide.awt.Mnemonics.setLocalizedText(nodesCountInfoLabel, org.openide.util.NbBundle
                .getMessage(VisibilityContextPanel.class, "VisibilityContextPanel.nodesCountInfoLabel.text")); // NOI18N

        edgesCountInfoLabel.setFont(new java.awt.Font("Tahoma", 1, 10)); // NOI18N
        edgesCountInfoLabel.setLabelFor(edgesPiePanel);
        org.openide.awt.Mnemonics.setLocalizedText(edgesCountInfoLabel, org.openide.util.NbBundle
                .getMessage(VisibilityContextPanel.class, "VisibilityContextPanel.edgesCountInfoLabel.text")); // NOI18N

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup().addContainerGap().addGroup(layout
                        .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addComponent(nodesTitledSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 251,
                                Short.MAX_VALUE)
                        .addComponent(edgesTitledSeparator, javax.swing.GroupLayout.DEFAULT_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                                .addGap(0, 0, Short.MAX_VALUE)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addComponent(nodesCountInfoLabel,
                                                javax.swing.GroupLayout.Alignment.TRAILING)
                                        .addComponent(edgesCountInfoLabel,
                                                javax.swing.GroupLayout.Alignment.TRAILING)))
                        .addComponent(nodesPiePanel, javax.swing.GroupLayout.DEFAULT_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(edgesPiePanel, javax.swing.GroupLayout.DEFAULT_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addContainerGap()));
        layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup().addContainerGap()
                        .addComponent(nodesTitledSeparator, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(nodesCountInfoLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(nodesPiePanel, javax.swing.GroupLayout.PREFERRED_SIZE, 140,
                                javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(edgesTitledSeparator, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(edgesCountInfoLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(edgesPiePanel, javax.swing.GroupLayout.PREFERRED_SIZE, 140,
                                javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)));
    }// </editor-fold>//GEN-END:initComponents
     // Variables declaration - do not modify//GEN-BEGIN:variables

    private javax.swing.JLabel edgesCountInfoLabel;
    private javax.swing.JPanel edgesPiePanel;
    private org.jdesktop.swingx.JXTitledSeparator edgesTitledSeparator;
    private javax.swing.JLabel nodesCountInfoLabel;
    private javax.swing.JPanel nodesPiePanel;
    private org.jdesktop.swingx.JXTitledSeparator nodesTitledSeparator;
    // End of variables declaration//GEN-END:variables

    private static class VisibilityPie extends ChartPanel {

        VisibilityPie(String title, VisibilityDataSet data) {
            super(ChartFactory.createPieChart(title, data, false, false, false), true, true, true, false, true);
            setMinimumDrawWidth(0);
            setMaximumDrawWidth(Integer.MAX_VALUE);
            setMinimumDrawHeight(0);
            setMaximumDrawHeight(Integer.MAX_VALUE);
            JFreeChart chart = getChart();
            chart.setTitle(new TextTitle());
            chart.setBackgroundPaint(null);
            PiePlot plot = (PiePlot) chart.getPlot();
            plot.setShadowPaint(null);
            plot.setOutlineVisible(false);
            plot.setInteriorGap(0);
            plot.setSimpleLabels(true);
            plot.setLabelBackgroundPaint(null);
            plot.setLabelPaint(Color.WHITE);
            plot.setLabelOutlineStroke(null);
            plot.setLabelShadowPaint(null);
            plot.setLabelFont(new java.awt.Font("Dialog", 0, 10));
            plot.setLabelGap(0.5);
            plot.setLabelGenerator(new PieSectionLabelGenerator() {
                @Override
                public String generateSectionLabel(PieDataset pd, Comparable section) {
                    VisibilityDataSet visibility = (VisibilityDataSet) pd;
                    int fullCount = visibility.getFullCount();
                    if (fullCount == 0) {
                        return section.toString();
                    } else if (VISIBLE.equals(section)) {
                        return VISIBLE + " (" + visibility.getVisibleCount() + ")";
                    } else if (NOT_VISIBLE.equals(section)) {
                        return NOT_VISIBLE + " (" + (fullCount - visibility.getVisibleCount()) + ")";
                    }
                    throw new AssertionError();
                }

                @Override
                public AttributedString generateAttributedSectionLabel(PieDataset pd, Comparable cmprbl) {
                    throw new UnsupportedOperationException("Not supported.");
                }
            });
            plot.setCircular(true);
            plot.setBackgroundPaint(null);
            plot.setBackgroundAlpha(1f);
            plot.setSectionPaint(VISIBLE, new Color(0x444444));
            plot.setSectionPaint(NOT_VISIBLE, new Color(0xAAAAAA));
            setOpaque(false);
            // setPopupMenu(null);
        }
    }

    private static class VisibilityDataSet extends DefaultPieDataset {

        private int visibleCount, fullCount;
        private final String group;

        VisibilityDataSet(String group) {
            setValue(VISIBLE, 1.0);
            setValue(NOT_VISIBLE, 0.0);
            this.group = group;
        }

        void update(MongkieDisplay display) {
            fullCount = count(display.getVisualization().items(group));
            visibleCount = count(display.getVisualization().visibleItems(group));
            setValue(VISIBLE, fullCount == 0 ? 1.0 : visibleCount);
            setValue(NOT_VISIBLE, fullCount - visibleCount);
        }

        private int count(Iterator items) {
            int i = 0;
            while (items.hasNext()) {
                items.next();
                i++;
            }
            return i;
        }

        int getVisibleCount() {
            return visibleCount;
        }

        int getFullCount() {
            return fullCount;
        }
    }

    private static final String VISIBLE = "Visible";
    private static final String NOT_VISIBLE = "Not visible";
}