/*
* Copyright (c) 2007-2013 The Broad Institute, Inc.
* SOFTWARE COPYRIGHT NOTICE
* This software and its documentation are the copyright of the Broad Institute, Inc. All rights are reserved.
*
* This software is supplied without any warranty or guaranteed support whatsoever. The Broad Institute is not responsible for its use, misuse, or functionality.
*
* This software is licensed under the terms of the GNU Lesser General Public License (LGPL),
* Version 2.1 which is available at http://www.opensource.org/licenses/lgpl-2.1.php.
*/
package org.broad.igv.ui.util;
import org.apache.log4j.Logger;
import org.broad.igv.exceptions.DataLoadException;
import org.broad.igv.feature.genome.GenomeManager;
import org.broad.igv.feature.tribble.CodecFactory;
import org.broad.igv.sam.reader.AlignmentIndexer;
import org.broad.igv.sam.reader.FeatureIndex;
import org.broad.igv.tools.IgvTools;
import org.broad.igv.util.ResourceLocator;
import htsjdk.tribble.FeatureCodec;
import htsjdk.tribble.TribbleException;
import htsjdk.tribble.index.Index;
import htsjdk.tribble.index.IndexFactory;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import javax.swing.*;
import javax.swing.border.*;
public class IndexCreatorDialog extends JDialog {
private static Logger log = Logger.getLogger(IndexCreatorDialog.class);
File file;
File idxFile;
IndexWorker worker;
FileType fileType;
String introText;
private enum FileType {
SAM,
TRIBBLE
}
public static IndexCreatorDialog createShowDialog(Frame parent, File baseFile, File newIdxFile, String introText) {
final IndexCreatorDialog dialog = new IndexCreatorDialog(parent, true, baseFile, newIdxFile, introText);
dialog.setLocationRelativeTo(parent);
UIUtilities.invokeAndWaitOnEventThread(new Runnable() {
@Override
public void run() {
dialog.setVisible(true);
}
});
return dialog;
}
/**
* Creates new form IndexCreatorDialog
*/
public IndexCreatorDialog(java.awt.Frame parent, boolean modal, File file, File idxFile, String introText) {
super(parent, modal);
initComponents();
this.introText = introText;
jLabel1.setVisible(false);
this.file = file;
this.idxFile = idxFile;
this.determineFileType(file);
if (this.fileType == null) {
log.error("Cannot determine file type for " + file.getAbsolutePath());
}
String txt = introText;
this.introTextArea.setText(txt);
this.introTextArea.setBorder(BorderFactory.createEmptyBorder());
switch (this.fileType) {
case SAM:
worker = new SamIndexWorker();
break;
case TRIBBLE:
worker = new TribbleIndexWorker();
break;
}
}
private void determineFileType(File file) {
String filename = file.getName();
if (filename.toLowerCase().endsWith(".sam")) {
fileType = FileType.SAM;
} else if (CodecFactory.hasCodec(new ResourceLocator(file.getPath()), null)) {
fileType = FileType.TRIBBLE;
} else {
fileType = null;
}
}
public Object getIndex() {
if (worker == null || !worker.isDone()) {
return null;
} else {
try {
return worker.get();
} catch (Exception ex) {
MessageUtils.showMessage(ex.getMessage());
}
return null;
}
}
private void goButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goButtonActionPerformed
if (worker.isDone() || worker.isCancelled()) {
setVisible(false);
} else {
if (!worker.isStarted) {
goButton.setEnabled(false);
worker.isStarted = true;
worker.execute();
jLabel1.setVisible(true);
//Haven't worked out how to publish progress yet, just going to set it to indeterminate
if (fileType == FileType.TRIBBLE) {
IndexCreatorDialog.this.progressBar.setIndeterminate(true);
jLabel1.setText("Creating index...");
}
}
}
}
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {
if (worker != null && worker.isStarted && !(worker.isDone() || worker.isCancelled())) {
worker.isStarted = false;
worker.cancel(true); // <+ doing this before execution starts will raise an error
}
setVisible(false);
}
public class SamIndexWorker extends IndexWorker<FeatureIndex> {
@Override
protected FeatureIndex doInBackground() throws Exception {
AlignmentIndexer indexer = AlignmentIndexer.getInstance(file, progressBar, this);
return indexer.createSamIndex(idxFile, 16000);
}
}
private class TribbleIndexWorker extends IndexWorker<Index> {
@Override
protected Index doInBackground() throws Exception {
int binSize = IgvTools.LINEAR_BIN_SIZE;
FeatureCodec codec = CodecFactory.getCodec(file.getAbsolutePath(), GenomeManager.getInstance().getCurrentGenome());
if (codec != null) {
try {
Index index = IndexFactory.createLinearIndex(file, codec, binSize);
if (index != null) {
IgvTools.writeTribbleIndex(index, idxFile.getAbsolutePath());
}
return index;
} catch (TribbleException.MalformedFeatureFile e) {
StringBuffer buf = new StringBuffer();
buf.append("<html>Files must be sorted by start position prior to indexing.<br>");
buf.append(e.getMessage());
buf.append("<br><br>Note: igvtools can be used to sort the file, select \"File > Run igvtools...\".");
MessageUtils.showMessage(buf.toString());
}
} else {
throw new DataLoadException("Unknown File Type", file.getAbsolutePath());
}
return null;
}
}
public abstract class IndexWorker<I> extends SwingWorker<I, Void> {
private boolean isStarted = false;
@Override
protected void done() {
setVisible(false);
}
public void setTimeRemaining(long timeInMillis) {
final int timeRemaining = (int) (timeInMillis / (60 * 1000));
UIUtilities.invokeOnEventThread(new Runnable() {
public void run() {
String txt = String.valueOf(timeRemaining) + " minutes";
if (timeRemaining == 1) {
txt = "1 minute";
} else if (timeRemaining < 1) {
txt = " < 1 minute";
}
timeRemainingLabel.setText(txt);
}
});
}
}
/**
* ProgressListener listens to "progress" property
* changes in the SwingWorkers that search and load
* images.
*/
class ProgressListener implements PropertyChangeListener {
// prevent creation without providing a progress bar
private ProgressListener() {
}
ProgressListener(JProgressBar progressBar) {
this.progressBar = progressBar;
this.progressBar.setValue(0);
}
public void propertyChange(PropertyChangeEvent evt) {
String strPropertyName = evt.getPropertyName();
if ("progress".equals(strPropertyName)) {
progressBar.setIndeterminate(false);
int progress = (Integer) evt.getNewValue();
progressBar.setValue(progress);
}
}
private JProgressBar progressBar;
}
/**
* 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")
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
// Generated using JFormDesigner non-commercial license
dialogPane = new JPanel();
contentPanel = new JPanel();
scrollPane1 = new JScrollPane();
introTextArea = new JTextPane();
timeRemainingLabel = new JLabel();
jLabel1 = new JLabel();
progressBar = new JProgressBar();
buttonBar = new JPanel();
goButton = new JButton();
cancelButton = new JButton();
//======== this ========
setResizable(false);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
//======== dialogPane ========
{
dialogPane.setBorder(new EmptyBorder(12, 12, 12, 12));
dialogPane.setLayout(new BorderLayout());
//======== contentPanel ========
{
contentPanel.setLayout(null);
//======== scrollPane1 ========
{
scrollPane1.setViewportView(introTextArea);
}
contentPanel.add(scrollPane1);
scrollPane1.setBounds(0, 0, 465, 260);
contentPanel.add(timeRemainingLabel);
timeRemainingLabel.setBounds(255, 265, 210, 31);
//---- jLabel1 ----
jLabel1.setHorizontalTextPosition(SwingConstants.RIGHT);
contentPanel.add(jLabel1);
jLabel1.setBounds(0, 265, 210, 31);
contentPanel.add(progressBar);
progressBar.setBounds(0, 305, 465, progressBar.getPreferredSize().height);
{ // compute preferred size
Dimension preferredSize = new Dimension();
for(int i = 0; i < contentPanel.getComponentCount(); i++) {
Rectangle bounds = contentPanel.getComponent(i).getBounds();
preferredSize.width = Math.max(bounds.x + bounds.width, preferredSize.width);
preferredSize.height = Math.max(bounds.y + bounds.height, preferredSize.height);
}
Insets insets = contentPanel.getInsets();
preferredSize.width += insets.right;
preferredSize.height += insets.bottom;
contentPanel.setMinimumSize(preferredSize);
contentPanel.setPreferredSize(preferredSize);
}
}
dialogPane.add(contentPanel, BorderLayout.CENTER);
//======== buttonBar ========
{
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};
//---- goButton ----
goButton.setText("Go");
goButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
goButtonActionPerformed(e);
}
});
buttonBar.add(goButton, 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);
}
});
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));
}
dialogPane.add(buttonBar, BorderLayout.SOUTH);
}
contentPane.add(dialogPane, BorderLayout.CENTER);
setSize(500, 415);
setLocationRelativeTo(getOwner());
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
// Generated using JFormDesigner non-commercial license
private JPanel dialogPane;
private JPanel contentPanel;
private JScrollPane scrollPane1;
private JTextPane introTextArea;
private JLabel timeRemainingLabel;
private JLabel jLabel1;
private JProgressBar progressBar;
private JPanel buttonBar;
private JButton goButton;
private JButton cancelButton;
// JFormDesigner - End of variables declaration //GEN-END:variables
}