From dc196ddae58e2fc49774931f5ef6464e8a8ac591 Mon Sep 17 00:00:00 2001 From: Jim Robinson <933148+jrobinso@users.noreply.github.com> Date: Sun, 6 Oct 2024 20:32:48 -0700 Subject: [PATCH] Encode (#1594) --- scripts/mac.app/Contents/MacOS/main.c | 146 ++++++++ .../igv/{util => }/encode/DCCEncodeUtils.java | 2 +- .../{util => }/encode/EncodeFileRecord.java | 19 +- .../{util => }/encode/EncodeTableModel.java | 36 +- .../EncodeTrackChooser.java} | 314 ++++++++++++------ .../{util => }/encode/UCSCEncodeUtils.java | 130 ++------ .../broad/igv/maf/MultipleAlignmentTrack.java | 2 +- .../java/org/broad/igv/prefs/Constants.java | 3 + .../java/org/broad/igv/sam/CoverageTrack.java | 4 +- .../broad/igv/sam/SpliceJunctionTrack.java | 7 +- .../org/broad/igv/track/AbstractTrack.java | 37 ++- .../broad/igv/track/CombinedDataTrack.java | 4 +- .../org/broad/igv/track/SequenceTrack.java | 6 +- src/main/java/org/broad/igv/track/Track.java | 2 +- .../java/org/broad/igv/ui/IGVMenuBar.java | 98 +++--- .../igv/ui/action/BrowseEncodeAction.java | 102 ++++-- .../broad/igv/ui/action/UCSCGenArkAction.java | 9 - .../broad/igv/ui/panel/TrackNamePanel.java | 2 +- .../org/broad/igv/util/ResourceLocator.java | 13 +- .../org/broad/igv/variant/VariantTrack.java | 8 +- .../igv/{util => }/encode/encode.hg18.txt | 0 .../igv/{util => }/encode/encode.hg19.txt | 0 .../igv/{util => }/encode/encode.mm9.txt | 0 .../org/broad/igv/prefs/preferences.tab | 2 + 24 files changed, 574 insertions(+), 372 deletions(-) create mode 100644 scripts/mac.app/Contents/MacOS/main.c rename src/main/java/org/broad/igv/{util => }/encode/DCCEncodeUtils.java (98%) rename src/main/java/org/broad/igv/{util => }/encode/EncodeFileRecord.java (87%) rename src/main/java/org/broad/igv/{util => }/encode/EncodeTableModel.java (81%) rename src/main/java/org/broad/igv/{util/encode/EncodeFileBrowser.java => encode/EncodeTrackChooser.java} (55%) rename src/main/java/org/broad/igv/{util => }/encode/UCSCEncodeUtils.java (57%) rename src/main/resources/org/broad/igv/{util => }/encode/encode.hg18.txt (100%) rename src/main/resources/org/broad/igv/{util => }/encode/encode.hg19.txt (100%) rename src/main/resources/org/broad/igv/{util => }/encode/encode.mm9.txt (100%) diff --git a/scripts/mac.app/Contents/MacOS/main.c b/scripts/mac.app/Contents/MacOS/main.c new file mode 100644 index 0000000000..5cf4bc0035 --- /dev/null +++ b/scripts/mac.app/Contents/MacOS/main.c @@ -0,0 +1,146 @@ +// +// main.c +// igv-launcher +// +// Created by James Robinson on 9/14/24. +// +// Launch IGV on MacOS (https://github.com/igvteam/igv). +// +// Code adapted from https://incenp.org/notes/2023/universal-java-app-on-macos.html +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Remove the last n components of a pathname. The pathname + * is modified in place. Returns 0 if the requested number + * of components have been removed, -1 otherwise. */ +static int remove_last_component(char *buffer , unsigned n) +{ + char *last_slash = NULL; + while ( n-- > 0 ) { + if ( (last_slash = strrchr(buffer, '/')) ) + *last_slash = '\0'; + } + return last_slash ? 0 : -1; +} + +/* + * Test if a given path exists and if it is a directory. + * It returns 1 if given path is directory and exists + * otherwise returns 0. + */ +static int isDirectoryExists(const char *path) +{ + struct stat stats; + stat(path, &stats); + + // Check for file existence + if (S_ISDIR(stats.st_mode)) + return 1; + + return 0; +} + +static int simpleLauncher(int argc, char **argv) +{ + char app_path[PATH_MAX]; + uint32_t path_size = PATH_MAX; + int ret = 0; + + (void) argc; + (void) argv; + + /* Get the path to the "Contents" directory. */ + if ( _NSGetExecutablePath(app_path, &path_size) == -1 ) + err(EXIT_FAILURE, "Cannot get application directory"); + if ( remove_last_component(app_path, 2) == -1 ) + errx(EXIT_FAILURE, "Cannot get application directory"); + + /* Move to that directory. */ + if ( chdir(app_path) == -1 ) + err(EXIT_FAILURE, "Cannot change current directory"); + + char* cmd; + + /* See if there is a bundled JDK */ + if(isDirectoryExists("jdk-21")) { + char jdkPath[2048] = {'\0'}; + snprintf(jdkPath, sizeof(jdkPath), "%s/jdk-21", app_path); + + setenv("JAVA_HOME", jdkPath, true); + + char javaPath[2048] = {'\0'}; + snprintf(javaPath, sizeof(javaPath), "%s/bin/java", jdkPath); + cmd = javaPath; + + printf("Using bundled JDK"); + + //PATH=$JAVA_HOME/bin:$PATH + } else { + + cmd = "java"; + printf("Using System JDK\n"); + } + + /* Get user defined extra arguments, if any */ + char extraArgumentsPath[2048] = {'\0'}; + const char *homeDir = getenv("HOME"); + snprintf(extraArgumentsPath, sizeof(extraArgumentsPath), "%s/.igv/java_arguments", homeDir); + + if(access(extraArgumentsPath, F_OK) == 0) { + char extraArguments[2048] = {'\0'}; + snprintf(extraArguments, sizeof(extraArguments), "@%s", extraArgumentsPath); + + /* Run IGV with user extra arguments */ + + + char* args[] = { + "java", + "-showversion", + "--module-path=Java/lib", + "-Xmx8g", + "@Java/igv.args", + "-Xdock:name=IGV", + "-Xdock:icon=Resources/IGV_64.png", + "-Dapple.laf.useScreenMenuBar=true", + extraArguments, + "--module=org.igv/org.broad.igv.ui.Main", + NULL}; + + ret = execvp(cmd, args); + return ret; + + } else { + + /* Run IGV without user extra arguments */ + + char* args[] = { + "java", + "-showversion", + "--module-path=Java/lib", + "-Xmx8g", + "@Java/igv.args", + "-Xdock:name=IGV", + "-Xdock:icon=Resources/IGV_64.png", + "--module=org.igv/org.broad.igv.ui.Main", + NULL}; + + ret = execvp(cmd, args); + return ret; + } +} + +int main(int argc, char **argv) +{ + return simpleLauncher(argc, argv); +} diff --git a/src/main/java/org/broad/igv/util/encode/DCCEncodeUtils.java b/src/main/java/org/broad/igv/encode/DCCEncodeUtils.java similarity index 98% rename from src/main/java/org/broad/igv/util/encode/DCCEncodeUtils.java rename to src/main/java/org/broad/igv/encode/DCCEncodeUtils.java index fe517c1334..5ea688d9e2 100644 --- a/src/main/java/org/broad/igv/util/encode/DCCEncodeUtils.java +++ b/src/main/java/org/broad/igv/encode/DCCEncodeUtils.java @@ -23,7 +23,7 @@ * THE SOFTWARE. */ -package org.broad.igv.util.encode; +package org.broad.igv.encode; /** * Created by jrobinso on 6/4/15. diff --git a/src/main/java/org/broad/igv/util/encode/EncodeFileRecord.java b/src/main/java/org/broad/igv/encode/EncodeFileRecord.java similarity index 87% rename from src/main/java/org/broad/igv/util/encode/EncodeFileRecord.java rename to src/main/java/org/broad/igv/encode/EncodeFileRecord.java index 56cd8beb17..ca95a8d1a2 100644 --- a/src/main/java/org/broad/igv/util/encode/EncodeFileRecord.java +++ b/src/main/java/org/broad/igv/encode/EncodeFileRecord.java @@ -23,7 +23,7 @@ * THE SOFTWARE. */ -package org.broad.igv.util.encode; +package org.broad.igv.encode; import java.io.File; import java.util.Collection; @@ -70,11 +70,8 @@ public Collection getAttributeNames() { return attributes.keySet(); } - public boolean containsText(String filter) { - for (String value : attributes.values()) { - if (value.contains(filter)) return true; - } - return false; + public Map getAttributes() { + return attributes; } boolean isSelected() { @@ -108,14 +105,4 @@ public String getTrackName() { } - /** - * Test if record has a eough of meta-data to be interpretable - * - * @return - */ - public boolean hasMetaData() { - - return (attributes.containsKey("cell")) || (attributes.containsKey("antibody")); - - } } diff --git a/src/main/java/org/broad/igv/util/encode/EncodeTableModel.java b/src/main/java/org/broad/igv/encode/EncodeTableModel.java similarity index 81% rename from src/main/java/org/broad/igv/util/encode/EncodeTableModel.java rename to src/main/java/org/broad/igv/encode/EncodeTableModel.java index 9b67cb69e5..4c8fc15a92 100644 --- a/src/main/java/org/broad/igv/util/encode/EncodeTableModel.java +++ b/src/main/java/org/broad/igv/encode/EncodeTableModel.java @@ -23,41 +23,16 @@ * THE SOFTWARE. */ -package org.broad.igv.util.encode; +package org.broad.igv.encode; -import javax.swing.*; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; import javax.swing.table.TableRowSorter; import javax.swing.table.TableStringConverter; import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashSet; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** - * //wgEncodeBroadHistoneGm12878H3k4me1StdSig.bigWig - * // size=346M; - * // dateSubmitted=2009-01-05; - * // dataType=ChipSeq; - * // cell=GM12878; - * // antibody=H3K4me1; - * // control=std; - * // expId=33; - * // setType=exp; - * // controlId=GM12878/Input/std; - * // subId=2804; - * // dataVersion=ENCODE Jan 2011 Freeze; - * // dateResubmitted=2010-11-05; - * // grant=Bernstein; - * // lab=Broad; - * // view=Signal; - * // type=bigWig; - * // dccAccession=wgEncodeEH000033; - * // origAssembly=hg18 - * * @author jrobinso * Date: 10/31/13 * Time: 10:09 PM @@ -68,7 +43,7 @@ public class EncodeTableModel extends AbstractTableModel { private List records; private final TableRowSorter sorter; - public EncodeTableModel(String [] headings, List records) { + public EncodeTableModel(List headings, List records) { this.records = records; @@ -80,11 +55,10 @@ public EncodeTableModel(String [] headings, List records) { tmp.add(heading); } } - //tmp.add("path"); - columnHeadings = tmp.toArray(new String[tmp.size()]); + columnHeadings = tmp.toArray(new String[tmp.size()]); - sorter = new TableRowSorter(this); + sorter = new TableRowSorter<>(this); sorter.setStringConverter(new TableStringConverter() { @Override @@ -149,6 +123,8 @@ public void setValueAt(Object value, int row, int col) { fireTableCellUpdated(row, col); } + + public List getRecords() { return records; } diff --git a/src/main/java/org/broad/igv/util/encode/EncodeFileBrowser.java b/src/main/java/org/broad/igv/encode/EncodeTrackChooser.java similarity index 55% rename from src/main/java/org/broad/igv/util/encode/EncodeFileBrowser.java rename to src/main/java/org/broad/igv/encode/EncodeTrackChooser.java index a027851fc7..294ad85456 100644 --- a/src/main/java/org/broad/igv/util/encode/EncodeFileBrowser.java +++ b/src/main/java/org/broad/igv/encode/EncodeTrackChooser.java @@ -27,7 +27,7 @@ * Created by JFormDesigner on Thu Oct 31 22:31:02 EDT 2013 */ -package org.broad.igv.util.encode; +package org.broad.igv.encode; import java.awt.*; import java.awt.event.*; @@ -40,6 +40,7 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import javax.swing.*; import javax.swing.border.*; import javax.swing.event.DocumentEvent; @@ -49,116 +50,213 @@ import com.jidesoft.swing.JideBoxLayout; import org.broad.igv.logging.*; import org.broad.igv.Globals; +import org.broad.igv.prefs.Constants; +import org.broad.igv.prefs.PreferencesManager; import org.broad.igv.ui.IGV; +import org.broad.igv.ui.action.BrowseEncodeAction; +import org.broad.igv.util.FileUtils; import org.broad.igv.util.Pair; +import org.broad.igv.util.ParsingUtils; import org.broad.igv.util.ResourceLocator; /** * @author Jim Robinson */ -public class EncodeFileBrowser extends org.broad.igv.ui.IGVDialog { +public class EncodeTrackChooser extends org.broad.igv.ui.IGVDialog { - private static Logger log = LogManager.getLogger(EncodeFileBrowser.class); + private static Logger log = LogManager.getLogger(EncodeTrackChooser.class); - private static Map instanceMap = Collections.synchronizedMap(new HashMap()); + private static Map instanceMap = Collections.synchronizedMap(new HashMap<>()); private static NumberFormatter numberFormatter = new NumberFormatter(); - private JButton cancelButton; - private JPanel dialogPane; - private JPanel contentPanel; - private JScrollPane scrollPane1; - private JTable table; - private JPanel filterPanel; - private JLabel filterLabel; - private JTextField filterTextField; - private JLabel rowCountLabel; - private JPanel buttonBar; - private JButton okButton; + private static String ENCODE_HOST = "https://www.encodeproject.org"; + private static Set filteredColumns = new HashSet(Arrays.asList("ID", "Assembly", "HREF", "path")); + private static List filteredExtensions = Arrays.asList("tsv", "tsv.gz"); + + private static Map speciesNames = Map.of( + "ce10", "Caenorhabditis elegans", + "ce11", "Caenorhabditis elegans", + "dm3", "Drosophila melanogaster", + "dm6", "Drosophila melanogaster", + "GRCh38", "Homo sapiens", + "hg19", "Homo sapiens", + "mm10", "Mus musculus", + "mm9", "Mus musculus" + ); + + static HashSet ucscSupportedGenomes = new HashSet<>(Arrays.asList("hg19", "mm9")); + static HashSet supportedGenomes = new HashSet<>( + Arrays.asList("ce10", "ce11", "dm3", "dm6", "GRCh38", "hg19", "mm10", "mm9")); + + + + JTable table; + JTextField filterTextField; + JLabel rowCountLabel; EncodeTableModel model; private boolean canceled; - public synchronized static EncodeFileBrowser getInstance(String genomeId) throws IOException { + /** + * Return a new or cached instance of a track chooser for the given genome and type. + * + * @param genomeId + * @param type + * @return + * @throws IOException + */ + public synchronized static EncodeTrackChooser getInstance(String genomeId, BrowseEncodeAction.Type type) throws IOException { - String encodeGenomeId = getEncodeGenomeId(genomeId); - EncodeFileBrowser instance = instanceMap.get(encodeGenomeId); + String encodeGenomeId = getEncodeGenomeID(genomeId); + String key = encodeGenomeId + type.toString(); + EncodeTrackChooser instance = instanceMap.get(key); if (instance == null) { - Pair> records = getEncodeFileRecords(encodeGenomeId); + Pair, List> records = getEncodeFileRecords(encodeGenomeId, type); if (records == null) { return null; } Frame parent = IGV.hasInstance() ? IGV.getInstance().getMainFrame() : null; - instance = new EncodeFileBrowser(parent, new EncodeTableModel(records.getFirst(), records.getSecond())); - instanceMap.put(encodeGenomeId, instance); + final List headings = records.getFirst(); + final List rows = records.getSecond(); + final String title = getDialogTitle(genomeId, type); + instance = new EncodeTrackChooser(parent, new EncodeTableModel(headings, rows), title); + instanceMap.put(key, instance); } return instance; } - static HashSet supportedGenomes = new HashSet(Arrays.asList("hg19", "mm9")); - public static boolean genomeSupported(String genomeId) { - return genomeId != null && supportedGenomes.contains(getEncodeGenomeId(genomeId)); + private static String getDialogTitle(String genomeId, BrowseEncodeAction.Type type) { + + if (type == BrowseEncodeAction.Type.UCSC) { + return "ENCODE data hosted at UCSC (2012)"; + } else { + switch (type) { + case SIGNALS_CHIP: + return "ENCODE CHiP Seq - Signals"; + case SIGNALS_OTHER: + return "ENCODE Non CHiP Data - Signals"; + default: + return "ENCODE"; + } + } } - private static String getEncodeGenomeId(String genomeId) { - if (genomeId.equals("b37") || genomeId.equals("1kg_v37")) return "hg19"; - else return genomeId; + public static boolean genomeSupportedUCSC(String genomeId) { + return genomeId != null && ucscSupportedGenomes.contains(getEncodeGenomeID(genomeId)); } - private static Pair> getEncodeFileRecords(String genomeId) throws IOException { + public static boolean genomeSupported(String genomeId) { + return genomeId != null && supportedGenomes.contains(getEncodeGenomeID(genomeId)); + } - InputStream is = null; - try { + private static String getEncodeGenomeID(String genomeId) { + switch (genomeId) { + case "hg38": + case "hg38_1kg": + return "GRCh38"; + case "b37": + case "1kg_v37": + return "hg19"; + default: + return genomeId; + } + + } + + private static Pair, List> getEncodeFileRecords(String genomeId, BrowseEncodeAction.Type type) throws IOException { - is = EncodeFileBrowser.class.getResourceAsStream("encode." + genomeId + ".txt"); + try (InputStream is = getStreamFor(genomeId, type)) { if (is == null) { return null; } - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + return parseRecords(is, type, genomeId); + } + } - String[] headers = Globals.tabPattern.split(reader.readLine()); + private static InputStream getStreamFor(String genomeId, BrowseEncodeAction.Type type) throws IOException { + if (type == BrowseEncodeAction.Type.UCSC) { + return EncodeTrackChooser.class.getResourceAsStream("encode." + genomeId + ".txt"); + } else { + String root = PreferencesManager.getPreferences().get(Constants.ENCODE_FILELIST_URL) + genomeId + "."; + String url = null; + switch (type) { + case SIGNALS_CHIP: + url = root + "signals.chip.txt"; + break; + case SIGNALS_OTHER: + url = root + "signals.other.txt"; + break; + case OTHER: + url = root + "other.txt"; + break; + } + if (url == null) { + throw new RuntimeException("Unknown encode data collection type: " + type); + } + return ParsingUtils.openInputStream(url); + } + } - List records = new ArrayList(20000); - String nextLine; - while ((nextLine = reader.readLine()) != null) { - if (!nextLine.startsWith("#")) { + private static Pair parseRecords(InputStream is, BrowseEncodeAction.Type type, String genomeId) throws IOException { - String[] tokens = Globals.tabPattern.split(nextLine, -1); - String path = tokens[0]; + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - Map attributes = new HashMap(); - for (int i = 0; i < headers.length; i++) { - String value = i < tokens.length ? tokens[i] : ""; - if (value.length() > 0) { - attributes.put(headers[i], value); - } - } - final EncodeFileRecord record = new EncodeFileRecord(path, attributes); - if(record.hasMetaData()) records.add(record); + String[] headers = Globals.tabPattern.split(reader.readLine()); + + int pathColumn = type == BrowseEncodeAction.Type.UCSC ? 0 : Arrays.asList(headers).indexOf("HREF"); + List records = new ArrayList<>(20000); + String nextLine; + while ((nextLine = reader.readLine()) != null) { + if (!nextLine.startsWith("#")) { + + String[] tokens = Globals.tabPattern.split(nextLine, -1); + String path = type == BrowseEncodeAction.Type.UCSC ? tokens[pathColumn] : ENCODE_HOST + tokens[pathColumn]; + + if(filteredExtensions.stream().anyMatch(e -> path.endsWith(e))) { + continue; + } + + Map attributes = new LinkedHashMap<>(); + for (int i = 0; i < headers.length; i++) { + String value = i < tokens.length ? tokens[i] : ""; + if (value.length() > 0) { + attributes.put(headers[i], shortenField(value, genomeId)); + } } + final EncodeFileRecord record = new EncodeFileRecord(path, attributes); + records.add(record); } - return new Pair(headers, records); - } finally { - if (is != null) is.close(); } + + List filteredHeaders = Arrays.stream(headers).filter(h -> !filteredColumns.contains(h)).collect(Collectors.toList()); + + return new Pair(filteredHeaders, records); + } + + private static String shortenField(String value, String genomeId) { + String species = speciesNames.get(genomeId); + return species == null ? + value : + value.replace("(" + species + ")", "").replace(species, "").trim(); } - private EncodeFileBrowser(Frame owner, EncodeTableModel model) { + private EncodeTrackChooser(Frame owner, EncodeTableModel model, String title) { super(owner); + setTitle(title); this.model = model; setModal(true); - initComponents(); + initComponents(owner); init(model); } private void init(final EncodeTableModel model) { setModal(true); - setTitle("Encode Production Data"); table.setAutoCreateRowSorter(true); table.setModel(model); @@ -263,14 +361,14 @@ public List getSelectedRecords() throws IOException { private class RegexFilter extends RowFilter { - List> matchers; + List> matchers; RegexFilter(String text) { if (text == null) { throw new IllegalArgumentException("Pattern must be non-null"); } - matchers = new ArrayList>(); + matchers = new ArrayList>(); String[] tokens = Globals.whitespacePattern.split(text); for (String t : tokens) { // If token contains an = sign apply to specified column only @@ -336,95 +434,83 @@ public boolean include(Entry value) { } - private void initComponents() { + private void initComponents(Frame owner) { - dialogPane = new JPanel(); - contentPanel = new JPanel(); - scrollPane1 = new JScrollPane(); - table = new JTable(); - filterPanel = new JPanel(); - filterLabel = new JLabel(); - filterTextField = new JTextField(); - rowCountLabel = new JLabel(); - buttonBar = new JPanel(); - okButton = new JButton(); - cancelButton = new JButton(); - - getRootPane().setDefaultButton(okButton); - - final String filterToolTip = "Enter multiple filter strings separated by commas. e.g. GM12878, ChipSeq"; - filterLabel.setToolTipText(filterToolTip); - filterTextField.setToolTipText(filterToolTip); + // All this to have tool tip text! + table = new JTable() { + @Override + public String getToolTipText(MouseEvent e) { + java.awt.Point p = e.getPoint(); + int rowIndex = rowAtPoint(p); + int colIndex = columnAtPoint(p); + int realColumnIndex = convertColumnIndexToModel(colIndex); + if (realColumnIndex > 0) { + return getModel().getValueAt(rowIndex, realColumnIndex).toString(); + } + return null; + } + }; - //======== this ======== + //======== outer content pane ======== Container contentPane = getContentPane(); contentPane.setLayout(new BorderLayout()); //======== dialogPane ======== - + JPanel dialogPane = new JPanel(); dialogPane.setBorder(new EmptyBorder(12, 12, 12, 12)); dialogPane.setLayout(new BorderLayout()); - //======== contentPanel ======== - + //======== main content panel ======== + JPanel contentPanel = new JPanel(); contentPanel.setLayout(new BorderLayout(0, 10)); //======== scrollPane1 ======== - + JScrollPane scrollPane1 = new JScrollPane(); scrollPane1.setViewportView(table); - contentPanel.add(scrollPane1, BorderLayout.CENTER); - //======== panel1 ======== - + //---- Filter panel ---- + JPanel filterPanel = new JPanel(); filterPanel.setLayout(new JideBoxLayout(filterPanel, JideBoxLayout.X_AXIS, 5)); - - //---- label1 ---- - filterLabel.setText("Filter:"); + JLabel filterLabel = new JLabel("Filter:"); + final String filterToolTip = "Enter multiple filter strings separated by commas. e.g. GM12878, ChipSeq"; + filterLabel.setToolTipText(filterToolTip); filterPanel.add(filterLabel, JideBoxLayout.FIX); - - //---- filterTextField ---- + filterTextField = new JTextField(); + filterTextField.setToolTipText(filterToolTip); filterPanel.add(filterTextField, JideBoxLayout.VARY); + rowCountLabel = new JLabel(); rowCountLabel.setHorizontalAlignment(JLabel.RIGHT); - JPanel sillyPanel = new JPanel(); - sillyPanel.setLayout(new JideBoxLayout(sillyPanel, JideBoxLayout.X_AXIS, 0)); - sillyPanel.setPreferredSize(new Dimension(100, 28)); - sillyPanel.add(rowCountLabel, JideBoxLayout.VARY); - - filterPanel.add(sillyPanel, JideBoxLayout.FIX); + JPanel rowCountPanel = new JPanel(); + rowCountPanel.setLayout(new JideBoxLayout(rowCountPanel, JideBoxLayout.X_AXIS, 0)); + rowCountPanel.setPreferredSize(new Dimension(100, 28)); + rowCountPanel.add(rowCountLabel, JideBoxLayout.VARY); + filterPanel.add(rowCountPanel, JideBoxLayout.FIX); contentPanel.add(filterPanel, BorderLayout.NORTH); dialogPane.add(contentPanel, BorderLayout.CENTER); //======== buttonBar ======== - + JPanel buttonBar = new JPanel(); buttonBar.setBorder(new EmptyBorder(12, 0, 0, 0)); buttonBar.setLayout(new GridBagLayout()); ((GridBagLayout) buttonBar.getLayout()).columnWidths = new int[]{0, 85, 80}; ((GridBagLayout) buttonBar.getLayout()).columnWeights = new double[]{1.0, 0.0, 0.0}; //---- okButton ---- - okButton.setText("Load"); - okButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - loadButtonActionPerformed(e); - } - }); + JButton okButton = new JButton("Load"); + getRootPane().setDefaultButton(okButton); + okButton.addActionListener(e -> loadButtonActionPerformed(e)); buttonBar.add(okButton, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 5), 0, 0)); //---- cancelButton ---- - cancelButton.setText("Cancel"); - cancelButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - cancelButtonActionPerformed(e); - } - }); + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(e -> cancelButtonActionPerformed(e)); + buttonBar.add(cancelButton, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); @@ -432,13 +518,21 @@ public void actionPerformed(ActionEvent e) { dialogPane.add(buttonBar, BorderLayout.SOUTH); contentPane.add(dialogPane, BorderLayout.CENTER); - setSize(700, 620); + + Rectangle ownerBounds = owner.getBounds(); + setSize(ownerBounds.width, 620); setLocationRelativeTo(getOwner()); } + /** + * Main function for testing only + * + * @param args + * @throws IOException + */ public static void main(String[] args) throws IOException { - getInstance("hg19").setVisible(true); + getInstance("hg19", BrowseEncodeAction.Type.UCSC).setVisible(true); } } diff --git a/src/main/java/org/broad/igv/util/encode/UCSCEncodeUtils.java b/src/main/java/org/broad/igv/encode/UCSCEncodeUtils.java similarity index 57% rename from src/main/java/org/broad/igv/util/encode/UCSCEncodeUtils.java rename to src/main/java/org/broad/igv/encode/UCSCEncodeUtils.java index e99222b273..a731770d21 100644 --- a/src/main/java/org/broad/igv/util/encode/UCSCEncodeUtils.java +++ b/src/main/java/org/broad/igv/encode/UCSCEncodeUtils.java @@ -23,15 +23,13 @@ * THE SOFTWARE. */ -package org.broad.igv.util.encode; +package org.broad.igv.encode; import org.broad.igv.Globals; import org.broad.igv.util.HttpUtils; import org.broad.igv.util.ParsingUtils; -import java.awt.*; import java.io.*; -import java.net.URL; import java.util.*; import java.util.List; @@ -42,88 +40,30 @@ */ public class UCSCEncodeUtils { - static HashSet labs = new HashSet(); - static HashSet dataTypes = new HashSet(); - static HashSet cells = new HashSet(); - static HashSet antibodies = new HashSet(); - static HashSet fileTypes = new HashSet(); - static HashSet allHeaders = new LinkedHashSet(); + private static Set labs = new HashSet<>(); + private static Set dataTypes = new HashSet<>(); + private static Set cells = new HashSet<>(); + private static Set antibodies = new HashSet<>(); + private static Set fileTypes = new HashSet<>(); + private static Set allHeaders = new LinkedHashSet<>(); private static List rnaChipQualifiers = Arrays.asList("CellTotal", "Longnonpolya", "Longpolya", "NucleolusTotal", "ChromatinTotal", "ChromatinTotal", "NucleoplasmTotal"); public static void main(String[] args) throws IOException { - -// List records = new ArrayList(); -// parseFilesDotTxt(args[0], records); -// PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(args[1]))); -// -// pw.print("path"); -// for (String h : EncodeTableModel.columnHeadings) { -// pw.print("\t"); -// pw.print(h); -// } -// pw.println(); -// -// for (EncodeFileRecord rec : records) { -// pw.print(rec.getPath()); -// for (String h : EncodeTableModel.columnHeadings) { -// pw.print("\t"); -// String value = rec.getAttributeValue(h); -// pw.print(value == null ? "" : value); -// } -// pw.println(); -// } -// pw.close(); - updateEncodeTableFile(args[0], args[1]); } - private static List parseTableFile(String url) throws IOException { - - List records = new ArrayList(20000); - - BufferedReader reader = null; - - try { - reader = ParsingUtils.openBufferedReader(url); - - String[] headers = Globals.tabPattern.split(reader.readLine()); - - String nextLine; - while ((nextLine = reader.readLine()) != null) { - if (!nextLine.startsWith("#")) { - String[] tokens = Globals.tabPattern.split(nextLine, -1); - String path = tokens[0]; - Map attributes = new HashMap(); - for (int i = 0; i < headers.length; i++) { - String value = tokens[i]; - if (value.length() > 0) { - attributes.put(headers[i], value); - } - } - records.add(new EncodeFileRecord(path, attributes)); - } - - } - return records; - } finally { - reader.close(); - } - } static String[] columnHeadings = {"cell", "dataType", "antibody", "view", "replicate", "type", "lab"}; private static void updateEncodeTableFile(String inputFile, String outputFile) throws IOException { - List records = new ArrayList(); - - BufferedReader reader = null; - try { - reader = ParsingUtils.openBufferedReader(inputFile); + List records = new ArrayList<>(); + try (BufferedReader reader = ParsingUtils.openBufferedReader(inputFile)) { String rootPath = reader.readLine(); String hub = null; @@ -131,56 +71,48 @@ private static void updateEncodeTableFile(String inputFile, String outputFile) t while ((nextLine = reader.readLine()) != null) { if (nextLine.startsWith("#")) { - if (nextLine.startsWith("#hub=")) { - hub = nextLine.substring(5); - } + hub = nextLine.startsWith("#hub=") ? nextLine.substring(5) : hub; } else { String dir = nextLine.equals(".") ? rootPath : rootPath + nextLine; String filesDotTxt = dir + "/files.txt"; - try { - if (HttpUtils.getInstance().resourceAvailable(filesDotTxt)) { + if (HttpUtils.getInstance().resourceAvailable(filesDotTxt)) { + try { parseFilesDotTxt(filesDotTxt, records); + } catch (IOException e) { + // e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } - } catch (IOException e) { - // e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } } } - for (String dt : fileTypes) System.out.println(dt); - + fileTypes.forEach(System.out::println); outputRecords(outputFile, records, hub); - } finally { - reader.close(); } } private static void outputRecords(String outputFile, List records, String hub) throws IOException { - PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(outputFile))); - pw.print("path"); - for (String h : columnHeadings) { - pw.print("\t"); - pw.print(h); - } - if (hub != null) { - pw.print("\thub"); - } - pw.println(); - - for (EncodeFileRecord rec : records) { - pw.print(rec.getPath()); + try (PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(outputFile)))) { + StringBuilder sb = new StringBuilder("path"); for (String h : columnHeadings) { - pw.print("\t"); - String value = rec.getAttributeValue(h); - pw.print(value == null ? "" : value); + sb.append("\t").append(h); } if (hub != null) { - pw.print("\t" + hub); + sb.append("\thub"); + } + pw.println(sb.toString()); + + for (EncodeFileRecord rec : records) { + sb = new StringBuilder(rec.getPath()); + for (String h : columnHeadings) { + sb.append("\t").append(Optional.ofNullable(rec.getAttributeValue(h)).orElse("")); + } + if (hub != null) { + sb.append("\t").append(hub); + } + pw.println(sb.toString()); } - pw.println(); } - pw.close(); } static HashSet knownFileTypes = new HashSet(Arrays.asList( diff --git a/src/main/java/org/broad/igv/maf/MultipleAlignmentTrack.java b/src/main/java/org/broad/igv/maf/MultipleAlignmentTrack.java index e9fe48166d..b648d32ef3 100644 --- a/src/main/java/org/broad/igv/maf/MultipleAlignmentTrack.java +++ b/src/main/java/org/broad/igv/maf/MultipleAlignmentTrack.java @@ -153,7 +153,7 @@ public void renderName(Graphics2D g2D, Rectangle trackRectangle, Rectangle visib Rectangle rect = new Rectangle(trackRectangle); g2D.clearRect(rect.x, rect.y, rect.width, rect.height); - Font font = FontManager.getFont(fontSize); + Font font = FontManager.getFont(getFontSize()); g2D.setFont(font); int y = trackRectangle.y; diff --git a/src/main/java/org/broad/igv/prefs/Constants.java b/src/main/java/org/broad/igv/prefs/Constants.java index b8bc1a425f..f87eb6c403 100644 --- a/src/main/java/org/broad/igv/prefs/Constants.java +++ b/src/main/java/org/broad/igv/prefs/Constants.java @@ -304,6 +304,9 @@ private Constants() { public static final String CIRC_VIEW_PORT = "CIRC_VIEW_PORT"; public static final String CIRC_VIEW_HOST = "CIRC_VIEW_HOST"; + // Misc URLS + public static final String ENCODE_FILELIST_URL = "ENCODE_FILELIST_URL"; + /** * List of keys that affect the alignments loaded. This list is used to trigger a reload, if required. diff --git a/src/main/java/org/broad/igv/sam/CoverageTrack.java b/src/main/java/org/broad/igv/sam/CoverageTrack.java index c7bcfae143..b7ebc0e08c 100644 --- a/src/main/java/org/broad/igv/sam/CoverageTrack.java +++ b/src/main/java/org/broad/igv/sam/CoverageTrack.java @@ -147,8 +147,8 @@ public void setColor(Color color) { @Override public String getSample() { - if (sampleId != null) { - return sampleId; // Explicitly set sample ID (e.g. from server load XML) + if (getSampleId() != null) { + return getSampleId(); // Explicitly set sample ID (e.g. from server load XML) } return alignmentTrack == null ? null : alignmentTrack.getSample(); } diff --git a/src/main/java/org/broad/igv/sam/SpliceJunctionTrack.java b/src/main/java/org/broad/igv/sam/SpliceJunctionTrack.java index 2e3d5af972..29640eb0bc 100644 --- a/src/main/java/org/broad/igv/sam/SpliceJunctionTrack.java +++ b/src/main/java/org/broad/igv/sam/SpliceJunctionTrack.java @@ -31,9 +31,6 @@ import org.broad.igv.logging.*; import org.broad.igv.Globals; import org.broad.igv.feature.SpliceJunctionFeature; -import org.broad.igv.prefs.Constants; -import org.broad.igv.prefs.IGVPreferences; -import org.broad.igv.prefs.PreferencesManager; import org.broad.igv.renderer.DataRange; import org.broad.igv.renderer.GraphicUtils; import org.broad.igv.renderer.Renderer; @@ -108,8 +105,8 @@ public void setRenderer(Renderer renderer) { @Override public String getSample() { - if (sampleId != null) { - return sampleId; // Explicitly set sample ID (e.g. from server load XML) + if (getSampleId() != null) { + return getSampleId(); // Explicitly set sample ID (e.g. from server load XML) } return alignmentTrack.getSample(); } diff --git a/src/main/java/org/broad/igv/track/AbstractTrack.java b/src/main/java/org/broad/igv/track/AbstractTrack.java index 8673abb4c1..aa3a4e0afe 100644 --- a/src/main/java/org/broad/igv/track/AbstractTrack.java +++ b/src/main/java/org/broad/igv/track/AbstractTrack.java @@ -63,51 +63,44 @@ */ public abstract class AbstractTrack implements Track { - + private static Logger log = LogManager.getLogger(AbstractTrack.class); public static final Color DEFAULT_COLOR = Color.blue.darker(); public static final DisplayMode DEFAULT_DISPLAY_MODE = DisplayMode.COLLAPSED; public static final int DEFAULT_HEIGHT = -1; public static final int VISIBILITY_WINDOW = -1; public static final boolean DEFAULT_SHOW_FEATURE_NAMES = true; - private static Logger log = LogManager.getLogger(AbstractTrack.class); - - protected String id; + private ResourceLocator resourceLocator; + private String id; + private String sampleId; private String attributeKey; private String name; private String featureInfoURL; private boolean itemRGB = true; private boolean useScore; + protected boolean autoScale; private float viewLimitMin = Float.NaN; // From UCSC track line private float viewLimitMax = Float.NaN; // From UCSC track line - - protected int fontSize; + private int fontSize; private boolean showDataRange = true; - protected String sampleId; - - private ResourceLocator resourceLocator; private int top; protected int minimumHeight = -1; private TrackType trackType = TrackType.OTHER; - private boolean selected = false; private boolean visible = true; - private boolean sortable = true; boolean overlaid; - boolean drawYLine = false; float yLine = 0; + private Map attributes = new HashMap(); private ContinuousColorScale colorScale; - protected boolean autoScale; - String autoscaleGroup; protected Color posColor = null; @@ -857,11 +850,21 @@ public void setDisplayMode(DisplayMode mode) { } - public String getNameValueString(int y) { + public String getTooltipText(int y) { StringBuffer buffer = new StringBuffer(); buffer.append("" + getName()); + Map metadata = resourceLocator.getMetadata(); + if(metadata.size() > 0) { + for(Map.Entry entry : metadata.entrySet()) { + String value = entry.getValue(); + if(value != null && value.length() > 0) { + buffer.append("
" + entry.getKey() + ": " + entry.getValue()); + } + } + } + if (resourceLocator != null && resourceLocator.getPath() != null) { buffer.append("
" + this.resourceLocator.getPath()); } @@ -1180,4 +1183,8 @@ public void unmarshalXML(Element element, Integer version) { } } + public String getSampleId() { + return sampleId; + } + } diff --git a/src/main/java/org/broad/igv/track/CombinedDataTrack.java b/src/main/java/org/broad/igv/track/CombinedDataTrack.java index 87bee53eef..7294fb4e90 100644 --- a/src/main/java/org/broad/igv/track/CombinedDataTrack.java +++ b/src/main/java/org/broad/igv/track/CombinedDataTrack.java @@ -24,8 +24,8 @@ public void marshalXML(Document document, Element element) { super.marshalXML(document, element); - element.setAttribute("track1", ((CombinedDataSource) dataSource).getTrackl().id); - element.setAttribute("track2", ((CombinedDataSource) dataSource).getTrack2().id); + element.setAttribute("track1", ((CombinedDataSource) dataSource).getTrackl().getId()); + element.setAttribute("track2", ((CombinedDataSource) dataSource).getTrack2().getId()); element.setAttribute("op", ((CombinedDataSource) dataSource).getOperation().toString()); diff --git a/src/main/java/org/broad/igv/track/SequenceTrack.java b/src/main/java/org/broad/igv/track/SequenceTrack.java index 55db8d7eb4..edbc437a90 100644 --- a/src/main/java/org/broad/igv/track/SequenceTrack.java +++ b/src/main/java/org/broad/igv/track/SequenceTrack.java @@ -166,7 +166,7 @@ public void renderName(Graphics2D g, Rectangle trackRectangle, Rectangle visible // Use local graphics -- this method corrupts graphics context when exporting to "png" files Graphics2D graphics = (Graphics2D) g.create(); - Font font = FontManager.getFont(fontSize); + Font font = FontManager.getFont(getFontSize()); boolean visible = isVisible(); @@ -421,10 +421,10 @@ public Renderer getRenderer() { } @Override - public String getNameValueString(int y) { + public String getTooltipText(int y) { CodonTable explicitlySelectedTable = CodonTableManager.getInstance().getCurrentCodonTable(); if (explicitlySelectedTable != null) { - String nvs = "" + super.getNameValueString(y); + String nvs = "" + super.getTooltipText(y); nvs += "
Translation Table: "; nvs += explicitlySelectedTable.getDisplayName(); return nvs; diff --git a/src/main/java/org/broad/igv/track/Track.java b/src/main/java/org/broad/igv/track/Track.java index 1f9a2ea22f..553828b516 100644 --- a/src/main/java/org/broad/igv/track/Track.java +++ b/src/main/java/org/broad/igv/track/Track.java @@ -127,7 +127,7 @@ void renderAttributes(Graphics2D graphics, Rectangle trackRectangle, Rectangle v String getDisplayName(); - String getNameValueString(int y); + String getTooltipText(int y); String getSample(); diff --git a/src/main/java/org/broad/igv/ui/IGVMenuBar.java b/src/main/java/org/broad/igv/ui/IGVMenuBar.java index ea8e962778..a0427907d3 100644 --- a/src/main/java/org/broad/igv/ui/IGVMenuBar.java +++ b/src/main/java/org/broad/igv/ui/IGVMenuBar.java @@ -36,12 +36,10 @@ import org.broad.igv.event.IGVEventBus; import org.broad.igv.event.IGVEventObserver; import org.broad.igv.feature.genome.Genome; -import org.broad.igv.feature.genome.GenomeListItem; import org.broad.igv.feature.genome.GenomeManager; import org.broad.igv.feature.genome.GenomeUtils; import org.broad.igv.track.AttributeManager; import org.broad.igv.track.Track; -import org.broad.igv.ui.commandbar.GenomeListManager; import org.broad.igv.ui.commandbar.GenomeSelectionDialog; import org.broad.igv.util.GoogleUtils; import org.broad.igv.oauth.OAuthProvider; @@ -65,12 +63,13 @@ import org.broad.igv.util.BrowserLauncher; import org.broad.igv.util.LongRunningTask; import org.broad.igv.util.blat.BlatClient; -import org.broad.igv.util.encode.EncodeFileBrowser; +import org.broad.igv.encode.EncodeTrackChooser; import javax.swing.*; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; import javax.swing.plaf.basic.BasicBorders; +import javax.swing.plaf.basic.BasicMenuItemUI; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -114,7 +113,9 @@ public class IGVMenuBar extends JMenuBar implements IGVEventObserver { private JMenuItem loadGenomeFromServerMenuItem; private JMenuItem loadTracksFromServerMenuItem; private JMenuItem selectGenomeAnnotationsItem; - private JMenuItem encodeMenuItem; + private JMenuItem encodeUCSCMenuItem; + + private List encodeMenuItems = new ArrayList<>(); private JMenuItem reloadSessionItem; @@ -189,7 +190,7 @@ private List createMenus() { // by loading a protected Google resource try { googleMenu = createGoogleMenu(); - if(googleMenu != null) { + if (googleMenu != null) { boolean enabled = PreferencesManager.getPreferences().getAsBoolean(ENABLE_GOOGLE_MENU); enableGoogleMenu(enabled); menus.add(googleMenu); @@ -206,7 +207,6 @@ private List createMenus() { LongRunningTask.submit(this::updateAWSMenu); - menus.add(createHelpMenu()); // Experimental -- remove for production release @@ -277,7 +277,7 @@ public void enableExtrasMenu() { JMenu createFileMenu() { Genome genome = GenomeManager.getInstance().getCurrentGenome(); - String genomeId = genome == null ? null : genome.getId(); + String genomeId = genome == null ? null : genome.getId(); List menuItems = new ArrayList(); MenuAction menuAction = null; @@ -296,31 +296,14 @@ JMenu createFileMenu() { menuAction = new LoadFromServerAction("Load From Server...", KeyEvent.VK_S, igv); menuAction.setToolTipText(UIConstants.LOAD_SERVER_DATA_TOOLTIP); loadTracksFromServerMenuItem = MenuAndToolbarUtils.createMenuItem(menuAction); - // loadTracksFromServerMenuItem.setVisible(genomeId != null && LoadFromServerAction.getNodeURLs(genomeId) != null); menuItems.add(loadTracksFromServerMenuItem); - // Track hubs -- moved to Genomes menu -// menuAction = new LoadFromURLMenuAction(LoadFromURLMenuAction.LOAD_TRACKHUB, KeyEvent.VK_S, igv); -// menuAction.setToolTipText(UIConstants.LOAD_TRACKHUB_TOOLTIP); -// menuItems.add(MenuAndToolbarUtils.createMenuItem(menuAction)); -// -// menuAction = new SelectGenomeAnnotationTracksAction("Select Hub Tracks...", igv); -// selectGenomeAnnotationsItem = MenuAndToolbarUtils.createMenuItem(menuAction); -// selectGenomeAnnotationsItem.setVisible(genome != null && genome.getHub() != null); -// menuItems.add(selectGenomeAnnotationsItem); -// -// menuAction = new LoadFromURLMenuAction(LoadFromURLMenuAction.LOAD_FROM_HTSGET, 0, igv); -// menuAction.setToolTipText(UIConstants.LOAD_HTSGET_TOOLTOP); -// menuItems.add(MenuAndToolbarUtils.createMenuItem(menuAction)); - if (PreferencesManager.getPreferences().getAsBoolean(DB_ENABLED)) { menuAction = new LoadFromDatabaseAction("Load from Database...", 0, igv); menuItems.add(MenuAndToolbarUtils.createMenuItem(menuAction)); } - encodeMenuItem = MenuAndToolbarUtils.createMenuItem(new BrowseEncodeAction("Load from ENCODE (2012)...", KeyEvent.VK_E, igv)); - encodeMenuItem.setVisible(EncodeFileBrowser.genomeSupported(genomeId)); - menuItems.add(encodeMenuItem); + addEncodeItems(menuItems, genomeId); menuItems.add(new JSeparator()); menuAction = new ReloadTracksMenuAction("Reload Tracks", -1, igv); @@ -429,6 +412,40 @@ public void actionPerformed(ActionEvent e) { return fileMenu; } + private void addEncodeItems(List menuItems, String genomeId) { + + JSeparator separator = new JSeparator(); + menuItems.add(separator); + + JLabel encodeLabel = new JLabel(" ENCODE"); + encodeLabel.setFont(encodeLabel.getFont().deriveFont(Font.BOLD)); + menuItems.add(encodeLabel); + + // Post 2012 ENCODE menu + JMenuItem chipItem = new JMenuItem(); + chipItem.setAction(new BrowseEncodeAction("CHiP - Signals", 0, BrowseEncodeAction.Type.SIGNALS_CHIP, igv)); + encodeMenuItems.add(chipItem); + + JMenuItem otherSignalsItem = new JMenuItem(); + otherSignalsItem.setAction(new BrowseEncodeAction("Other - Signals", 0, BrowseEncodeAction.Type.SIGNALS_OTHER, igv)); + encodeMenuItems.add(otherSignalsItem); + + JMenuItem otherItem = new JMenuItem(); + otherItem.setAction(new BrowseEncodeAction("Other (peaks, calls, ...)", 0, BrowseEncodeAction.Type.OTHER, igv)); + encodeMenuItems.add(otherItem); + + for(JComponent item : encodeMenuItems) { + menuItems.add(item); + item.setVisible(EncodeTrackChooser.genomeSupported(genomeId)); + } + + // UCSC hosted ENCODE menu. + encodeUCSCMenuItem = MenuAndToolbarUtils.createMenuItem( + new BrowseEncodeAction("ENCODE (2012)...", KeyEvent.VK_E, BrowseEncodeAction.Type.UCSC, igv)); + encodeUCSCMenuItem.setVisible(EncodeTrackChooser.genomeSupportedUCSC(genomeId)); + menuItems.add(encodeUCSCMenuItem); + } + private JMenu createGenomesMenu() { JMenu menu = new JMenu("Genomes"); @@ -1052,7 +1069,7 @@ public void menuCanceled(MenuEvent e) { private JMenu createGoogleMenu() { final OAuthProvider googleProvider = OAuthUtils.getInstance().getGoogleProvider(); - if(googleProvider == null) { + if (googleProvider == null) { log.error("Error creating google oauth provider"); return null; } @@ -1121,17 +1138,11 @@ public void menuCanceled(MenuEvent e) { * @throws IOException */ public void enableGoogleMenu(boolean enable) throws IOException { - if(googleMenu != null) { + if (googleMenu != null) { googleMenu.setVisible(enable); } } -// public void enableRemoveGenomes() { -// if (removeImportedGenomeAction != null) { -// removeImportedGenomeAction.setEnabled(true); -// } -// } - public void resetSessionActions() { if (filterTracksAction != null) { filterTracksAction.resetTrackFilter(); @@ -1169,10 +1180,6 @@ public boolean isFilterShowAllTracks() { return false; } - public JMenu getViewMenu() { - return viewMenu; - } - final public void doExitApplication() { try { @@ -1201,7 +1208,12 @@ public void receiveEvent(final IGVEvent event) { if (event instanceof GenomeChangeEvent) { UIUtilities.invokeOnEventThread(() -> { final Genome genome = ((GenomeChangeEvent) event).genome(); - encodeMenuItem.setVisible(EncodeFileBrowser.genomeSupported(genome.getId())); + final String genomeId = genome.getId(); + encodeUCSCMenuItem.setVisible(EncodeTrackChooser.genomeSupportedUCSC(genomeId)); + for(JComponent item : encodeMenuItems) { + item.setVisible(EncodeTrackChooser.genomeSupported(genomeId)); + } + }); } } @@ -1278,5 +1290,15 @@ private void exportTrackNames(final Collection selectedTracks) { } } +} + +class Foo extends BasicMenuItemUI { + + + public Foo() { + this.disabledForeground = Color.black; + } + + } diff --git a/src/main/java/org/broad/igv/ui/action/BrowseEncodeAction.java b/src/main/java/org/broad/igv/ui/action/BrowseEncodeAction.java index 01f1225f3f..c5eb6c64dc 100644 --- a/src/main/java/org/broad/igv/ui/action/BrowseEncodeAction.java +++ b/src/main/java/org/broad/igv/ui/action/BrowseEncodeAction.java @@ -30,18 +30,19 @@ import org.broad.igv.feature.genome.Genome; import org.broad.igv.track.AttributeManager; import org.broad.igv.ui.IGV; +import org.broad.igv.ui.WaitCursorManager; import org.broad.igv.ui.util.MessageUtils; import org.broad.igv.util.ResourceLocator; -import org.broad.igv.util.encode.EncodeFileBrowser; -import org.broad.igv.util.encode.EncodeFileRecord; +import org.broad.igv.encode.EncodeTrackChooser; +import org.broad.igv.encode.EncodeFileRecord; +import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; +import java.util.*; import java.util.List; -import java.util.Map; +import java.util.concurrent.ExecutionException; /** * @author jrobinso @@ -50,6 +51,14 @@ */ public class BrowseEncodeAction extends MenuAction { + + public enum Type { + UCSC, + SIGNALS_CHIP, + SIGNALS_OTHER, + OTHER + } + private static Logger log = LogManager.getLogger(BrowseEncodeAction.class); private static Map colors; @@ -66,11 +75,16 @@ public class BrowseEncodeAction extends MenuAction { colors.put("H3K9ME1", new Color(100, 0, 0)); } + static Set sampleInfoAttributes = new HashSet<>(Arrays.asList( + "dataType", "cell", "antibody", "lab", "Biosample", "AssayType", "Target")); + + private final Type type; IGV igv; - public BrowseEncodeAction(String label, int mnemonic, IGV igv) { + public BrowseEncodeAction(String label, int mnemonic, Type type, IGV igv) { super(label, null, mnemonic); + this.type = type; this.igv = igv; } @@ -78,46 +92,66 @@ public BrowseEncodeAction(String label, int mnemonic, IGV igv) { @Override public void actionPerformed(ActionEvent event) { - String[] visibleAttributes = {"dataType", "cell", "antibody", "lab"}; - try { - Genome genome = GenomeManager.getInstance().getCurrentGenome(); - EncodeFileBrowser browser = EncodeFileBrowser.getInstance(genome.getId()); + Genome genome = GenomeManager.getInstance().getCurrentGenome(); - if (browser == null) { - MessageUtils.showMessage("Encode data is not available for " + genome.getDisplayName() + " through IGV."); - return; + final WaitCursorManager.CursorToken token = WaitCursorManager.showWaitCursor(); + SwingWorker worker = new SwingWorker() { + @Override + protected EncodeTrackChooser doInBackground() throws Exception { + return EncodeTrackChooser.getInstance(genome.getId(), BrowseEncodeAction.this.type); } - browser.setVisible(true); - if (browser.isCanceled()) return; + @Override + protected void done() { + WaitCursorManager.removeWaitCursor(token); + try { + EncodeTrackChooser chooser = get(); + if (chooser == null) { + MessageUtils.showMessage("Encode data is not available for " + genome.getDisplayName() + " through IGV."); + return; + } - java.util.List records = browser.getSelectedRecords(); - if (records.size() > 0) { - List locators = new ArrayList(records.size()); - for (EncodeFileRecord record : records) { - ResourceLocator rl = new ResourceLocator(record.getPath()); - rl.setName(record.getTrackName()); + chooser.setVisible(true); + if (chooser.isCanceled()) return; - final String antibody = record.getAttributeValue("antibody"); - if (antibody != null) { - rl.setColor(colors.get(antibody.toUpperCase())); - } + java.util.List records = chooser.getSelectedRecords(); + if (records.size() > 0) { + List locators = new ArrayList<>(records.size()); + for (EncodeFileRecord record : records) { - for (String name : visibleAttributes) { - String value = record.getAttributeValue(name); - if (value != null) { - AttributeManager.getInstance().addAttribute(rl.getName(), name, value); + ResourceLocator rl = new ResourceLocator(record.getPath()); + rl.setName(record.getTrackName()); + + Map attributes = record.getAttributes(); + + String antibody = attributes.containsKey("antibody") ? attributes.get("antibody") : attributes.get("Target"); + if (antibody != null) { + rl.setColor(colors.get(antibody.toUpperCase())); + } + + for (Map.Entry entry : attributes.entrySet()) { + String value = entry.getValue(); + if (value != null && value.length() > 0 && sampleInfoAttributes.contains(entry.getKey())) { + AttributeManager.getInstance().addAttribute(rl.getName(), entry.getKey(), value); + } + } + + rl.setMetadata(attributes); + + locators.add(rl); } + igv.loadTracks(locators); } - locators.add(rl); + } catch (Exception e) { + log.error("Error opening Encode browser", e); + throw new RuntimeException(e); } - igv.loadTracks(locators); } + }; + + worker.execute(); - } catch (IOException e) { - log.error("Error opening Encode browser", e); - } } } diff --git a/src/main/java/org/broad/igv/ui/action/UCSCGenArkAction.java b/src/main/java/org/broad/igv/ui/action/UCSCGenArkAction.java index 785d23a307..bdb06b20f9 100644 --- a/src/main/java/org/broad/igv/ui/action/UCSCGenArkAction.java +++ b/src/main/java/org/broad/igv/ui/action/UCSCGenArkAction.java @@ -26,26 +26,17 @@ package org.broad.igv.ui.action; import org.broad.igv.Globals; -import org.broad.igv.feature.genome.Genome; -import org.broad.igv.feature.genome.GenomeListItem; import org.broad.igv.feature.genome.GenomeManager; import org.broad.igv.feature.genome.load.HubGenomeLoader; import org.broad.igv.logging.LogManager; import org.broad.igv.logging.Logger; -import org.broad.igv.track.AttributeManager; import org.broad.igv.ui.IGV; -import org.broad.igv.ui.commandbar.GenomeListManager; import org.broad.igv.ui.table.SearchableTableDialog; import org.broad.igv.ui.table.SearchableTableModel; import org.broad.igv.ui.table.SearchableTableRecord; import org.broad.igv.ui.util.MessageUtils; -import org.broad.igv.util.FileUtils; import org.broad.igv.util.ParsingUtils; -import org.broad.igv.util.ResourceLocator; -import org.broad.igv.util.encode.EncodeFileBrowser; -import org.broad.igv.util.encode.EncodeFileRecord; -import java.awt.*; import java.awt.event.ActionEvent; import java.io.BufferedReader; import java.io.IOException; diff --git a/src/main/java/org/broad/igv/ui/panel/TrackNamePanel.java b/src/main/java/org/broad/igv/ui/panel/TrackNamePanel.java index 43c7a123fb..90b76771f9 100644 --- a/src/main/java/org/broad/igv/ui/panel/TrackNamePanel.java +++ b/src/main/java/org/broad/igv/ui/panel/TrackNamePanel.java @@ -312,7 +312,7 @@ public String getTooltipTextForLocation(int x, int y) { Collection tracks = mouseableRegion.getTracks(); if (tracks != null && tracks.size() == 1) { Track track = tracks.iterator().next(); - text = track.getNameValueString(y); + text = track.getTooltipText(y); } else { text = mouseableRegion.getText(); } diff --git a/src/main/java/org/broad/igv/util/ResourceLocator.java b/src/main/java/org/broad/igv/util/ResourceLocator.java index abf3c99fbb..7fb3e4b030 100644 --- a/src/main/java/org/broad/igv/util/ResourceLocator.java +++ b/src/main/java/org/broad/igv/util/ResourceLocator.java @@ -123,7 +123,11 @@ public class ResourceLocator { String sampleId; - private HashMap attributes = new HashMap(); + + /** + * Track metadata. Primarily for generating description and popup text. + */ + private Map metadata; private boolean indexed; private boolean dataURL; @@ -622,6 +626,13 @@ public String getTrixURL() { return trixURL; } + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } public static ResourceLocator fromTrackConfig(TrackConfig trackConfig) { String trackPath = trackConfig.url; diff --git a/src/main/java/org/broad/igv/variant/VariantTrack.java b/src/main/java/org/broad/igv/variant/VariantTrack.java index 1e3633edf1..b6a8e13db5 100644 --- a/src/main/java/org/broad/igv/variant/VariantTrack.java +++ b/src/main/java/org/broad/igv/variant/VariantTrack.java @@ -672,7 +672,7 @@ public void renderName(Graphics2D g2D, Rectangle trackRectangle, Rectangle visib top = trackRectangle.y; Rectangle rect = new Rectangle(trackRectangle); - g2D.setFont(FontManager.getFont(fontSize)); + g2D.setFont(FontManager.getFont(getFontSize())); g2D.setColor(BAND2_COLOR); @@ -806,7 +806,7 @@ private void drawBackground(Graphics2D g2D, Rectangle bandRectangle, Rectangle v Rectangle textRectangle = new Rectangle(bandRectangle); textRectangle.height--; - int bandFontSize = Math.min(fontSize, (int) bandRectangle.getHeight() - 1); + int bandFontSize = Math.min(getFontSize(), (int) bandRectangle.getHeight() - 1); Font font = FontManager.getFont(bandFontSize); Font oldFont = g2D.getFont(); g2D.setFont(font); @@ -915,9 +915,9 @@ public void setColor(Color color) { super.setColor(color); } - public String getNameValueString(int y) { + public String getTooltipText(int y) { if (y < top + getVariantsHeight()) { - return super.getNameValueString(y); + return super.getTooltipText(y); } else { String sample = getSampleAtPosition(y); return sample; diff --git a/src/main/resources/org/broad/igv/util/encode/encode.hg18.txt b/src/main/resources/org/broad/igv/encode/encode.hg18.txt similarity index 100% rename from src/main/resources/org/broad/igv/util/encode/encode.hg18.txt rename to src/main/resources/org/broad/igv/encode/encode.hg18.txt diff --git a/src/main/resources/org/broad/igv/util/encode/encode.hg19.txt b/src/main/resources/org/broad/igv/encode/encode.hg19.txt similarity index 100% rename from src/main/resources/org/broad/igv/util/encode/encode.hg19.txt rename to src/main/resources/org/broad/igv/encode/encode.hg19.txt diff --git a/src/main/resources/org/broad/igv/util/encode/encode.mm9.txt b/src/main/resources/org/broad/igv/encode/encode.mm9.txt similarity index 100% rename from src/main/resources/org/broad/igv/util/encode/encode.mm9.txt rename to src/main/resources/org/broad/igv/encode/encode.mm9.txt diff --git a/src/main/resources/org/broad/igv/prefs/preferences.tab b/src/main/resources/org/broad/igv/prefs/preferences.tab index 9d7944d8b2..4ca38fe9e9 100644 --- a/src/main/resources/org/broad/igv/prefs/preferences.tab +++ b/src/main/resources/org/broad/igv/prefs/preferences.tab @@ -294,6 +294,8 @@ CIRC_VIEW_PORT CircView port integer 60152 #Hidden +ENCODE_FILELIST_URL https://s3.amazonaws.com/igv.org.app/encode/ + PROVISIONING_URL_DEFAULT https://igv.org/services/desktop_google SAM.SHOW_JUNCTION_FLANKINGREGIONS FALSE SAM.JUNCTION_MIN_FLANKING_WIDTH 0