# download
git clone http://source.jalview.org/git/jalview.git
# compile
-cd jalview
+cd ./jalview
gradle shadowJar
# run
java -jar build/libs/jalview-all-*-j11.jar
# and/or create launcher
gradle getdown
# use launcher
-cd getdown/files
+cd ./build/getdown/files/11
java -jar getdown-launcher.jar . jalview
```
## New Features
- <!-- JAL-4036 --> Migrated Uniprot Free Text Search to latest Uniprot search API
+- <!-- JAL-4034 --> Improved Structure Chooser's 3D-Beacons search button design and visual delay indicators
+- <!-- JAL-4034 --> 3D beacons Fetch Uniprot References confirmation dialog is only shown when number of sequences exceeds a threshold
+- <!-- -->
+
--- /dev/null
+Jalview 2.11.2.4 is the fourth patch release in the 2.11.2 series. It includes a new client for the latest Uniprot Search API (released June 2022), updated build documentation and improved user experience when discovering models and experimental structures from 3D-Beacons.
+
label.standard_databases = Standard Databases
label.fetch_embl_uniprot = Fetch from EMBL/EMBLCDS or Uniprot/PDB and any selected DAS sources
label.fetch_uniprot_references = Fetch Uniprot references
-label.search_3dbeacons = 3D-Beacons Search
+label.search_3dbeacons = Search 3D-Beacons
label.find_models_from_3dbeacons = Search 3D-Beacons for 3D structures and models
label.3dbeacons = 3D-Beacons
label.fetch_references_for = Fetch database references for {0} sequences ?
-label.fetch_references_for_3dbeacons = 3D Beacons needs Uniprot References. Fetch database references for {0} sequences ?
+label.fetch_references_for_3dbeacons = 3D Beacons needs to fetch Uniprot References for {0} sequences. Do you want to continue ?
label.reset_min_max_colours_to_defaults = Reset min and max colours to defaults from user preferences.
label.align_structures_using_linked_alignment_views = Superpose structures using {0} selected alignment view(s)
label.threshold_feature_display_by_score = Threshold the feature display by score.
package jalview.gui;
import java.awt.Component;
+import java.awt.Dialog.ModalityType;
import java.awt.HeadlessException;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Executors;
import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JInternalFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
+import javax.swing.UIManager;
import jalview.util.Platform;
import jalview.util.dialogrunner.DialogRunnerI;
public void showDialog(String message, String title, int optionType,
int messageType, Icon icon, Object[] options, Object initialValue)
{
+ showDialog(message, title, optionType, messageType, icon, options,
+ initialValue, true);
+ }
+ public void showDialog(String message, String title, int optionType,
+ int messageType, Icon icon, Object[] options, Object initialValue,
+ boolean modal)
+ {
if (!isInteractiveMode())
{
handleResponse(getMockResponse());
ourOptions = Arrays.asList(options);
- int response = JOptionPane.showOptionDialog(parentComponent, message,
- title, optionType, messageType, icon, options, initialValue);
-
- /*
- * In Java, the response is returned to this thread and handled here;
- * (for Javascript, see propertyChange)
- */
- if (!Platform.isJS())
- /**
- * Java only
- *
- * @j2sIgnore
- */
+ if (modal)
{
- handleResponse(response);
+ // use a JOptionPane as usual
+ int response = JOptionPane.showOptionDialog(parentComponent, message,
+ title, optionType, messageType, icon, options, initialValue);
+
+ /*
+ * In Java, the response is returned to this thread and handled here;
+ * (for Javascript, see propertyChange)
+ */
+ if (!Platform.isJS())
+ /**
+ * Java only
+ *
+ * @j2sIgnore
+ */
+ {
+ handleResponse(response);
+ }
+ }
+ else
+ {
+ /*
+ * This is java similar to the swingjs handling, with the callbacks
+ * attached to the button press of the dialog. This means we can use
+ * a non-modal JDialog for the confirmation without blocking the GUI.
+ */
+ JOptionPane joptionpane = new JOptionPane();
+ // Make button options
+ int[] buttonActions = { JvOptionPane.YES_OPTION,
+ JvOptionPane.NO_OPTION, JvOptionPane.CANCEL_OPTION };
+
+ // we need the strings to make the buttons with actionEventListener
+ if (options == null)
+ {
+ ArrayList<String> options_default = new ArrayList<>();
+ options_default
+ .add(UIManager.getString("OptionPane.yesButtonText"));
+ if (optionType == JvOptionPane.YES_NO_OPTION
+ || optionType == JvOptionPane.YES_NO_CANCEL_OPTION)
+ {
+ options_default
+ .add(UIManager.getString("OptionPane.noButtonText"));
+ }
+ if (optionType == JvOptionPane.YES_NO_CANCEL_OPTION)
+ {
+ options_default
+ .add(UIManager.getString("OptionPane.cancelButtonText"));
+ }
+ options = options_default.toArray();
+ }
+
+ ArrayList<JButton> options_btns = new ArrayList<>();
+ Object initialValue_btn = null;
+ if (!Platform.isJS()) // JalviewJS already uses callback, don't need to add them here
+ {
+ for (int i = 0; i < options.length && i < 3; i++)
+ {
+ Object o = options[i];
+ int buttonAction = buttonActions[i];
+ Runnable action = callbacks.get(buttonAction);
+ JButton jb = new JButton();
+ jb.setText((String) o);
+ jb.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ joptionpane.setValue(buttonAction);
+ if (action != null)
+ Executors.defaultThreadFactory().newThread(action).start();
+ // joptionpane.transferFocusBackward();
+ joptionpane.transferFocusBackward();
+ joptionpane.setVisible(false);
+ // put focus and raise parent window if possible, unless cancel
+ // button pressed
+ boolean raiseParent = (parentComponent != null);
+ if (buttonAction == JvOptionPane.CANCEL_OPTION)
+ raiseParent = false;
+ if (optionType == JvOptionPane.YES_NO_OPTION
+ && buttonAction == JvOptionPane.NO_OPTION)
+ raiseParent = false;
+ if (raiseParent)
+ {
+ parentComponent.requestFocus();
+ if (parentComponent instanceof JInternalFrame)
+ {
+ JInternalFrame jif = (JInternalFrame) parentComponent;
+ jif.show();
+ jif.moveToFront();
+ jif.grabFocus();
+ }
+ else if (parentComponent instanceof Window)
+ {
+ Window w = (Window) parentComponent;
+ w.toFront();
+ w.requestFocus();
+ }
+ }
+ joptionpane.setVisible(false);
+ }
+ });
+ options_btns.add(jb);
+ if (o.equals(initialValue))
+ initialValue_btn = jb;
+ }
+ }
+ joptionpane.setMessage(message);
+ joptionpane.setMessageType(messageType);
+ joptionpane.setOptionType(optionType);
+ joptionpane.setIcon(icon);
+ joptionpane.setOptions(
+ Platform.isJS() ? options : options_btns.toArray());
+ joptionpane.setInitialValue(
+ Platform.isJS() ? initialValue : initialValue_btn);
+
+ JDialog dialog = joptionpane.createDialog(parentComponent, title);
+ dialog.setModalityType(modal ? ModalityType.APPLICATION_MODAL
+ : ModalityType.MODELESS);
+ dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+ dialog.setVisible(true);
}
}
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
-import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
+import jalview.bin.Console;
import jalview.bin.Jalview;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
{
private static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
+ /**
+ * warn user if need to fetch more than this many uniprot records at once
+ */
+ private static final int THRESHOLD_WARN_UNIPROT_FETCH_NEEDED = 20;
+
private SequenceI selectedSequence;
private SequenceI[] selectedSequences;
Executors.defaultThreadFactory().newThread(new Runnable()
{
+ @Override
public void run()
{
populateSeqsWithoutSourceDBRef();
progressBar.setProgressBar(
MessageManager.getString("status.searching_3d_beacons"),
progressId);
+ btn_queryTDB.setEnabled(false);
// TODO: warn if no accessions discovered
populateSeqsWithoutSourceDBRef();
// redo initial discovery - this time with 3d beacons
btn_queryTDB.setToolTipText(MessageManager.getString(
"status.no_structures_discovered_from_3d_beacons"));
btn_queryTDB.setEnabled(false);
+ pnl_queryTDB.setVisible(false);
}
else
{
cmb_filterOption.setSelectedIndex(0); // select 'best'
btn_queryTDB.setVisible(false);
+ pnl_queryTDB.setVisible(false);
progressBar.setProgressBar(null, progressId);
}
mainFrame.setEnabled(true);
@Override
public void run()
{
+ btn_queryTDB.setEnabled(false);
populateSeqsWithoutSourceDBRef();
final int y = seqsWithoutSourceDBRef.size();
{ new jalview.ws.dbsources.Uniprot() }, null, false);
dbRefFetcher.addListener(afterDbRefFetch);
// ideally this would also gracefully run with callbacks
+
dbRefFetcher.fetchDBRefs(true);
}
else
};
final Runnable revertview = new Runnable()
{
+ @Override
public void run()
{
if (lastSelected != null)
}
};
};
- if (ignoreGui)
+ int threshold = Cache.getDefault("UNIPROT_AUTOFETCH_THRESHOLD",
+ THRESHOLD_WARN_UNIPROT_FETCH_NEEDED);
+ Console.debug("Using Uniprot fetch threshold of " + threshold);
+ if (ignoreGui || seqsWithoutSourceDBRef.size() < threshold)
{
Executors.defaultThreadFactory().newThread(discoverCanonicalDBrefs)
.start();
}
// need cancel and no to result in the discoverPDB action - mocked is
// 'cancel' TODO: mock should be OK
- JvOptionPane.newOptionDialog(this)
+
+ StructureChooser thisSC = this;
+ JvOptionPane.newOptionDialog(thisSC.getFrame())
.setResponseHandler(JvOptionPane.OK_OPTION,
discoverCanonicalDBrefs)
.setResponseHandler(JvOptionPane.CANCEL_OPTION, revertview)
null, new Object[]
{ MessageManager.getString("action.ok"),
MessageManager.getString("action.cancel") },
- MessageManager.getString("action.ok"));
+ MessageManager.getString("action.ok"), false);
}
/**
if (canQueryTDB && notQueriedTDBYet)
{
btn_queryTDB.setVisible(true);
+ pnl_queryTDB.setVisible(true);
}
if (cachedPDBExist)
popup.add(viewUrl);
SwingUtilities.invokeLater(new Runnable()
{
+ @Override
public void run()
{
popup.show(getResultTable(), x, y);
{
if (selectedSequences != null)
{
+ lbl_loading.setVisible(true);
Thread refreshThread = new Thread(new Runnable()
{
@Override
filterResultSet(
((FilterOption) cmb_filterOption.getSelectedItem())
.getValue());
+ lbl_loading.setVisible(false);
}
});
refreshThread.start();
package jalview.jbgui;
-import jalview.datamodel.SequenceI;
-import jalview.fts.api.FTSDataColumnI;
-import jalview.fts.core.FTSDataColumnPreferences;
-import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
-import jalview.fts.service.pdb.PDBFTSRestClient;
-import jalview.gui.AlignmentPanel;
-import jalview.gui.Desktop;
-import jalview.gui.JvSwingUtils;
-import jalview.gui.StructureViewer;
-import jalview.util.MessageManager;
-
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
+import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
+import javax.swing.SwingConstants;
import javax.swing.Timer;
-import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.InternalFrameEvent;
import javax.swing.table.TableColumn;
+import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.core.FTSDataColumnPreferences;
+import jalview.gui.AlignmentPanel;
+import jalview.gui.Desktop;
+import jalview.gui.JvSwingUtils;
+import jalview.gui.StructureViewer;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
import net.miginfocom.swing.MigLayout;
@SuppressWarnings("serial")
protected JButton btn_pdbFromFile = new JButton();
+ // holder for icon and button
+ protected JPanel pnl_queryTDB;
+
protected JButton btn_queryTDB = new JButton();
protected JCheckBox chk_superpose = new JCheckBox(
});
chk_invertFilter.addItemListener(this);
- btn_queryTDB.setFont(VERDANA_12);
- // btn_queryTDB.setPreferredSize(new Dimension(200,22));
+ btn_queryTDB = new JButton();
+ if (Platform.isMac())
+ {
+ // needed to make icon button have round corners in vaqua
+ btn_queryTDB.putClientProperty("JButton.buttonType", "bevel");
+ }
+ btn_queryTDB.setMargin(new Insets(0, 16, 0, 20));
btn_queryTDB
.setText(MessageManager.getString("label.search_3dbeacons"));
+ btn_queryTDB.setIconTextGap(12);
+ btn_queryTDB.setIcon(tdbImage);
+ btn_queryTDB.setVerticalTextPosition(SwingConstants.CENTER);
+ btn_queryTDB.setHorizontalTextPosition(SwingConstants.TRAILING);
+ btn_queryTDB.setFont(VERDANA_12);
btn_queryTDB.setToolTipText(
MessageManager.getString("label.find_models_from_3dbeacons"));
- btn_queryTDB.setIcon(tdbImage);
+ // btn_queryTDB.setPreferredSize(new Dimension(200, 32));
btn_queryTDB.setVisible(false);
targetView.setVisible(false);
JPanel pnl_main = new JPanel(new BorderLayout());
JPanel pnl_controls = new JPanel();
- pnl_main.add(btn_queryTDB, BorderLayout.NORTH);
+ pnl_queryTDB = new JPanel();
+ pnl_queryTDB.setLayout(new FlowLayout(FlowLayout.CENTER, 4, 4));
+ pnl_queryTDB.setBackground(getBackground());
+ pnl_queryTDB.add(btn_queryTDB);
+
+ pnl_queryTDB.setVisible(false);
+ pnl_main.add(pnl_queryTDB, BorderLayout.NORTH);
pnl_controls.add(cmb_filterOption);
pnl_controls.add(lbl_loading);
pnl_controls.add(chk_invertFilter);
protected abstract void tabRefresh();
protected abstract void validateSelections();
-}
\ No newline at end of file
+
+ public JInternalFrame getFrame()
+ {
+ return mainFrame;
+ }
+}