biomine.bmvis2.crawling.CrawlSuggestionList.java Source code

Java tutorial

Introduction

Here is the source code for biomine.bmvis2.crawling.CrawlSuggestionList.java

Source

/*
 * Copyright 2012 University of Helsinki.
 *
 * This file is part of BMVis.
 *
 * BMVis is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * BMVis 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 along with BMVis.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

package biomine.bmvis2.crawling;

import java.awt.Color;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.AbstractAction;
import javax.swing.AbstractListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

import biomine.bmgraph.BMNode;
import biomine.bmvis2.VisualNode;
import biomine.bmvis2.crawling.SuggestionQuery.NodeItem;
import biomine.bmvis2.crawling.SuggestionQuery.NodeType;

/**
 * 
 * Component for selecting nodes for queries. Uses suggest.cgi web-interface and
 * so requires internet access.
 * 
 * @author alhartik
 * 
 */
public class CrawlSuggestionList extends JPanel {

    JTextField query = new JTextField();

    JButton back = new JButton();
    JList list = new JList();
    JList selectedList = new JList();

    ArrayList<NodeItem> selectedNodes = new ArrayList<NodeItem>();

    JScrollPane listScroller = new JScrollPane();
    final SuggestionQuery suggestionQuery = new SuggestionQuery();

    HashMap<String, String> nameMap = new HashMap<String, String>();

    public String getName(String queryid) {
        return nameMap.get(queryid);
    }

    class SelectedListModel extends AbstractListModel {
        public Object getElementAt(int i) {
            return selectedNodes.get(i);
        }

        public int getSize() {
            return selectedNodes.size();
        }
    }

    class SuggestListModel extends AbstractListModel {
        public Object getElementAt(int i) {
            return itemList.get(i);
        }

        public int getSize() {
            return itemList.size();
        }
    }

    public void addSelection(NodeItem item) {
        System.out.println("adding " + item.getName());
        if (selectedNodes.contains(item))
            return;
        selectedNodes.add(item);
        selectedList.updateUI();

    }

    public void removeSelection(NodeItem item) {
        selectedNodes.remove(item);
        System.out.println("removing " + item.getName());
        selectedList.updateUI();
    }

    Object hoveredObject = null;

    class SuggestCellRenderer implements ListCellRenderer {

        class NodeComp extends JPanel {

            public NodeComp(final NodeItem item, boolean selected) {
                JLabel text = new JLabel(item.getName());

                this.setLayout(new GridLayout());

                this.add(text);
                boolean hover = hoveredObject != null && item.equals(hoveredObject);
                this.setBackground(new Color(62, 200, 64));
                if (hover)
                    this.setBackground(new Color(128, 255, 128));

            }
        }

        class TypeComp extends JPanel {
            public TypeComp(NodeType t, boolean selected) {
                this.setLayout(new GridBagLayout());
                GridBagConstraints c = new GridBagConstraints();
                c.gridx = 0;
                c.gridy = 0;
                c.fill = GridBagConstraints.HORIZONTAL;
                c.weightx = 1;

                this.add(new JLabel(t.name), c);
                JLabel text = new JLabel(t.more);
                // + " -- type=" + t.tcode + " organism=" + t.ocode);
                text.setAlignmentX(RIGHT_ALIGNMENT);

                c.fill = c.NONE;
                c.anchor = GridBagConstraints.EAST;
                c.gridx = 1;
                this.add(text, c);
                this.setBackground(new Color(52, 125, 53));
                if (t.ocode == 0 && t.tcode == 0)
                    setBackground(Color.gray);

                boolean hover = hoveredObject != null && t.equals(hoveredObject);
                if (hover)
                    this.setBackground(new Color(128, 255, 128));

            }
        }

        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
                boolean cellHasFocus) {
            if (value instanceof NodeItem)
                return new NodeComp((NodeItem) value, isSelected);
            if (value instanceof NodeType)
                return new TypeComp((NodeType) value, isSelected);
            return null;
        }

    }

    class SuggestMouseListener implements MouseListener, MouseMotionListener {
        JList mylist;

        public SuggestMouseListener(JList l) {
            mylist = l;
        }

        public void mouseClicked(MouseEvent e) {
            int x = e.getX();
            int y = e.getY();
            int cell = mylist.locationToIndex(e.getPoint());
            System.out.println(e.getPoint());
            System.out.println("mylist=" + mylist);
            if (mylist.getCellBounds(cell, cell) != null)
                if (mylist.getCellBounds(cell, cell).contains(e.getPoint())) {
                    if (e.getClickCount() >= 1) {
                        // DOUBLECLICK ON CELL!!
                        Object value = mylist.getModel().getElementAt(cell);
                        if (value instanceof NodeItem) {
                            NodeItem ni = (NodeItem) value;
                            if (mylist == selectedList)
                                removeSelection(ni);
                            else
                                addSelection((NodeItem) value);
                        }
                        if (value instanceof NodeType) {
                            NodeType nt = (NodeType) value;
                            suggestionQuery.focusType(nt);
                            updateList();
                        }
                    }
                }
        }

        public void mouseEntered(MouseEvent e) {
            // TODO Auto-generated method stub

        }

        public void mouseExited(MouseEvent e) {
            hoveredObject = null;
            redrawLists();
        }

        public void mousePressed(MouseEvent e) {
        }

        public void mouseReleased(MouseEvent e) {
        }

        public void mouseDragged(MouseEvent e) {
            // TODO Auto-generated method stub

        }

        public void mouseMoved(MouseEvent e) {
            int cell = mylist.locationToIndex(e.getPoint());
            Rectangle bounds = mylist.getCellBounds(cell, cell);
            if (bounds == null)
                return;
            if (bounds.contains(e.getPoint())) {
                hoveredObject = mylist.getModel().getElementAt(cell);

            }
            redrawLists();
        }
    }

    private String db = null;

    private JComboBox dbSelect = null;

    public CrawlSuggestionList() {
        // setMinimumSize(new Dimension(600,200));

        // initialize layout
        GridBagLayout layout = new GridBagLayout();

        this.setLayout(layout);
        GridBagConstraints c = new GridBagConstraints();

        c.weightx = 1;
        c.weighty = 0;
        c.gridx = 0;
        c.gridy = 0;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridwidth = 1;
        c.gridheight = 1;

        dbSelect = new JComboBox();
        for (String db : Databases.getDatabases()) {
            dbSelect.addItem(db);
        }

        dbSelect.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                suggestionQuery.setDb(dbSelect.getSelectedItem().toString());
            }
        });

        this.add(dbSelect, c);
        c.gridy++;
        this.add(query, c);

        c.gridwidth = 1;
        c.weighty = 3;
        c.weightx = 10;
        c.fill = GridBagConstraints.BOTH;
        c.gridx = 0;
        c.gridy++;
        // listScroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        listScroller = new JScrollPane(list);
        this.add(listScroller, c);

        c.weighty = 0;
        c.weightx = 10;
        c.gridwidth = 1;
        c.gridx = 0;
        c.gridy++;
        this.add(new JLabel("Selected nodes:"), c);

        c.weighty = 3;
        c.weightx = 10;
        c.gridwidth = 1;
        c.gridx = 0;
        c.gridy++;
        JScrollPane selectedScroller = new JScrollPane(selectedList);
        this.add(selectedScroller, c);

        // initialize components
        back.setAction(new AbstractAction("< back to unfiltered results") {

            public void actionPerformed(ActionEvent arg0) {
                suggestionQuery.back();
                updateList();
            }
        });
        query.addCaretListener(new CaretListener() {
            public void caretUpdate(CaretEvent arg0) {
                updateList();
            }

        });

        list.setModel(new SuggestListModel());
        list.addMouseListener(new SuggestMouseListener(list));
        list.addMouseMotionListener(new SuggestMouseListener(list));

        list.setCellRenderer(new SuggestCellRenderer());

        selectedList.setModel(new SelectedListModel());
        selectedList.addMouseListener(new SuggestMouseListener(selectedList));
        selectedList.addMouseMotionListener(new SuggestMouseListener(selectedList));
        selectedList.setCellRenderer(new SuggestCellRenderer());
    }

    public boolean isSelected(NodeItem ni) {
        return selectedNodes.contains(ni);
    }

    public void redrawLists() {
        list.updateUI();
        selectedList.updateUI();
    }

    /**
     * Tries to add node by name
     * @param name
     * @return true if we find the node from db
     */
    public void addNode(VisualNode vn) {
        BMNode bmn = vn.getBMNode();
        System.out.println("adding to query:" + vn + " shortname=" + bmn.get("ShortName"));

        if (bmn == null)
            throw new RuntimeException("Only proper nodes can be queried");
        String shortName = bmn.get("ShortName");
        if (shortName == null)
            shortName = bmn.getId();
        this.selectedNodes.add(new SuggestionQuery.NodeItem(bmn.getId(), shortName));
    }

    ArrayList<Object> itemList = new ArrayList<Object>();

    private int curVersion = 0;

    private void updateList() {
        final int myVersion = ++curVersion;
        SwingWorker<Void, Void> work = new SwingWorker<Void, Void>() {
            protected Void doInBackground() throws Exception {

                try {
                    suggestionQuery.setQuery(query.getText());
                    suggestionQuery.updateResult();
                } catch (final IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            JOptionPane.showMessageDialog(CrawlSuggestionList.this, e.getMessage());
                        }
                    });
                    return null;
                }
                // update list in event thread
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        // this thread finished after new thread was started
                        if (myVersion < curVersion)
                            return;
                        itemList.clear();
                        for (NodeType n : suggestionQuery.getResult()) {
                            itemList.add(n);
                            for (NodeItem ni : n.items) {
                                nameMap.put(ni.getCode(), ni.getName());
                                itemList.add(ni);
                            }
                        }
                        list.updateUI();
                    }
                });
                return null;
            }
        };

        work.execute();

    }

    public String getDatabase() {
        return suggestionQuery.getDb();
    }

    public void setDatabase(String str) {
        dbSelect.setSelectedItem(str);
    }

    public CrawlQuery getQueryTerms() {
        ArrayList<String> ret = new ArrayList<String>();
        for (NodeItem it : selectedNodes)
            ret.add(it.getCode());
        return new CrawlQuery(ret);
    }
}

class SuggestionQuery {

    private String query;
    private int type;
    private int organism;
    private String db = null;

    public String getDb() {
        return db;
    }

    public void setDb(String db) {
        this.db = db;
    }

    private ArrayList<NodeType> resultList = new ArrayList<NodeType>();

    private ArrayList<NodeType> fetchList(String q, int type, int organism) throws IOException {

        ArrayList<NodeType> ret = new ArrayList<NodeType>();
        if (q.length() == 0)
            return ret;
        String typePar = type <= 0 ? "" : ("type=" + type + "__");
        String orgPar = organism <= 0 ? "" : ("organism=" + organism + "__");
        String dbPar = db == null ? "" : ("db=" + URLEncoder.encode(db, "UTF-8") + "__");

        URL u = new URL(WebConstants.DEFAULT_BASEURL + "suggest.cgi?" + orgPar + typePar + dbPar + "term="
                + URLEncoder.encode(q, "UTF-8"));

        System.out.println("querying " + u + " organism=" + organism + " type=" + type);

        String jsonStr = URLUtils.getURLContents(u);
        if (type != 0) {
            NodeType back = new NodeType();
            back.name = "back to unfiltered results";
            back.tcode = 0;
            back.ocode = 0;
            ret.add(back);
        }
        try {
            JSONArray ja = (JSONArray) JSONValue.parse(jsonStr);

            for (Object orgz : ja) {

                JSONObject orgtype = (JSONObject) orgz;
                Long tcodeL = (Long) orgtype.get("type");
                int tcode = tcodeL.intValue();
                Long ocodeL = (Long) orgtype.get("organism");
                int ocode = ocodeL.intValue();

                NodeType curType = null;
                curType = new NodeType();
                curType.tcode = tcode;
                curType.ocode = ocode;
                curType.name = orgtype.get("text").toString();
                curType.more = orgtype.get("unshown").toString();
                ret.add(curType);

                JSONArray match = (JSONArray) orgtype.get("matches");
                for (Object o : match) {
                    JSONObject node = (JSONObject) o;

                    String code = node.get("term").toString();
                    String name = node.get("title").toString();

                    NodeItem it = new NodeItem(code, name);
                    curType.items.add(it);
                }

            }
        } catch (ClassCastException e) {
            throw new IOException("Invalid JSON from server", e);
        }
        return ret;
    }

    public static class NodeItem {
        private String code;
        private String name;

        public NodeItem(String c, String n) {
            code = c;
            name = n;
        }

        public String getCode() {
            return code;
        }

        public String getName() {
            return name;
        }

        public boolean equals(Object o) {
            if (o.getClass() == getClass()) {
                NodeItem oi = (NodeItem) o;
                return oi.name.equals(name) && oi.code.equals(code);
            }
            return false;
        }

        public int hashCode() {
            return code.hashCode() + Integer.rotateLeft(name.hashCode(), 12);
        }
    }

    class NodeType {
        int tcode;
        int ocode;
        String name;
        ArrayList<NodeItem> items = new ArrayList<NodeItem>();
        String more;
    }

    /**
     * Resets state to show unfiltered results (needs updating before getResult
     * changes)
     */
    void back() {
        type = 0;
        organism = 0;
    }

    /**
     * Sets query to show only results of given type (needs updating before
     * getResult changes)
     */
    void focusType(NodeType t) {
        type = t.tcode;
        organism = t.ocode;
    }

    void setQuery(String q) {
        query = q;
    }

    /**
     * Updates suggestion list
     * 
     * @throws IOException
     *             when something goes bad in networkstuff
     */
    void updateResult() throws IOException {
        resultList = fetchList(query, type, organism);
        System.out.println("updateResult");

    }

    ArrayList<NodeType> getResult() {
        return resultList;
    }

}