jalview.ext.android includes code taken from the Android Open Source Project (https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/util).
The Apache 2.0 Licence (http://www.apache.org/licenses/LICENSE-2.0) is acknowledged in the source code.
+ org.stackoverflowusers.file.WindowsShortcuts was downloaded from http://github.com/codebling/WindowsShortcuts via https://stackoverflow.com/questions/309495/windows-shortcut-lnk-parser-in-java
Licensing information for each library is given below:
label.autoadd_secstr = Add secondary structure annotation to alignment
label.autoadd_temp = Add Temperature Factor annotation to alignment
label.structure_viewer = Default structure viewer
+label.double_click_to_browse = Double-click to browse for file
label.chimera_path = Path to Chimera program
label.chimera_path_tip = Jalview will first try any path entered here, else standard installation locations.<br>Double-click to browse for file.
label.invalid_chimera_path = Chimera path not found or not executable
action.export_features=Exportar Características
error.invalid_regex=Expresión regular inválida
label.autoadd_temp=Añadir anotación factor de temperatura al alineamiento
+label.double_click_to_browse = Haga doble clic para buscar fichero
label.chimera_path_tip=Jalview intentará primero las rutas introducidas aquí, Y si no las rutas usuales de instalación
label.structure_chooser=Selector de Estructuras
label.structure_chooser_manual_association=Selector de Estructuras - asociación manual
label.aacon_calculations=cálculos AACon
label.pdb_web-service_error=Error de servicio web PDB
exception.unable_to_detect_internet_connection=Jalview no puede detectar una conexión a Internet
-label.chimera_path=Ruta de acceso a programa Chimera
+label.chimera_path=Ruta de acceso a Chimera
warn.delete_all=<html>Borrar todas las secuencias cerrará la ventana del alineamiento.<br>Confirmar o Cancelar.
label.select_all=Seleccionar Todos
label.alpha_helix=Hélice Alfa
label.chimera_help=Ayuda para Chimera
label.find_tip=Buscar alineamiento, selección o IDs de secuencia para una subsecuencia (sin huecos)
-label.structure_viewer=Visualizador de estructura por defecto
+label.structure_viewer=Visualizador por defecto
label.embbed_biojson=Incrustar BioJSON al exportar HTML
label.transparency_tip=Ajustar la transparencia a "ver a través" los colores de las características.
label.choose_annotations=Escoja anotaciones
this.haveGUI = haveGUI;
// Create the Chimera interface
chimeraManager = new ChimeraManager(this);
- chimSelectionList = new ArrayList<ChimeraStructuralObject>();
+ chimSelectionList = new ArrayList<>();
pathProps = new Properties();
}
ModelType type)
{
// new models
- Map<String, List<ChimeraModel>> newModels = new HashMap<String, List<ChimeraModel>>();
+ Map<String, List<ChimeraModel>> newModels = new HashMap<>();
if (chimObjNames.size() > 0)
{
List<String> names = chimObjNames.iterator().next();
// alDialog.dispose();
// }
// System.out.println("launch align dialog");
- List<ChimeraStructuralObject> chimObjectList = new ArrayList<ChimeraStructuralObject>();
+ List<ChimeraStructuralObject> chimObjectList = new ArrayList<>();
for (ChimeraModel model : chimeraManager.getChimeraModels())
{
if (useChains)
public List<String> getAllChimeraResidueAttributes()
{
- List<String> attributes = new ArrayList<String>();
+ List<String> attributes = new ArrayList<>();
// attributes.addAll(rinManager.getResAttrs());
attributes.addAll(chimeraManager.getAttrList());
return attributes;
// TODO: [Optional] Change priority of Chimera paths
public static List<String> getChimeraPaths()
{
- List<String> pathList = new ArrayList<String>();
+ List<String> pathList = new ArrayList<>();
// if no network is available and the settings have been modified by the
// user, check for a
}
else if (os.startsWith("Windows"))
{
- pathList.add("\\Program Files\\Chimera\\bin\\chimera");
- pathList.add("C:\\Program Files\\Chimera\\bin\\chimera.exe");
+ for (String root : new String[] { "\\Program Files",
+ "C:\\Program Files", "\\Program Files (x86)",
+ "C:\\Program Files (x86)" })
+ {
+ for (String version : new String[] { "1.11", "1.11.1", "1.11.2",
+ "1.12", "1.12.1", "1.12.2", "1.13" })
+ {
+ pathList.add(root + "\\Chimera " + version + "\\bin\\chimera");
+ pathList.add(
+ root + "\\Chimera " + version + "\\bin\\chimera.exe");
+ }
+ }
}
else if (os.startsWith("Mac"))
{
import jalview.io.FileFormatI;
import jalview.io.FileFormats;
import jalview.io.FileLoader;
+import jalview.io.FormatAdapter;
import jalview.io.IdentifyFile;
import jalview.io.JalviewFileChooser;
import jalview.io.JalviewFileView;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
+import org.stackoverflowusers.file.WindowsShortcut;
+
/**
* Jalview Desktop
*
return groovyConsole;
}
+ /**
+ * handles the payload of a drag and drop event.
+ *
+ * TODO refactor to desktop utilities class
+ *
+ * @param files
+ * - Data source strings extracted from the drop event
+ * @param protocols
+ * - protocol for each data source extracted from the drop event
+ * @param evt
+ * - the drop event
+ * @param t
+ * - the payload from the drop event
+ * @throws Exception
+ */
public static void transferFromDropTarget(List<String> files,
List<DataSourceType> protocols, DropTargetDropEvent evt,
Transferable t) throws Exception
{
DataFlavor uriListFlavor = new DataFlavor(
- "text/uri-list;class=java.lang.String");
+ "text/uri-list;class=java.lang.String"), urlFlavour = null;
+ try
+ {
+ urlFlavour = new DataFlavor(
+ "application/x-java-url; class=java.net.URL");
+ } catch (ClassNotFoundException cfe)
+ {
+ Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
+ }
+
+ if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
+ {
+
+ try
+ {
+ java.net.URL url = (URL) t.getTransferData(urlFlavour);
+ // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
+ // means url may be null.
+ if (url != null)
+ {
+ protocols.add(DataSourceType.URL);
+ files.add(url.toString());
+ Cache.log.debug("Drop handled as URL dataflavor "
+ + files.get(files.size() - 1));
+ return;
+ }
+ else
+ {
+ if (Platform.isAMac())
+ {
+ System.err.println(
+ "Please ignore plist error - occurs due to problem with java 8 on OSX");
+ }
+ ;
+ }
+ } catch (Throwable ex)
+ {
+ Cache.log.debug("URL drop handler failed.", ex);
+ }
+ }
if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
{
// Works on Windows and MacOSX
// fallback to text: workaround - on OSX where there's a JVM bug
Cache.log.debug("standard URIListFlavor failed. Trying text");
// try text fallback
- data = (String) t.getTransferData(
- new DataFlavor("text/plain;class=java.lang.String"));
- if (Cache.log.isDebugEnabled())
+ DataFlavor textDf = new DataFlavor(
+ "text/plain;class=java.lang.String");
+ if (t.isDataFlavorSupported(textDf))
{
- Cache.log.debug("fallback returned " + data);
+ data = (String) t.getTransferData(textDf);
}
+
+ Cache.log.debug("Plain text drop content returned "
+ + (data == null ? "Null - failed" : data));
+
}
- while (protocols.size() < files.size())
- {
- Cache.log.debug("Adding missing FILE protocol for "
- + files.get(protocols.size()));
- protocols.add(DataSourceType.FILE);
- }
- for (java.util.StringTokenizer st = new java.util.StringTokenizer(
- data, "\r\n"); st.hasMoreTokens();)
+ if (data != null)
{
- added = true;
- String s = st.nextToken();
- if (s.startsWith("#"))
+ while (protocols.size() < files.size())
{
- // the line is a comment (as per the RFC 2483)
- continue;
- }
- java.net.URI uri = new java.net.URI(s);
- if (uri.getScheme().toLowerCase().startsWith("http"))
- {
- protocols.add(DataSourceType.URL);
- files.add(uri.toString());
+ Cache.log.debug("Adding missing FILE protocol for "
+ + files.get(protocols.size()));
+ protocols.add(DataSourceType.FILE);
}
- else
+ for (java.util.StringTokenizer st = new java.util.StringTokenizer(
+ data, "\r\n"); st.hasMoreTokens();)
{
- // otherwise preserve old behaviour: catch all for file objects
- java.io.File file = new java.io.File(uri);
- protocols.add(DataSourceType.FILE);
- files.add(file.toString());
+ added = true;
+ String s = st.nextToken();
+ if (s.startsWith("#"))
+ {
+ // the line is a comment (as per the RFC 2483)
+ continue;
+ }
+ java.net.URI uri = new java.net.URI(s);
+ if (uri.getScheme().toLowerCase().startsWith("http"))
+ {
+ protocols.add(DataSourceType.URL);
+ files.add(uri.toString());
+ }
+ else
+ {
+ // otherwise preserve old behaviour: catch all for file objects
+ java.io.File file = new java.io.File(uri);
+ protocols.add(DataSourceType.FILE);
+ files.add(file.toString());
+ }
}
}
+
if (Cache.log.isDebugEnabled())
{
if (data == null || !added)
{
- Cache.log.debug(
- "Couldn't resolve drop data. Here are the supported flavors:");
- for (DataFlavor fl : t.getTransferDataFlavors())
+
+ if (t.getTransferDataFlavors() != null
+ && t.getTransferDataFlavors().length > 0)
{
Cache.log.debug(
- "Supported transfer dataflavor: " + fl.toString());
- Object df = t.getTransferData(fl);
- if (df != null)
+ "Couldn't resolve drop data. Here are the supported flavors:");
+ for (DataFlavor fl : t.getTransferDataFlavors())
{
- Cache.log.debug("Retrieves: " + df);
- }
- else
- {
- Cache.log.debug("Retrieved nothing");
+ Cache.log.debug(
+ "Supported transfer dataflavor: " + fl.toString());
+ Object df = t.getTransferData(fl);
+ if (df != null)
+ {
+ Cache.log.debug("Retrieves: " + df);
+ }
+ else
+ {
+ Cache.log.debug("Retrieved nothing");
+ }
}
}
+ else
+ {
+ Cache.log.debug("Couldn't resolve dataflavor for drop: "
+ + t.toString());
+ }
+ }
+ }
+ }
+ if (Platform.isWindows())
+
+ {
+ Cache.log.debug("Scanning dropped content for Windows Link Files");
+
+ // resolve any .lnk files in the file drop
+ for (int f = 0; f < files.size(); f++)
+ {
+ String source = files.get(f).toLowerCase();
+ if (protocols.get(f).equals(DataSourceType.FILE)
+ && (source.endsWith(".lnk") || source.endsWith(".url")
+ || source.endsWith(".site")))
+ {
+ try {
+ File lf = new File(files.get(f));
+ // process link file to get a URL
+ Cache.log.debug("Found potential link file: " + lf);
+ WindowsShortcut wscfile = new WindowsShortcut(lf);
+ String fullname = wscfile.getRealFilename();
+ protocols.set(f, FormatAdapter.checkProtocol(fullname));
+ files.set(f, fullname);
+ Cache.log.debug("Parsed real filename " + fullname
+ + " to extract protocol: " + protocols.get(f));
+ }
+ catch (Exception ex)
+ {
+ Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
+ }
}
}
}
ViewportRanges ranges = av.getRanges();
ranges.setViewportStartAndWidth(startColumn, wrappedWidthInResidues);
+ // we need to call this again to make sure the startColumn +
+ // wrappedWidthInResidues values are used to calculate wrappedVisibleWidths
+ // correctly.
+ calculateWrappedGeometry(canvasWidth, canvasHeight);
+
/*
* draw one width at a time (including any scales or annotation shown),
* until we have run out of either alignment or vertical space available
MessageManager.getString("label.default_browser_unix"));
defaultBrowser.setFont(LABEL_FONT);
defaultBrowser.setText("");
-
+ final String tooltip = JvSwingUtils.wrapTooltip(true,
+ MessageManager.getString("label.double_click_to_browse"));
+ defaultBrowser.setToolTipText(tooltip);
defaultBrowser.addMouseListener(new MouseAdapter()
{
@Override
pathLabel.setFont(new java.awt.Font("SansSerif", 0, 11));
pathLabel.setHorizontalAlignment(SwingConstants.LEFT);
pathLabel.setText(MessageManager.getString("label.chimera_path"));
- final String tooltip = JvSwingUtils.wrapTooltip(true,
- MessageManager.getString("label.chimera_path_tip"));
- pathLabel.setToolTipText(tooltip);
pathLabel.setBounds(new Rectangle(10, ypos, 140, height));
structureTab.add(pathLabel);
chimeraPath.setFont(LABEL_FONT);
chimeraPath.setText("");
+ final String tooltip = JvSwingUtils.wrapTooltip(true,
+ MessageManager.getString("label.chimera_path_tip"));
+ chimeraPath.setToolTipText(tooltip);
chimeraPath.setBounds(new Rectangle(160, ypos, 300, height));
chimeraPath.addMouseListener(new MouseAdapter()
{
startupCheckbox.setSelected(true);
startupFileTextfield.setFont(LABEL_FONT);
startupFileTextfield.setBounds(new Rectangle(172, 310, 330, 20));
+ final String tooltip = JvSwingUtils.wrapTooltip(true,
+ MessageManager.getString("label.double_click_to_browse"));
+ startupFileTextfield.setToolTipText(tooltip);
startupFileTextfield.addMouseListener(new MouseAdapter()
{
@Override
--- /dev/null
+package org.stackoverflowusers.file;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.ParseException;
+
+/**
+ * Represents a Windows shortcut (typically visible to Java only as a '.lnk' file).
+ *
+ * Retrieved 2011-09-23 from http://stackoverflow.com/questions/309495/windows-shortcut-lnk-parser-in-java/672775#672775
+ * Originally called LnkParser
+ *
+ * Written by: (the stack overflow users, obviously!)
+ * Apache Commons VFS dependency removed by crysxd (why were we using that!?) https://github.com/crysxd
+ * Headerified, refactored and commented by Code Bling http://stackoverflow.com/users/675721/code-bling
+ * Network file support added by Stefan Cordes http://stackoverflow.com/users/81330/stefan-cordes
+ * Adapted by Sam Brightman http://stackoverflow.com/users/2492/sam-brightman
+ * Based on information in 'The Windows Shortcut File Format' by Jesse Hager <jessehager@iname.com>
+ * And somewhat based on code from the book 'Swing Hacks: Tips and Tools for Killer GUIs'
+ * by Joshua Marinacci and Chris Adamson
+ * ISBN: 0-596-00907-0
+ * http://www.oreilly.com/catalog/swinghks/
+ */
+public class WindowsShortcut
+{
+ private boolean isDirectory;
+ private boolean isLocal;
+ private String real_file;
+
+ /**
+ * Provides a quick test to see if this could be a valid link !
+ * If you try to instantiate a new WindowShortcut and the link is not valid,
+ * Exceptions may be thrown and Exceptions are extremely slow to generate,
+ * therefore any code needing to loop through several files should first check this.
+ *
+ * @param file the potential link
+ * @return true if may be a link, false otherwise
+ * @throws IOException if an IOException is thrown while reading from the file
+ */
+ public static boolean isPotentialValidLink(File file) throws IOException {
+ final int minimum_length = 0x64;
+ InputStream fis = new FileInputStream(file);
+ boolean isPotentiallyValid = false;
+ try {
+ isPotentiallyValid = file.isFile()
+ && file.getName().toLowerCase().endsWith(".lnk")
+ && fis.available() >= minimum_length
+ && isMagicPresent(getBytes(fis, 32));
+ } finally {
+ fis.close();
+ }
+ return isPotentiallyValid;
+ }
+
+ public WindowsShortcut(File file) throws IOException, ParseException {
+ InputStream in = new FileInputStream(file);
+ try {
+ parseLink(getBytes(in));
+ } finally {
+ in.close();
+ }
+ }
+
+ /**
+ * @return the name of the filesystem object pointed to by this shortcut
+ */
+ public String getRealFilename() {
+ return real_file;
+ }
+
+ /**
+ * Tests if the shortcut points to a local resource.
+ * @return true if the 'local' bit is set in this shortcut, false otherwise
+ */
+ public boolean isLocal() {
+ return isLocal;
+ }
+
+ /**
+ * Tests if the shortcut points to a directory.
+ * @return true if the 'directory' bit is set in this shortcut, false otherwise
+ */
+ public boolean isDirectory() {
+ return isDirectory;
+ }
+
+ /**
+ * Gets all the bytes from an InputStream
+ * @param in the InputStream from which to read bytes
+ * @return array of all the bytes contained in 'in'
+ * @throws IOException if an IOException is encountered while reading the data from the InputStream
+ */
+ private static byte[] getBytes(InputStream in) throws IOException {
+ return getBytes(in, null);
+ }
+
+ /**
+ * Gets up to max bytes from an InputStream
+ * @param in the InputStream from which to read bytes
+ * @param max maximum number of bytes to read
+ * @return array of all the bytes contained in 'in'
+ * @throws IOException if an IOException is encountered while reading the data from the InputStream
+ */
+ private static byte[] getBytes(InputStream in, Integer max) throws IOException {
+ // read the entire file into a byte buffer
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ byte[] buff = new byte[256];
+ while (max == null || max > 0) {
+ int n = in.read(buff);
+ if (n == -1) {
+ break;
+ }
+ bout.write(buff, 0, n);
+ if (max != null)
+ max -= n;
+ }
+ in.close();
+ return bout.toByteArray();
+ }
+
+ private static boolean isMagicPresent(byte[] link) {
+ final int magic = 0x0000004C;
+ final int magic_offset = 0x00;
+ return link.length >= 32 && bytesToDword(link, magic_offset) == magic;
+ }
+
+ /**
+ * Gobbles up link data by parsing it and storing info in member fields
+ * @param link all the bytes from the .lnk file
+ */
+ private void parseLink(byte[] link) throws ParseException {
+ try {
+ if (!isMagicPresent(link))
+ throw new ParseException("Invalid shortcut; magic is missing", 0);
+
+ // get the flags byte
+ byte flags = link[0x14];
+
+ // get the file attributes byte
+ final int file_atts_offset = 0x18;
+ byte file_atts = link[file_atts_offset];
+ byte is_dir_mask = (byte)0x10;
+ if ((file_atts & is_dir_mask) > 0) {
+ isDirectory = true;
+ } else {
+ isDirectory = false;
+ }
+
+ // if the shell settings are present, skip them
+ final int shell_offset = 0x4c;
+ final byte has_shell_mask = (byte)0x01;
+ int shell_len = 0;
+ if ((flags & has_shell_mask) > 0) {
+ // the plus 2 accounts for the length marker itself
+ shell_len = bytesToWord(link, shell_offset) + 2;
+ }
+
+ // get to the file settings
+ int file_start = 0x4c + shell_len;
+
+ final int file_location_info_flag_offset_offset = 0x08;
+ int file_location_info_flag = link[file_start + file_location_info_flag_offset_offset];
+ isLocal = (file_location_info_flag & 2) == 0;
+ // get the local volume and local system values
+ //final int localVolumeTable_offset_offset = 0x0C;
+ final int basename_offset_offset = 0x10;
+ final int networkVolumeTable_offset_offset = 0x14;
+ final int finalname_offset_offset = 0x18;
+ int finalname_offset = link[file_start + finalname_offset_offset] + file_start;
+ String finalname = getNullDelimitedString(link, finalname_offset);
+ if (isLocal) {
+ int basename_offset = link[file_start + basename_offset_offset] + file_start;
+ String basename = getNullDelimitedString(link, basename_offset);
+ real_file = basename + finalname;
+ } else {
+ int networkVolumeTable_offset = link[file_start + networkVolumeTable_offset_offset] + file_start;
+ int shareName_offset_offset = 0x08;
+ int shareName_offset = link[networkVolumeTable_offset + shareName_offset_offset]
+ + networkVolumeTable_offset;
+ String shareName = getNullDelimitedString(link, shareName_offset);
+ real_file = shareName + "\\" + finalname;
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new ParseException("Could not be parsed, probably not a valid WindowsShortcut", 0);
+ }
+ }
+
+ private static String getNullDelimitedString(byte[] bytes, int off) {
+ int len = 0;
+ // count bytes until the null character (0)
+ while (true) {
+ if (bytes[off + len] == 0) {
+ break;
+ }
+ len++;
+ }
+ return new String(bytes, off, len);
+ }
+
+ /*
+ * convert two bytes into a short note, this is little endian because it's
+ * for an Intel only OS.
+ */
+ private static int bytesToWord(byte[] bytes, int off) {
+ return ((bytes[off + 1] & 0xff) << 8) | (bytes[off] & 0xff);
+ }
+
+ private static int bytesToDword(byte[] bytes, int off) {
+ return (bytesToWord(bytes, off + 2) << 16) | bytesToWord(bytes, off);
+ }
+
+}