From: BobHanson Date: Mon, 8 Jun 2020 21:52:38 +0000 (-0500) Subject: Minor updates X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;ds=sidebyside;h=4e4a20f459bf41ff2a6256fd153c36043522f5c8;p=jalview.git Minor updates --- diff --git a/_j2sclasslist.txt b/_j2sclasslist.txt index 0f9253e..5b98fce 100644 --- a/_j2sclasslist.txt +++ b/_j2sclasslist.txt @@ -719,7 +719,7 @@ sun/swing/DefaultLookup.js sun/swing/SwingLazyValue.js sun/swing/UIAction.js sun/text/resources/FormatData.js -sun/text/resources/FormatData_en.js +sun/text/resources/en/FormatData_en.js sun/util/calendar/AbstractCalendar.js sun/util/calendar/BaseCalendar.js sun/util/calendar/CalendarDate.js diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 2371be3..6d5a0eb 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -35,6 +35,7 @@ import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; //from JalviewLite imports import jalview.api.FeatureRenderer; import jalview.api.FeatureSettingsControllerI; +import jalview.api.FeatureSettingsModelI; import jalview.api.SplitContainerI; import jalview.api.ViewStyleI; import jalview.api.analysis.SimilarityParamsI; @@ -131,7 +132,6 @@ import java.awt.event.MouseEvent; import java.awt.print.PageFormat; import java.awt.print.PrinterJob; import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; @@ -167,8 +167,8 @@ import ext.vamsas.ServiceHandle; */ @SuppressWarnings("serial") public class AlignFrame extends GAlignFrame - implements AlignFrameI, DropTargetListener, - IProgressIndicator, AlignViewControllerGuiI, ColourChangeListener + implements AlignFrameI, DropTargetListener, IProgressIndicator, + AlignViewControllerGuiI, ColourChangeListener { public static final int DEFAULT_WIDTH = 700; @@ -194,9 +194,9 @@ public class AlignFrame extends GAlignFrame /** * Current filename for this alignment */ - private String fileName = null; + String fileName = null; - private File fileObject; + File fileObject; /** * Creates a new AlignFrame object with specific width and height. @@ -366,10 +366,11 @@ public class AlignFrame extends GAlignFrame addAlignmentPanel(alignPanel, newPanel); // setBackground(Color.white); // BH 2019 - + if (!Jalview.isHeadlessMode()) { progressBar = new ProgressBar(this.statusPanel, this.statusBar); + // JalviewJS options statusPanel.setVisible(Jalview.getInstance().getShowStatus()); alignFrameMenuBar.setVisible(Jalview.getInstance().getAllowMenuBar()); } @@ -403,6 +404,7 @@ public class AlignFrame extends GAlignFrame calculateTree.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { @@ -414,24 +416,10 @@ public class AlignFrame extends GAlignFrame if (Desktop.getDesktopPane() != null) { this.setDropTarget(new java.awt.dnd.DropTarget(this, this)); - PropertyChangeListener serviceListener = (Platform.isJS() ? null - : addServiceListeners()); - addInternalFrameListener(new javax.swing.event.InternalFrameAdapter() + if (!Platform.isJS()) { - @Override - public void internalFrameClosed( - javax.swing.event.InternalFrameEvent evt) - { - // System.out.println("deregistering discoverer listener"); - if (serviceListener != null) - { - Desktop.getInstance().removeJalviewPropertyChangeListener( - "services", serviceListener); - } - closeMenuItem_actionPerformed(true); - } - }); - + addServiceListeners(); + } setGUINucleotide(); } @@ -455,6 +443,7 @@ public class AlignFrame extends GAlignFrame new ViewSetProvider() { + @Override public AlignmentPanel[] getAllAlignmentPanels() { @@ -469,6 +458,7 @@ public class AlignFrame extends GAlignFrame }, selviews, new ItemListener() { + @Override public void itemStateChanged(ItemEvent e) { @@ -524,6 +514,7 @@ public class AlignFrame extends GAlignFrame } addFocusListener(new FocusAdapter() { + @Override public void focusGained(FocusEvent e) { @@ -568,6 +559,7 @@ public class AlignFrame extends GAlignFrame { addKeyListener(new KeyAdapter() { + @Override public void keyPressed(KeyEvent evt) { @@ -585,8 +577,8 @@ public class AlignFrame extends GAlignFrame { case KeyEvent.VK_ESCAPE: // escape key - deselectAllSequenceMenuItem_actionPerformed(null); - + // alignPanel.deselectAllSequences(); + alignPanel.deselectAllSequences(); break; case KeyEvent.VK_DOWN: @@ -760,6 +752,7 @@ public class AlignFrame extends GAlignFrame } } + @Override public void keyReleased(KeyEvent evt) { @@ -848,40 +841,58 @@ public class AlignFrame extends GAlignFrame } /* Set up intrinsic listeners for dynamically generated GUI bits. */ - private PropertyChangeListener addServiceListeners() + private void addServiceListeners() { - PropertyChangeListener serviceListener = new PropertyChangeListener() + final java.beans.PropertyChangeListener thisListener; + Desktop.getInstance().addJalviewPropertyChangeListener("services", + thisListener = new java.beans.PropertyChangeListener() + { + + @Override + public void propertyChange(PropertyChangeEvent evt) + { + // // System.out.println("Discoverer property change."); + // if (evt.getPropertyName().equals("services")) + { + SwingUtilities.invokeLater(new Runnable() + { + + + @Override + public void run() + { + System.err.println( + "Rebuild WS Menu for service change"); + BuildWebServiceMenu(); + } + + }); + } + } + }); + addInternalFrameListener(new javax.swing.event.InternalFrameAdapter() { + @Override - public void propertyChange(PropertyChangeEvent evt) + public void internalFrameClosed( + javax.swing.event.InternalFrameEvent evt) { - { - SwingUtilities.invokeLater(new Runnable() - { - - @Override - public void run() - { - System.err.println("Rebuild WS Menu for service change"); - BuildWebServiceMenu(); - } - }); - } + // System.out.println("deregistering discoverer listener"); + Desktop.getInstance().removeJalviewPropertyChangeListener( + "services", thisListener); + closeMenuItem_actionPerformed(true); } - }; - - Desktop.getInstance().addJalviewPropertyChangeListener("services", - serviceListener); + }); // Finally, build the menu once to get current service state new Thread(new Runnable() { + @Override public void run() { BuildWebServiceMenu(); } }).start(); - return serviceListener; } /** @@ -912,6 +923,7 @@ public class AlignFrame extends GAlignFrame * operation that affects the data in the current view (selection changed, * etc) to update the menus to reflect the new state. */ + @Override public void setMenusForViewport() { @@ -942,11 +954,8 @@ public class AlignFrame extends GAlignFrame scaleLeft.setVisible(av.getWrapAlignment()); scaleRight.setVisible(av.getWrapAlignment()); annotationPanelMenuItem.setState(av.isShowAnnotation()); - /* - * Show/hide annotations only enabled if annotation panel is shown - */ - syncAnnotationMenuItems(); - + // Show/hide annotations only enabled if annotation panel is shown + syncAnnotationMenuItems(av.isShowAnnotation()); viewBoxesMenuItem.setSelected(av.getShowBoxes()); viewTextMenuItem.setSelected(av.getShowText()); showNonconservedMenuItem.setSelected(av.getShowUnconserved()); @@ -964,7 +973,8 @@ public class AlignFrame extends GAlignFrame applyToAllGroups.setState(av.getColourAppliesToAllGroups()); showNpFeatsMenuitem.setSelected(av.isShowNPFeats()); showDbRefsMenuitem.setSelected(av.isShowDBRefs()); - autoCalculate.setSelected(av.getAutoCalculateConsensusAndConservation()); + autoCalculate + .setSelected(av.getAutoCalculateConsensusAndConservation()); sortByTree.setSelected(av.sortByTree); listenToViewSelections.setSelected(av.followSelection); @@ -991,12 +1001,14 @@ public class AlignFrame extends GAlignFrame * * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long) */ + @Override public void setProgressBar(String message, long id) { progressBar.setProgressBar(message, id); } + @Override public void registerHandler(final long id, final IProgressIndicatorHandler handler) @@ -1008,6 +1020,7 @@ public class AlignFrame extends GAlignFrame * * @return true if any progress bars are still active */ + @Override public boolean operationInProgress() { @@ -1019,6 +1032,7 @@ public class AlignFrame extends GAlignFrame * will cause the status bar to be hidden, with possibly undesirable flicker * of the screen layout. */ + @Override public void setStatus(String text) { @@ -1038,18 +1052,21 @@ public class AlignFrame extends GAlignFrame return alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer(); } + @Override public void fetchSequence_actionPerformed() { new SequenceFetcher(this); } + @Override public void addFromFile_actionPerformed(ActionEvent e) { Desktop.getInstance().inputLocalFileMenuItem_actionPerformed(viewport); } + @Override public void reload_actionPerformed(ActionEvent e) { @@ -1123,6 +1140,7 @@ public class AlignFrame extends GAlignFrame final FeatureSettings nfs = newframe.featureSettings; SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { @@ -1136,6 +1154,7 @@ public class AlignFrame extends GAlignFrame } } + @Override public void addFromText_actionPerformed(ActionEvent e) { @@ -1143,12 +1162,14 @@ public class AlignFrame extends GAlignFrame .inputTextboxMenuItem_actionPerformed(viewport.getAlignPanel()); } + @Override public void addFromURL_actionPerformed(ActionEvent e) { Desktop.getInstance().inputURLMenuItem_actionPerformed(viewport); } + @Override public void save_actionPerformed(ActionEvent e) { @@ -1167,6 +1188,7 @@ public class AlignFrame extends GAlignFrame * Saves the alignment to a file with a name chosen by the user, if necessary * warning if a file would be overwritten */ + @Override public void saveAs_actionPerformed() { @@ -1264,21 +1286,23 @@ public class AlignFrame extends GAlignFrame String shortName = title; if (shortName.indexOf(File.separatorChar) > -1) { - shortName = shortName.substring( - shortName.lastIndexOf(File.separatorChar) + 1); + shortName = shortName + .substring(shortName.lastIndexOf(File.separatorChar) + 1); } - lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file, shortName); - + lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file, + shortName); + statusBar.setText(MessageManager.formatMessage( "label.successfully_saved_to_file_in_format", new Object[] { fileName, format })); - + return; } AlignExportSettingsI options = new AlignExportSettingsAdapter(false); Runnable cancelAction = new Runnable() { + @Override public void run() { @@ -1287,6 +1311,7 @@ public class AlignFrame extends GAlignFrame }; Runnable outputAction = new Runnable() { + @Override public void run() { @@ -1309,16 +1334,17 @@ public class AlignFrame extends GAlignFrame BackupFiles backupfiles = doBackup ? new BackupFiles(file) : null; try { - String tempFilePath = doBackup ? backupfiles.getTempFilePath() : file; - PrintWriter out = new PrintWriter( - new FileWriter(tempFilePath)); + String tempFilePath = doBackup ? backupfiles.getTempFilePath() + : file; + PrintWriter out = new PrintWriter(new FileWriter(tempFilePath)); out.print(output); out.close(); AlignFrame.this.setTitle(file); statusBar.setText(MessageManager.formatMessage( - "label.successfully_saved_to_file_in_format", new Object[] - { fileName, format.getName() })); + "label.successfully_saved_to_file_in_format", + new Object[] + { fileName, format.getName() })); lastSaveSuccessful = true; } catch (Exception ex) { @@ -1360,6 +1386,7 @@ public class AlignFrame extends GAlignFrame * * @param fileFormatName */ + @Override protected void outputText_actionPerformed(String fileFormatName) { @@ -1368,6 +1395,7 @@ public class AlignFrame extends GAlignFrame AlignExportSettingsI options = new AlignExportSettingsAdapter(false); Runnable outputAction = new Runnable() { + @Override public void run() { @@ -1418,6 +1446,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void htmlMenuItem_actionPerformed(ActionEvent e) { @@ -1425,6 +1454,7 @@ public class AlignFrame extends GAlignFrame htmlSVG.exportHTML(null); } + @Override public void bioJSMenuItem_actionPerformed(ActionEvent e) { @@ -1443,6 +1473,7 @@ public class AlignFrame extends GAlignFrame * * @param f */ + @Override public void createPNG(File f) { @@ -1455,6 +1486,7 @@ public class AlignFrame extends GAlignFrame * * @param f */ + @Override public void createEPS(File f) { @@ -1467,12 +1499,14 @@ public class AlignFrame extends GAlignFrame * * @param f */ + @Override public void createSVG(File f) { alignPanel.makeAlignmentImage(TYPE.SVG, f); } + @Override public void pageSetup_actionPerformed(ActionEvent e) { @@ -1486,6 +1520,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void printMenuItem_actionPerformed(ActionEvent e) { @@ -1494,30 +1529,34 @@ public class AlignFrame extends GAlignFrame thread.start(); } + @Override public void exportFeatures_actionPerformed(ActionEvent e) { new AnnotationExporter(alignPanel).exportFeatures(); } + @Override public void exportAnnotations_actionPerformed(ActionEvent e) { new AnnotationExporter(alignPanel).exportAnnotations(); } + @Override public void associatedData_actionPerformed(ActionEvent e) { final JalviewFileChooser chooser = new JalviewFileChooser( jalview.bin.Cache.getProperty("LAST_DIRECTORY")); chooser.setFileView(new JalviewFileView()); - chooser.setDialogTitle( - MessageManager.getString("label.load_jalview_annotations")); - chooser.setToolTipText( - MessageManager.getString("label.load_jalview_annotations")); + String tooltip = MessageManager + .getString("label.load_jalview_annotations"); + chooser.setDialogTitle(tooltip); + chooser.setToolTipText(tooltip); chooser.setResponseHandler(0, new Runnable() { + @Override public void run() { @@ -1536,6 +1575,7 @@ public class AlignFrame extends GAlignFrame * * @param closeAllTabs */ + @Override public void closeMenuItem_actionPerformed(boolean closeAllTabs) { @@ -1569,6 +1609,13 @@ public class AlignFrame extends GAlignFrame if (closeAllTabs) { + // JalviewJS-develop only + // + // if (featureSettings != null && featureSettings.isOpen()) + // { + // featureSettings.close(); + // featureSettings = null; + // } /* * this will raise an INTERNAL_FRAME_CLOSED event and this method will * be called recursively, with the frame now in 'closed' state @@ -1642,6 +1689,7 @@ public class AlignFrame extends GAlignFrame } } + @Override public void addHistoryItem(CommandI command) { @@ -1687,6 +1735,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void undoMenuItem_actionPerformed(ActionEvent e) { @@ -1725,6 +1774,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void redoMenuItem_actionPerformed(ActionEvent e) { @@ -1931,6 +1981,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void copy_actionPerformed() { @@ -1996,6 +2047,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void pasteNew_actionPerformed(ActionEvent e) { @@ -2008,6 +2060,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void pasteThis_actionPerformed(ActionEvent e) { @@ -2184,7 +2237,7 @@ public class AlignFrame extends GAlignFrame newGraphGroups.add(q, null); } newGraphGroups.set(newann.graphGroup, - new Integer(++fgroup)); + Integer.valueOf(++fgroup)); } newann.graphGroup = newGraphGroups.get(newann.graphGroup) .intValue(); @@ -2231,7 +2284,7 @@ public class AlignFrame extends GAlignFrame newGraphGroups.add(q, null); } newGraphGroups.set(newann.graphGroup, - new Integer(++fgroup)); + Integer.valueOf(++fgroup)); } newann.graphGroup = newGraphGroups.get(newann.graphGroup) .intValue(); @@ -2353,6 +2406,7 @@ public class AlignFrame extends GAlignFrame } + @Override protected void expand_newalign(ActionEvent e) { @@ -2407,6 +2461,7 @@ public class AlignFrame extends GAlignFrame /** * Action Cut (delete and copy) the selected region */ + @Override protected void cut_actionPerformed() { @@ -2417,6 +2472,7 @@ public class AlignFrame extends GAlignFrame /** * Performs menu option to Delete the currently selected region */ + @Override protected void delete_actionPerformed() { @@ -2427,56 +2483,63 @@ public class AlignFrame extends GAlignFrame return; } - Runnable okAction = new Runnable() - { - @Override - public void run() - { - SequenceI[] cut = sg.getSequences() - .toArray(new SequenceI[sg.getSize()]); - - addHistoryItem(new EditCommand( - MessageManager.getString("label.cut_sequences"), Action.CUT, - cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1, - viewport.getAlignment())); - - viewport.setSelectionGroup(null); - viewport.sendSelection(); - viewport.getAlignment().deleteGroup(sg); - - viewport.firePropertyChange("alignment", null, - viewport.getAlignment().getSequences()); - if (viewport.getAlignment().getHeight() < 1) - { - try - { - AlignFrame.this.setClosed(true); - } catch (Exception ex) - { - } - } - }}; + Runnable okAction = new Runnable() + { + + @Override + public void run() + { + SequenceI[] cut = sg.getSequences() + .toArray(new SequenceI[sg.getSize()]); + + addHistoryItem(new EditCommand( + MessageManager.getString("label.cut_sequences"), Action.CUT, + cut, sg.getStartRes(), + sg.getEndRes() - sg.getStartRes() + 1, + viewport.getAlignment())); + + viewport.setSelectionGroup(null); + viewport.sendSelection(); + viewport.getAlignment().deleteGroup(sg); + + viewport.firePropertyChange("alignment", null, + viewport.getAlignment().getSequences()); + if (viewport.getAlignment().getHeight() < 1) + { + try + { + AlignFrame.this.setClosed(true); + } catch (Exception ex) + { + } + } + } + }; /* * If the cut affects all sequences, prompt for confirmation */ - boolean wholeHeight = sg.getSize() == viewport.getAlignment().getHeight(); + boolean wholeHeight = sg.getSize() == viewport.getAlignment() + .getHeight(); boolean wholeWidth = (((sg.getEndRes() - sg.getStartRes()) + 1) == viewport.getAlignment().getWidth()) ? true : false; - if (wholeHeight && wholeWidth) - { - JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.getDesktopPane()); - dialog.setResponseHandler(0, okAction); // 0 = OK_OPTION - Object[] options = new Object[] { MessageManager.getString("action.ok"), - MessageManager.getString("action.cancel") }; - dialog.showDialog(MessageManager.getString("warn.delete_all"), - MessageManager.getString("label.delete_all"), - JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null, - options, options[0]); - } else - { - okAction.run(); - } + if (wholeHeight && wholeWidth) + { + JvOptionPane dialog = JvOptionPane + .newOptionDialog(Desktop.getDesktopPane()); + dialog.setResponseHandler(0, okAction); // 0 = OK_OPTION + Object[] options = new Object[] { + MessageManager.getString("action.ok"), + MessageManager.getString("action.cancel") }; + dialog.showDialog(MessageManager.getString("warn.delete_all"), + MessageManager.getString("label.delete_all"), + JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null, + options, options[0]); + } + else + { + okAction.run(); + } } /** @@ -2485,6 +2548,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void deleteGroups_actionPerformed(ActionEvent e) { @@ -2502,21 +2566,23 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e) { - SequenceGroup sg = new SequenceGroup( - viewport.getAlignment().getSequences()); - - sg.setEndRes(viewport.getAlignment().getWidth() - 1); - viewport.setSelectionGroup(sg); - viewport.isSelectionGroupChanged(true); - viewport.sendSelection(); - // JAL-2034 - should delegate to - // alignPanel to decide if overview needs - // updating. - alignPanel.paintAlignment(false, false); - PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId()); + // SequenceGroup sg = new SequenceGroup( + // viewport.getAlignment().getSequences()); + // + // sg.setEndRes(viewport.getAlignment().getWidth() - 1); + // viewport.setSelectionGroup(sg); + // viewport.isSelectionGroupChanged(true); + // viewport.sendSelection(); + // // JAL-2034 - should delegate to + // // alignPanel to decide if overview needs + // // updating. + // alignPanel.paintAlignment(false, false); + // PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId()); + alignPanel.selectAllSequences(); } /** @@ -2525,24 +2591,26 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void deselectAllSequenceMenuItem_actionPerformed(ActionEvent e) { - if (viewport.cursorMode) - { - alignPanel.getSeqPanel().keyboardNo1 = null; - alignPanel.getSeqPanel().keyboardNo2 = null; - } - viewport.setSelectionGroup(null); - viewport.getColumnSelection().clear(); - viewport.setSelectionGroup(null); - alignPanel.getIdPanel().getIdCanvas().searchResults = null; - // JAL-2034 - should delegate to - // alignPanel to decide if overview needs - // updating. - alignPanel.paintAlignment(false, false); - PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId()); - viewport.sendSelection(); + alignPanel.deselectAllSequences(); + // if (viewport.cursorMode) + // { + // alignPanel.getSeqPanel().keyboardNo1 = null; + // alignPanel.getSeqPanel().keyboardNo2 = null; + // } + // viewport.setSelectionGroup(null); + // viewport.getColumnSelection().clear(); + // viewport.setSelectionGroup(null); + // alignPanel.getIdPanel().getIdCanvas().searchResults = null; + // // JAL-2034 - should delegate to + // // alignPanel to decide if overview needs + // // updating. + // alignPanel.paintAlignment(false, false); + // PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId()); + // viewport.sendSelection(); } /** @@ -2551,6 +2619,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void invertSequenceMenuItem_actionPerformed(ActionEvent e) { @@ -2558,7 +2627,7 @@ public class AlignFrame extends GAlignFrame if (sg == null) { - selectAllSequenceMenuItem_actionPerformed(null); + alignPanel.selectAllSequences(); return; } @@ -2576,6 +2645,7 @@ public class AlignFrame extends GAlignFrame viewport.sendSelection(); } + @Override public void invertColSel_actionPerformed(ActionEvent e) { @@ -2590,6 +2660,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void remove2LeftMenuItem_actionPerformed(ActionEvent e) { @@ -2602,6 +2673,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void remove2RightMenuItem_actionPerformed(ActionEvent e) { @@ -2648,8 +2720,8 @@ public class AlignFrame extends GAlignFrame column, viewport.getAlignment()); } - setStatus(MessageManager - .formatMessage("label.removed_columns", new String[] + setStatus(MessageManager.formatMessage("label.removed_columns", + new String[] { Integer.valueOf(trimRegion.getSize()).toString() })); addHistoryItem(trimRegion); @@ -2674,6 +2746,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e) { @@ -2698,8 +2771,8 @@ public class AlignFrame extends GAlignFrame addHistoryItem(removeGapCols); - setStatus(MessageManager - .formatMessage("label.removed_empty_columns", new Object[] + setStatus(MessageManager.formatMessage("label.removed_empty_columns", + new Object[] { Integer.valueOf(removeGapCols.getSize()).toString() })); // This is to maintain viewport position on first residue @@ -2724,6 +2797,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void removeAllGapsMenuItem_actionPerformed(ActionEvent e) { @@ -2763,6 +2837,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void padGapsMenuitem_actionPerformed(ActionEvent e) { @@ -2777,6 +2852,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void findMenuItem_actionPerformed(ActionEvent e) { @@ -2786,6 +2862,7 @@ public class AlignFrame extends GAlignFrame /** * Create a new view of the current alignment. */ + @Override public void newView_actionPerformed(ActionEvent e) { @@ -2821,8 +2898,8 @@ public class AlignFrame extends GAlignFrame if (viewport.getViewName() == null) { - viewport.setViewName(MessageManager - .getString("label.view_name_original")); + viewport.setViewName( + MessageManager.getString("label.view_name_original")); } /* @@ -2927,6 +3004,7 @@ public class AlignFrame extends GAlignFrame /** * Explode tabbed views into separate windows. */ + @Override public void expandViews_actionPerformed(ActionEvent e) { @@ -2936,6 +3014,7 @@ public class AlignFrame extends GAlignFrame /** * Gather views in separate windows back into a tabbed presentation. */ + @Override public void gatherViews_actionPerformed(ActionEvent e) { @@ -2948,6 +3027,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void font_actionPerformed(ActionEvent e) { @@ -2960,6 +3040,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void seqLimit_actionPerformed(ActionEvent e) { @@ -2970,6 +3051,7 @@ public class AlignFrame extends GAlignFrame alignPanel.paintAlignment(true, false); } + @Override public void idRightAlign_actionPerformed(ActionEvent e) { @@ -2977,6 +3059,7 @@ public class AlignFrame extends GAlignFrame alignPanel.paintAlignment(false, false); } + @Override public void centreColumnLabels_actionPerformed(ActionEvent e) { @@ -2989,6 +3072,7 @@ public class AlignFrame extends GAlignFrame * * @see jalview.jbgui.GAlignFrame#followHighlight_actionPerformed() */ + @Override protected void followHighlight_actionPerformed() { @@ -3010,6 +3094,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void colourTextMenuItem_actionPerformed(ActionEvent e) { @@ -3023,6 +3108,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void wrapMenuItem_actionPerformed(ActionEvent e) { @@ -3033,12 +3119,14 @@ public class AlignFrame extends GAlignFrame alignPanel.updateLayout(); } + @Override public void showAllSeqs_actionPerformed(ActionEvent e) { viewport.showAllHiddenSeqs(); } + @Override public void showAllColumns_actionPerformed(ActionEvent e) { @@ -3047,6 +3135,7 @@ public class AlignFrame extends GAlignFrame viewport.sendSelection(); } + @Override public void hideSelSequences_actionPerformed(ActionEvent e) { @@ -3126,6 +3215,7 @@ public class AlignFrame extends GAlignFrame * jalview.jbgui.GAlignFrame#hideAllButSelection_actionPerformed(java.awt. * event.ActionEvent) */ + @Override public void hideAllButSelection_actionPerformed(ActionEvent e) { @@ -3140,6 +3230,7 @@ public class AlignFrame extends GAlignFrame * jalview.jbgui.GAlignFrame#hideAllSelection_actionPerformed(java.awt.event * .ActionEvent) */ + @Override public void hideAllSelection_actionPerformed(ActionEvent e) { @@ -3159,6 +3250,7 @@ public class AlignFrame extends GAlignFrame * jalview.jbgui.GAlignFrame#showAllhidden_actionPerformed(java.awt.event. * ActionEvent) */ + @Override public void showAllhidden_actionPerformed(ActionEvent e) { @@ -3168,6 +3260,7 @@ public class AlignFrame extends GAlignFrame viewport.sendSelection(); } + @Override public void hideSelColumns_actionPerformed(ActionEvent e) { @@ -3177,6 +3270,7 @@ public class AlignFrame extends GAlignFrame viewport.sendSelection(); } + @Override public void hiddenMarkers_actionPerformed(ActionEvent e) { @@ -3190,6 +3284,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void scaleAbove_actionPerformed(ActionEvent e) { @@ -3204,6 +3299,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void scaleLeft_actionPerformed(ActionEvent e) { @@ -3218,6 +3314,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void scaleRight_actionPerformed(ActionEvent e) { @@ -3232,6 +3329,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void viewBoxesMenuItem_actionPerformed(ActionEvent e) { @@ -3245,6 +3343,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void viewTextMenuItem_actionPerformed(ActionEvent e) { @@ -3258,6 +3357,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void renderGapsMenuItem_actionPerformed(ActionEvent e) { @@ -3267,18 +3367,26 @@ public class AlignFrame extends GAlignFrame public FeatureSettings featureSettings; + @Override public FeatureSettingsControllerI getFeatureSettingsUI() { return featureSettings; } + @Override public void featureSettings_actionPerformed(ActionEvent e) { + showFeatureSettingsUI(); + } + + + public FeatureSettingsControllerI showFeatureSettingsUI() + { if (featureSettings != null) { - featureSettings.close(); + // featureSettings.closeOldSettings(); featureSettings = null; } if (!showSeqFeatures.isSelected()) @@ -3288,6 +3396,7 @@ public class AlignFrame extends GAlignFrame showSeqFeatures_actionPerformed(null); } featureSettings = new FeatureSettings(this); + return featureSettings; } /** @@ -3296,6 +3405,7 @@ public class AlignFrame extends GAlignFrame * @param evt * DOCUMENT ME! */ + @Override public void showSeqFeatures_actionPerformed(ActionEvent evt) { @@ -3312,25 +3422,25 @@ public class AlignFrame extends GAlignFrame * * @param e */ + @Override public void annotationPanelMenuItem_actionPerformed(ActionEvent e) { final boolean setVisible = annotationPanelMenuItem.isSelected(); viewport.setShowAnnotation(setVisible); - syncAnnotationMenuItems(); + syncAnnotationMenuItems(setVisible); alignPanel.updateLayout(); } - private void syncAnnotationMenuItems() + private void syncAnnotationMenuItems(boolean setVisible) { - final boolean setVisible = annotationPanelMenuItem.isSelected(); showAllSeqAnnotations.setEnabled(setVisible); hideAllSeqAnnotations.setEnabled(setVisible); showAllAlAnnotations.setEnabled(setVisible); hideAllAlAnnotations.setEnabled(setVisible); } - + @Override public void alignmentProperties() { @@ -3348,7 +3458,7 @@ public class AlignFrame extends GAlignFrame JLabel textLabel = new JLabel(); textLabel.setText(content); textLabel.setBackground(Color.WHITE); - + pane = new JPanel(new BorderLayout()); ((JPanel) pane).setOpaque(true); pane.setBackground(Color.WHITE); @@ -3382,6 +3492,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void overviewMenuItem_actionPerformed(ActionEvent e) { @@ -3426,6 +3537,7 @@ public class AlignFrame extends GAlignFrame frame.addInternalFrameListener( new javax.swing.event.InternalFrameAdapter() { + @Override public void internalFrameClosed( javax.swing.event.InternalFrameEvent evt) @@ -3442,6 +3554,7 @@ public class AlignFrame extends GAlignFrame alignPanel.setOverviewPanel(overview); } + @Override public void textColour_actionPerformed() { @@ -3454,12 +3567,14 @@ public class AlignFrame extends GAlignFrame * CovariationColourScheme(viewport.getAlignment().getAlignmentAnnotation * ()[0])); } */ + @Override public void annotationColour_actionPerformed() { new AnnotationColourChooser(viewport, alignPanel); } + @Override public void annotationColumn_actionPerformed(ActionEvent e) { @@ -3473,6 +3588,7 @@ public class AlignFrame extends GAlignFrame * * @param selected */ + @Override public void applyToAllGroups_actionPerformed(boolean selected) { @@ -3485,6 +3601,7 @@ public class AlignFrame extends GAlignFrame * @param name * the name (not the menu item label!) of the colour scheme */ + @Override public void changeColour_actionPerformed(String name) { @@ -3502,8 +3619,8 @@ public class AlignFrame extends GAlignFrame * otherwise set the chosen colour scheme (or null for 'None') */ ColourSchemeI cs = ColourSchemes.getInstance().getColourScheme(name, - viewport, - viewport.getAlignment(), viewport.getHiddenRepSequences()); + viewport, viewport.getAlignment(), + viewport.getHiddenRepSequences()); changeColour(cs); } @@ -3512,6 +3629,7 @@ public class AlignFrame extends GAlignFrame * * @param cs */ + @Override public void changeColour(ColourSchemeI cs) { @@ -3526,6 +3644,7 @@ public class AlignFrame extends GAlignFrame /** * Show the PID threshold slider panel */ + @Override protected void modifyPID_actionPerformed() { @@ -3537,6 +3656,7 @@ public class AlignFrame extends GAlignFrame /** * Show the Conservation slider panel */ + @Override protected void modifyConservation_actionPerformed() { @@ -3548,6 +3668,7 @@ public class AlignFrame extends GAlignFrame /** * Action on selecting or deselecting (Colour) By Conservation */ + @Override public void conservationMenuItem_actionPerformed(boolean selected) { @@ -3569,6 +3690,7 @@ public class AlignFrame extends GAlignFrame /** * Action on selecting or deselecting (Colour) Above PID Threshold */ + @Override public void abovePIDThreshold_actionPerformed(boolean selected) { @@ -3597,6 +3719,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void sortPairwiseMenuItem_actionPerformed(ActionEvent e) { @@ -3614,6 +3737,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void sortIDMenuItem_actionPerformed(ActionEvent e) { @@ -3630,6 +3754,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void sortLengthMenuItem_actionPerformed(ActionEvent e) { @@ -3646,6 +3771,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void sortGroupMenuItem_actionPerformed(ActionEvent e) { @@ -3663,6 +3789,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void removeRedundancyMenuItem_actionPerformed(ActionEvent e) { @@ -3675,6 +3802,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e) { @@ -3697,10 +3825,12 @@ public class AlignFrame extends GAlignFrame } } + @Override public void autoCalculate_actionPerformed(ActionEvent e) { - viewport.setAutoCalculateConsensusAndConservation(autoCalculate.isSelected()); + viewport.setAutoCalculateConsensusAndConservation( + autoCalculate.isSelected()); if (viewport.getAutoCalculateConsensusAndConservation()) { viewport.firePropertyChange("alignment", null, @@ -3708,12 +3838,14 @@ public class AlignFrame extends GAlignFrame } } + @Override public void sortByTreeOption_actionPerformed(ActionEvent e) { viewport.sortByTree = sortByTree.isSelected(); } + @Override protected void listenToViewSelections_actionPerformed(ActionEvent e) { @@ -3800,6 +3932,7 @@ public class AlignFrame extends GAlignFrame sort.add(item); item.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(ActionEvent e) { @@ -3833,6 +3966,7 @@ public class AlignFrame extends GAlignFrame sort.add(item); item.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(ActionEvent e) { @@ -3858,6 +3992,7 @@ public class AlignFrame extends GAlignFrame * rebuilding in subsequence calls. * */ + @Override public void buildSortByAnnotationScoresMenu() { @@ -3887,8 +4022,7 @@ public class AlignFrame extends GAlignFrame Enumeration labels = scoreSorts.keys(); while (labels.hasMoreElements()) { - addSortByAnnotScoreMenuItem(sortByAnnotScore, - labels.nextElement()); + addSortByAnnotScoreMenuItem(sortByAnnotScore, labels.nextElement()); } sortByAnnotScore.setVisible(scoreSorts.size() > 0); scoreSorts.clear(); @@ -3905,6 +4039,7 @@ public class AlignFrame extends GAlignFrame * closed, and adjust the tree leaf to sequence mapping when the alignment is * modified. */ + @Override public void buildTreeSortMenu() { @@ -3934,6 +4069,7 @@ public class AlignFrame extends GAlignFrame final JMenuItem item = new JMenuItem(tp.getTitle()); item.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(ActionEvent e) { @@ -4043,6 +4179,7 @@ public class AlignFrame extends GAlignFrame * @param e * DOCUMENT ME! */ + @Override protected void loadTreeMenuItem_actionPerformed(ActionEvent e) { @@ -4055,8 +4192,9 @@ public class AlignFrame extends GAlignFrame chooser.setToolTipText( MessageManager.getString("label.load_tree_file")); - chooser.setResponseHandler(0,new Runnable() + chooser.setResponseHandler(0, new Runnable() { + @Override public void run() { @@ -4070,7 +4208,8 @@ public class AlignFrame extends GAlignFrame viewport.setCurrentTree(showNewickTree(fin, filePath).getTree()); } catch (Exception ex) { - JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), ex.getMessage(), + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), + ex.getMessage(), MessageManager .getString("label.problem_reading_tree_file"), JvOptionPane.WARNING_MESSAGE); @@ -4181,6 +4320,7 @@ public class AlignFrame extends GAlignFrame buildingMenu = true; new Thread(new Runnable() { + @Override public void run() { @@ -4215,11 +4355,11 @@ public class AlignFrame extends GAlignFrame final JMenu dismenu = new JMenu("Protein Disorder"); // JAL-940 - only show secondary structure prediction services from // the legacy server - Hashtable> services = Discoverer + Hashtable> ds = Discoverer .getInstance().getServices(); if (// Cache.getDefault("SHOW_JWS1_SERVICES", true) // && - services != null && (services.size() > 0)) + ds != null && (ds.size() > 0)) { // TODO: refactor to allow list of AbstractName/Handler bindings to // be @@ -4227,14 +4367,13 @@ public class AlignFrame extends GAlignFrame // No MSAWS used any more: // Vector msaws = null; // (Vector) // Discoverer.services.get("MsaWS"); - Vector secstrpr = services.get("SecStrPred"); + Vector secstrpr = ds.get("SecStrPred"); if (secstrpr != null) { // Add any secondary structure prediction services for (int i = 0, j = secstrpr.size(); i < j; i++) { - final ext.vamsas.ServiceHandle sh = secstrpr - .get(i); + final ext.vamsas.ServiceHandle sh = secstrpr.get(i); jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer .getServiceClient(sh); int p = secstrmenu.getItemCount(); @@ -4259,6 +4398,7 @@ public class AlignFrame extends GAlignFrame javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { @@ -4351,7 +4491,7 @@ public class AlignFrame extends GAlignFrame * JMenuItem testAlView = new JMenuItem("Test AlignmentView"); final * AlignFrame af = this; testAlView.addActionListener(new ActionListener() { * - * @Override public void actionPerformed(ActionEvent e) { + * public void actionPerformed(ActionEvent e) { * jalview.datamodel.AlignmentView * .testSelectionViews(af.viewport.getAlignment(), * af.viewport.getColumnSelection(), af.viewport.selectionGroup); } @@ -4407,6 +4547,7 @@ public class AlignFrame extends GAlignFrame JMenuItem xtype = new JMenuItem(source); xtype.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { @@ -4450,6 +4591,7 @@ public class AlignFrame extends GAlignFrame * Construct and display a new frame containing the translation of this * frame's DNA sequences to their aligned protein (amino acid) equivalents. */ + @Override public void showTranslation_actionPerformed(GeneticCodeI codeTable) { @@ -4468,8 +4610,8 @@ public class AlignFrame extends GAlignFrame final String errorTitle = MessageManager .getString("label.implementation_error") + MessageManager.getString("label.translation_failed"); - JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), msg, errorTitle, - JvOptionPane.ERROR_MESSAGE); + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), msg, + errorTitle, JvOptionPane.ERROR_MESSAGE); return; } if (al == null || al.getHeight() == 0) @@ -4478,8 +4620,8 @@ public class AlignFrame extends GAlignFrame "label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation"); final String errorTitle = MessageManager .getString("label.translation_failed"); - JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), msg, errorTitle, - JvOptionPane.WARNING_MESSAGE); + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), msg, + errorTitle, JvOptionPane.WARNING_MESSAGE); } else { @@ -4529,6 +4671,7 @@ public class AlignFrame extends GAlignFrame } + @Override public void refreshFeatureUI(boolean enableIfNecessary) { @@ -4543,26 +4686,31 @@ public class AlignFrame extends GAlignFrame } + @Override public void dragEnter(DropTargetDragEvent evt) { } + @Override public void dragExit(DropTargetEvent evt) { } + @Override public void dragOver(DropTargetDragEvent evt) { } + @Override public void dropActionChanged(DropTargetDragEvent evt) { } + @Override public void drop(DropTargetDropEvent evt) { @@ -4571,24 +4719,34 @@ public class AlignFrame extends GAlignFrame evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); Transferable t = evt.getTransferable(); - final AlignFrame thisaf = this; final List files = new ArrayList<>(); List protocols = new ArrayList<>(); try { Desktop.transferFromDropTarget(files, protocols, evt, t); - } catch (Exception e) - { - e.printStackTrace(); - } - if (files != null) + if (files.size() > 0) { new Thread(new Runnable() { + @Override public void run() { + loadDroppedFiles(files, protocols, evt, t); + } + }).start(); + } + } catch (Exception e) + { + e.printStackTrace(); + } + } + + protected void loadDroppedFiles(List files, + List protocols, DropTargetDropEvent evt, + Transferable t) + { try { // check to see if any of these files have names matching sequences @@ -4613,10 +4771,13 @@ public class AlignFrame extends GAlignFrame if (protocol == DataSourceType.FILE) { File fl; - if (file instanceof File) { + if (file instanceof File) + { fl = (File) file; Platform.cacheFileData(fl); - } else { + } + else + { fl = new File(fileName); } pdbfn = fl.getName(); @@ -4667,8 +4828,8 @@ public class AlignFrame extends GAlignFrame int assocfiles = 0; if (filesmatched.size() > 0) { - boolean autoAssociate = Cache - .getDefault(Preferences.AUTOASSOCIATE_PDBANDSEQS, false); + boolean autoAssociate = Cache.getDefault( + Preferences.AUTOASSOCIATE_PDBANDSEQS, false); if (!autoAssociate) { String msg = MessageManager.formatMessage( @@ -4678,8 +4839,8 @@ public class AlignFrame extends GAlignFrame .toString() }); String ttl = MessageManager.getString( "label.automatically_associate_structure_files_by_name"); - int choice = JvOptionPane.showConfirmDialog(thisaf, msg, - ttl, JvOptionPane.YES_NO_OPTION); + int choice = JvOptionPane.showConfirmDialog(this, msg, ttl, + JvOptionPane.YES_NO_OPTION); autoAssociate = choice == JvOptionPane.YES_OPTION; } if (autoAssociate) @@ -4720,9 +4881,9 @@ public class AlignFrame extends GAlignFrame } if (filesnotmatched.size() > 0) { - if (assocfiles > 0 && (Cache.getDefault( - "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false) - || JvOptionPane.showConfirmDialog(thisaf, + if (assocfiles > 0 && (Cache + .getDefault("AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false) + || JvOptionPane.showConfirmDialog(this, "" + MessageManager.formatMessage( "label.ignore_unmatched_dropped_files_info", new Object[] @@ -4747,9 +4908,6 @@ public class AlignFrame extends GAlignFrame ex.printStackTrace(); } } - }).start(); - } - } /** * Attempt to load a "dropped" file or URL string, by testing in turn for @@ -4858,9 +5016,17 @@ public class AlignFrame extends GAlignFrame { if (parseFeaturesFile(file, sourceType)) { + SplitFrame splitFrame = (SplitFrame) getSplitViewContainer(); + if (splitFrame != null) + { + splitFrame.repaint(); + } + else + { alignPanel.paintAlignment(true, true); } } + } else { new FileLoader().loadFile(viewport, file, sourceType, format); @@ -4910,9 +5076,37 @@ public class AlignFrame extends GAlignFrame } /** + * Change the display state for the given feature groups -- Added by BH from + * JalviewLite + * + * @param groups + * list of group strings + * @param state + * visible or invisible + */ + + public void setFeatureGroupState(String[] groups, boolean state) + { + jalview.api.FeatureRenderer fr = null; + viewport.setShowSequenceFeatures(true); + if (alignPanel != null + && (fr = alignPanel.getFeatureRenderer()) != null) + { + + fr.setGroupVisibility(Arrays.asList(groups), state); + alignPanel.getSeqPanel().seqCanvas.repaint(); + if (alignPanel.overviewPanel != null) + { + alignPanel.overviewPanel.updateOverviewImage(); + } + } + } + + /** * Method invoked by the ChangeListener on the tabbed pane, in other words * when a different tabbed pane is selected by the user or programmatically. */ + @Override public void tabSelectionChanged(int index) { @@ -4922,6 +5116,21 @@ public class AlignFrame extends GAlignFrame viewport = alignPanel.av; avc.setViewportAndAlignmentPanel(viewport, alignPanel); setMenusFromViewport(viewport); + if (featureSettings != null// && featureSettings.isOpen() + && featureSettings.fr.getViewport() != viewport) + { + if (viewport.isShowSequenceFeatures()) + { + // refresh the featureSettings to reflect UI change + showFeatureSettingsUI(); + } + else + { + // close feature settings for this view. + featureSettings.close(); + } + } + } /* @@ -4968,6 +5177,7 @@ public class AlignFrame extends GAlignFrame /** * On right mouse click on view tab, prompt for and set new view name. */ + @Override public void tabbedPane_mousePressed(MouseEvent e) { @@ -4992,34 +5202,9 @@ public class AlignFrame extends GAlignFrame } /** - * Change the display state for the given feature groups -- Added by BH from - * JalviewLite - * - * @param groups - * list of group strings - * @param state - * visible or invisible - */ - public void setFeatureGroupState(String[] groups, boolean state) - { - jalview.api.FeatureRenderer fr = null; - viewport.setShowSequenceFeatures(true); - if (alignPanel != null - && (fr = alignPanel.getFeatureRenderer()) != null) - { - - fr.setGroupVisibility(Arrays.asList(groups), state); - alignPanel.getSeqPanel().seqCanvas.repaint(); - if (alignPanel.overviewPanel != null) - { - alignPanel.overviewPanel.updateOverviewImage(); - } - } - } - - /** * Open the dialog for regex description parsing. */ + @Override protected void extractScores_actionPerformed(ActionEvent e) { @@ -5043,6 +5228,7 @@ public class AlignFrame extends GAlignFrame * jalview.jbgui.GAlignFrame#showDbRefs_actionPerformed(java.awt.event.ActionEvent * ) */ + @Override protected void showDbRefs_actionPerformed(ActionEvent e) { @@ -5055,6 +5241,7 @@ public class AlignFrame extends GAlignFrame * @seejalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event. * ActionEvent) */ + @Override protected void showNpFeats_actionPerformed(ActionEvent e) { @@ -5110,6 +5297,7 @@ public class AlignFrame extends GAlignFrame Cache.getDefault(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES, true)); trimrs.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { @@ -5126,11 +5314,13 @@ public class AlignFrame extends GAlignFrame fetchr.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { new Thread(new Runnable() { + @Override public void run() { @@ -5142,9 +5332,17 @@ public class AlignFrame extends GAlignFrame alignPanel.alignFrame.featureSettings, isNucleotide); dbRefFetcher.addListener(new FetchFinishedListenerI() { + @Override public void finished() { + // + // for (FeatureSettingsModelI srcSettings : dbRefFetcher + // .getFeatureSettingsModels()) + // { + // + // alignPanel.av.mergeFeaturesStyle(srcSettings); + // } AlignFrame.this.setMenusForViewport(); } }); @@ -5158,16 +5356,19 @@ public class AlignFrame extends GAlignFrame rfetch.add(fetchr); new Thread(new Runnable() { + @Override public void run() { javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { - String[] dbclasses = jalview.ws.SequenceFetcher.getInstance() - .getNonAlignmentSources(); + jalview.ws.SequenceFetcher + sf = jalview.ws.SequenceFetcher.getInstance(); + String[] dbclasses = sf.getNonAlignmentSources(); List otherdb; JMenu dfetch = new JMenu(); JMenu ifetch = new JMenu(); @@ -5177,8 +5378,7 @@ public class AlignFrame extends GAlignFrame int dbi = 0; for (String dbclass : dbclasses) { - otherdb = jalview.ws.SequenceFetcher.getInstance() - .getSourceProxy(dbclass); + otherdb = sf.getSourceProxy(dbclass); // add a single entry for this class, or submenu allowing 'fetch // all' or pick one if (otherdb == null || otherdb.size() < 1) @@ -5192,18 +5392,19 @@ public class AlignFrame extends GAlignFrame if (otherdb.size() == 1) { DbSourceProxy src = otherdb.get(0); - DbSourceProxy[] dassource = new DbSourceProxy[] { - src }; + DbSourceProxy[] dassource = new DbSourceProxy[] { src }; fetchr = new JMenuItem(src.getDbSource()); fetchr.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { new Thread(new Runnable() { + @Override public void run() { @@ -5218,9 +5419,14 @@ public class AlignFrame extends GAlignFrame dbRefFetcher .addListener(new FetchFinishedListenerI() { + @Override public void finished() { + FeatureSettingsModelI srcSettings = dassource[0] + .getFeatureColourScheme(); + // alignPanel.av.mergeFeaturesStyle( + // srcSettings); AlignFrame.this.setMenusForViewport(); } }); @@ -5248,12 +5454,14 @@ public class AlignFrame extends GAlignFrame { src.getDbSource() })); fetchr.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { new Thread(new Runnable() { + @Override public void run() { @@ -5268,6 +5476,7 @@ public class AlignFrame extends GAlignFrame dbRefFetcher .addListener(new FetchFinishedListenerI() { + @Override public void finished() { @@ -5316,12 +5525,14 @@ public class AlignFrame extends GAlignFrame fetchr.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { new Thread(new Runnable() { + @Override public void run() { @@ -5336,6 +5547,7 @@ public class AlignFrame extends GAlignFrame dbRefFetcher .addListener(new FetchFinishedListenerI() { + @Override public void finished() { @@ -5387,6 +5599,7 @@ public class AlignFrame extends GAlignFrame /** * Left justify the whole alignment. */ + @Override protected void justifyLeftMenuItem_actionPerformed(ActionEvent e) { @@ -5398,6 +5611,7 @@ public class AlignFrame extends GAlignFrame /** * Right justify the whole alignment. */ + @Override protected void justifyRightMenuItem_actionPerformed(ActionEvent e) { @@ -5406,6 +5620,7 @@ public class AlignFrame extends GAlignFrame viewport.firePropertyChange("alignment", null, al); } + @Override public void setShowSeqFeatures(boolean b) { @@ -5420,6 +5635,7 @@ public class AlignFrame extends GAlignFrame * jalview.jbgui.GAlignFrame#showUnconservedMenuItem_actionPerformed(java. * awt.event.ActionEvent) */ + @Override protected void showUnconservedMenuItem_actionPerformed(ActionEvent e) { @@ -5434,6 +5650,7 @@ public class AlignFrame extends GAlignFrame * jalview.jbgui.GAlignFrame#showGroupConsensus_actionPerformed(java.awt.event * .ActionEvent) */ + @Override protected void showGroupConsensus_actionPerformed(ActionEvent e) { @@ -5449,6 +5666,7 @@ public class AlignFrame extends GAlignFrame * jalview.jbgui.GAlignFrame#showGroupConservation_actionPerformed(java.awt * .event.ActionEvent) */ + @Override protected void showGroupConservation_actionPerformed(ActionEvent e) { @@ -5463,6 +5681,7 @@ public class AlignFrame extends GAlignFrame * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt * .event.ActionEvent) */ + @Override protected void showConsensusHistogram_actionPerformed(ActionEvent e) { @@ -5477,6 +5696,7 @@ public class AlignFrame extends GAlignFrame * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt * .event.ActionEvent) */ + @Override protected void showSequenceLogo_actionPerformed(ActionEvent e) { @@ -5484,6 +5704,7 @@ public class AlignFrame extends GAlignFrame alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState()); } + @Override protected void normaliseSequenceLogo_actionPerformed(ActionEvent e) { @@ -5493,6 +5714,7 @@ public class AlignFrame extends GAlignFrame alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState()); } + @Override protected void applyAutoAnnotationSettings_actionPerformed(ActionEvent e) { @@ -5506,6 +5728,7 @@ public class AlignFrame extends GAlignFrame * jalview.jbgui.GAlignFrame#makeGrpsFromSelection_actionPerformed(java.awt * .event.ActionEvent) */ + @Override protected void makeGrpsFromSelection_actionPerformed(ActionEvent e) { @@ -5530,6 +5753,7 @@ public class AlignFrame extends GAlignFrame } } + @Override protected void createGroup_actionPerformed(ActionEvent e) { @@ -5543,6 +5767,7 @@ public class AlignFrame extends GAlignFrame } } + @Override protected void unGroup_actionPerformed(ActionEvent e) { @@ -5581,6 +5806,7 @@ public class AlignFrame extends GAlignFrame * @param forAlignment * update non-sequence-related annotations */ + @Override protected void setAnnotationsVisibility(boolean visible, boolean forSequences, boolean forAlignment) @@ -5614,6 +5840,7 @@ public class AlignFrame extends GAlignFrame /** * Store selected annotation sort order for the view and repaint. */ + @Override protected void sortAnnotations_actionPerformed() { @@ -5688,6 +5915,7 @@ public class AlignFrame extends GAlignFrame * * @param show */ + @Override protected void showComplement_actionPerformed(boolean show) { @@ -5702,6 +5930,7 @@ public class AlignFrame extends GAlignFrame * Generate the reverse (optionally complemented) of the selected sequences, * and add them to the alignment */ + @Override protected void showReverse_actionPerformed(boolean complement) { @@ -5727,6 +5956,7 @@ public class AlignFrame extends GAlignFrame * AlignFrame is set as currentAlignFrame in Desktop, to allow the script to * be targeted at this alignment. */ + @Override protected void runGroovy_actionPerformed() { @@ -5777,6 +6007,7 @@ public class AlignFrame extends GAlignFrame return false; } + @Override protected void selectHighlightedColumns_actionPerformed( ActionEvent actionEvent) @@ -5827,6 +6058,7 @@ public class AlignFrame extends GAlignFrame } } + @Override protected void loadVcf_actionPerformed() { @@ -5838,6 +6070,7 @@ public class AlignFrame extends GAlignFrame final AlignFrame us = this; chooser.setResponseHandler(0, new Runnable() { + @Override public void run() { @@ -5851,6 +6084,38 @@ public class AlignFrame extends GAlignFrame } + private Rectangle lastFeatureSettingsBounds = null; + + + public void setFeatureSettingsGeometry(Rectangle bounds) + { + lastFeatureSettingsBounds = bounds; + } + + + public Rectangle getFeatureSettingsGeometry() + { + return lastFeatureSettingsBounds; + } + + + public void scrollTo(int row, int column) + { + alignPanel.getSeqPanel().scrollTo(row, column); + } + + + public void scrollToRow(int row) + { + alignPanel.getSeqPanel().scrollToRow(row); + } + + + public void scrollToColumn(int column) + { + alignPanel.getSeqPanel().scrollToColumn(column); + } + /** * BH 2019 from JalviewLite * @@ -5864,8 +6129,7 @@ public class AlignFrame extends GAlignFrame { jalview.api.FeatureRenderer fr = null; if (alignPanel != null - && (fr = alignPanel - .getFeatureRenderer()) != null) + && (fr = alignPanel.getFeatureRenderer()) != null) { List gps = fr.getGroups(visible); String[] _gps = gps.toArray(new String[gps.size()]); @@ -5874,21 +6138,6 @@ public class AlignFrame extends GAlignFrame return null; } - public void scrollTo(int row, int column) - { - alignPanel.getSeqPanel().scrollTo(row, column); - } - - public void scrollToRow(int row) - { - alignPanel.getSeqPanel().scrollToRow(row); - } - - public void scrollToColumn(int column) - { - alignPanel.getSeqPanel().scrollToColumn(column); - } - /** * * @return list of feature groups on the view diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index 72a074d..443ae68 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -1856,11 +1856,21 @@ public class AlignmentPanel extends GAlignmentPanel implements private boolean holdRepaint = false; + /** + * Checked by SeqCanvas when painting + * + * @return + */ public boolean getHoldRepaint() { return holdRepaint; } + /** + * Called specifically by Jalview2xml when loading a JPV file + * + * @param b + */ public void setHoldRepaint(boolean b) { if (holdRepaint == b) @@ -1886,4 +1896,42 @@ public class AlignmentPanel extends GAlignmentPanel implements super.repaint(); } + public void selectAllSequences() + { + selectSequences(av.getAlignment().getSequences()); + } + + public void deselectAllSequences() + { + if (av.cursorMode) + { + getSeqPanel().keyboardNo1 = null; + getSeqPanel().keyboardNo2 = null; + } + av.setSelectionGroup(null); + av.getColumnSelection().clear(); + av.setSelectionGroup(null); + getIdPanel().getIdCanvas().searchResults = null; + av.sendSelection(); + // JAL-2034 - should delegate to + // alignPanel to decide if overview needs + // updating. + paintAlignment(false, false); + PaintRefresher.Refresh(this, av.getSequenceSetId()); + } + + public void selectSequences(List seqs) + { + SequenceGroup sg = new SequenceGroup(seqs); + sg.setEndRes(av.getAlignment().getWidth() - 1); + av.setSelectionGroup(sg); + av.isSelectionGroupChanged(true); + av.sendSelection(); + // JAL-2034 - should delegate to + // alignPanel to decide if overview needs + // updating. + paintAlignment(false, false); + PaintRefresher.Refresh(this, av.getSequenceSetId()); + } + } diff --git a/src/jalview/gui/AssociatePdbFileWithSeq.java b/src/jalview/gui/AssociatePdbFileWithSeq.java index 1f540da..5b5bd18 100644 --- a/src/jalview/gui/AssociatePdbFileWithSeq.java +++ b/src/jalview/gui/AssociatePdbFileWithSeq.java @@ -84,7 +84,7 @@ public class AssociatePdbFileWithSeq entry.setType(PDBEntry.Type.FILE); entry.setFile(fileName); sequence.getDatasetSequence().addPDBId(entry); - Desktop.getInstance().getStructureSelectionManager() + Desktop.getStructureSelectionManager() .registerPDBEntry(entry); return entry; } diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 9e0c89b..3cecfdd 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -471,88 +471,94 @@ public class Desktop extends GDesktop getIdentifiersOrgData(); - checkURLLinks(); + if (Jalview.isInteractive()) + { + // disabled for SeqCanvasTest + checkURLLinks(); - // Spawn a thread that shows the splashscreen + // Spawn a thread that shows the splashscreen - SwingUtilities.invokeLater(new Runnable() - { - @Override - public void run() + SwingUtilities.invokeLater(new Runnable() { - new SplashScreen(); - } - }); + @Override + public void run() + { + new SplashScreen(); + } + }); - // Thread off a new instance of the file chooser - this reduces the time - // it - // takes to open it later on. - new Thread(new Runnable() - { - @Override - public void run() + // Thread off a new instance of the file chooser - this reduces the + // time + // it + // takes to open it later on. + new Thread(new Runnable() { - Cache.log.debug("Filechooser init thread started."); - String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT"); - JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"), - fileFormat); - Cache.log.debug("Filechooser init thread finished."); - } - }).start(); - // Add the service change listener - changeSupport.addJalviewPropertyChangeListener("services", - new PropertyChangeListener() - { - - @Override - public void propertyChange(PropertyChangeEvent evt) + @Override + public void run() + { + Cache.log.debug("Filechooser init thread started."); + String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT"); + JalviewFileChooser.forRead( + Cache.getProperty("LAST_DIRECTORY"), fileFormat); + Cache.log.debug("Filechooser init thread finished."); + } + }).start(); + // Add the service change listener + changeSupport.addJalviewPropertyChangeListener("services", + new PropertyChangeListener() { - Cache.log.debug("Firing service changed event for " - + evt.getNewValue()); - JalviewServicesChanged(evt); - } - }); - - } + @Override + public void propertyChange(PropertyChangeEvent evt) + { + Cache.log.debug("Firing service changed event for " + + evt.getNewValue()); + JalviewServicesChanged(evt); + } - this.setDropTarget(new java.awt.dnd.DropTarget(desktopPane, this)); + }); - this.addWindowListener(new WindowAdapter() - { - @Override - public void windowClosing(WindowEvent evt) - { - quit(); } - }); - MouseAdapter ma; - this.addMouseListener(ma = new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent evt) + this.setDropTarget(new java.awt.dnd.DropTarget(desktopPane, this)); + + this.addWindowListener(new WindowAdapter() { - if (evt.isPopupTrigger()) // Mac + @Override + public void windowClosing(WindowEvent evt) { - showPasteMenu(evt.getX(), evt.getY()); + quit(); } - } + }); - @Override - public void mouseReleased(MouseEvent evt) + MouseAdapter ma; + this.addMouseListener(ma = new MouseAdapter() { - if (evt.isPopupTrigger()) // Windows + @Override + public void mousePressed(MouseEvent evt) { - showPasteMenu(evt.getX(), evt.getY()); + if (evt.isPopupTrigger()) // Mac + { + showPasteMenu(evt.getX(), evt.getY()); + } } - } - }); - desktopPane.addMouseListener(ma); + + @Override + public void mouseReleased(MouseEvent evt) + { + if (evt.isPopupTrigger()) // Windows + { + showPasteMenu(evt.getX(), evt.getY()); + } + } + }); + desktopPane.addMouseListener(ma); + } } catch (Throwable t) { t.printStackTrace(); } + } /** diff --git a/src/javajs/async/Assets.java b/src/javajs/async/Assets.java index b57528b..3650544 100644 --- a/src/javajs/async/Assets.java +++ b/src/javajs/async/Assets.java @@ -1,5 +1,6 @@ package javajs.async; +import java.awt.Toolkit; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -361,7 +362,7 @@ public class Assets { try { URL url = getInstance()._getURLFromPath(path, true); if (url == null && !zipOnly) { - url = Assets.class.getResource(path); + url = Assets.class.getClassLoader().getResource(path); } if (url != null) return url.openStream(); diff --git a/swingjs/SwingJS-site.zip b/swingjs/SwingJS-site.zip index d5e28c1..f722183 100644 Binary files a/swingjs/SwingJS-site.zip and b/swingjs/SwingJS-site.zip differ diff --git a/swingjs/differences.txt b/swingjs/differences.txt new file mode 100644 index 0000000..70eabbc --- /dev/null +++ b/swingjs/differences.txt @@ -0,0 +1,1480 @@ +Notes +===== + +---IMPORTANT CHARACTER SET NOTE--- + +It is critical that all development work in Java2Script +be done in UTF-8. This means: + +- making sure your Eclipse project is set up for UTF-8 (not the Eclipse default?) +- making sure your server can serve up UTF-8 by default for any browser-loaded files +- making sure you don't edit a Java2Script class file or one of the site .js files + using a non-UTF-8 editor. It may replace non-Latin characters with "?" or garbage. +- making sure that your web pages are delivered with proper headings indicating HTML5 and UTF-8 + + + + + + +Note that the DOCTYPE tag is critical for some browsers to switch into HTML5 mode. (MSIE?) + + + + +In particular, the Mandarin character 秘 (mi; "secret") is used extensively throughout +the SwingJS class files to distinguish j2s-specific fields and methods that must not +ever be shadowed or overridden by subclasses. For example, we see in java.lang.Thread.java: + + public static JSThread 秘thisThread; + +---------------------------------- + + +updated 3/21/2020 -- adds note about HashMap, Hashtable, and HashSet iterator ordering +updated 3/20/2020 -- adds note about interning, new String("xxx"), and "xxx" +updated 2/26/2020 -- adds Graphics.setClip issue +updated 12/22/19 -- additional issues +updated 11/03/19 -- adds information about File.exists() and points to src/javajs/async +updated 10/26/19 -- adds information about File.createTempFile() +updated 8/16/19 -- minor typos and added summary paragraph +updated 7/19/19 -- clarification that AWT and Swing classes are supported directly +updated 5/13/19 -- Mandarin U+79D8 reserved character; Missing Math methods; int and long +updated 5/10/19 -- adds a section on static issues in multi-(duplicate)-applet pages +updated 1/4/19 -- nio +updated 9/15/18 -- adds integer 1/0 == Infinity +updated 7/24/18 -- most classes replaced with https://github.com/frohoff/jdk8u-jdk +updated 6/5/17 -- reserved package name "window" +updated 3/11/17 -- myClass.getField +updated 3/7/17 -- overloading of JSplitPane.setDividerLocation +updated 3/2/17 -- more indication of classes not implemented (KeyListener) + +============================================================================= +SwingJS and OpenJDK 8+ +============================================================================= + +SwingJS implements a wide range of the Java language in JavaScript. The base +version for this implementation is OpenJDK8. some classes are implemented using +older source code, and there are some missing methods. For the most part, this is +no real problem. You can add or modify any java class just be adding it as source +in your project. Or (preferably) you can contact me, and I can get it into the +distribution. Or (even more preferably) you can do that via a patch submission. + +================= +DESIGN PHILOSOPHY +================= + +The java2script/SwingJS design goal is to recreate a recognizable, easily debuggable +equivalent in JavaScript for as much of Java as practical. This means, for example, +that one can call in JavaScript + + new java.util.Hashtable() + +and for all practical purposes it will appear that Java is running. + + +Method and Field Disambiguation +------------------------------- + +SwingJS has no problem with the overloading of methods, for example: + + public void print(int b); + public void print(float b); + +JavaScript does not allow overloading of methods, and the common practice in +Java of naming a field the same as a method -- isAllowed and isAllowed() -- is +not possible in JavaScript. As a result, SwingJS implements "fully-qualified" +method names using "$" parameter type separation. Thus, these methods in SwingJS +will be referred to as print$I and print$F. The rules for this encoding are +relatively simple: + +1. The seven primitive types in Java are encoded $I (int), $L (long), $F (float), +$D (double), $B (byte) $Z (boolean), and $H (short). + +2. String and Object are encoded as $S and $O, respectively. + +3. "java_lang_" is dropped for all other classes in the java.lang package (as in Java). + For example: $StringBuffer, not $java_lang_StringBuffer + +4. All other classes are encoded as + + "$" + Class.getName().replace(".","_") + +For example, in Java we see: + + public void equals(Object o) {...} + +Whereas in SwingJS we have: + + Clazz.newMeth(C$, 'equals$O', function (o) {...} + +And + + this.getContentPane().add(bar, "North"); + +becomes + + this.getContentPane$().add$java_awt_Component$O(bar, "North"); + +5. Arrays are indicated with appended "A" for each level. So + + setDataVector(Object[][] dataVector, Object[] columnIdentifiers) + +becomes + + setDataVector$OAA$OA(dataVector, columnIdentifiers) + +(It is recognized that this design does introduce a bit of ambiguity, in that + in principal there could be user class named XA and X in the same package, + and methods a(X[]) and a(XA) in the same class that cannot be distinguished. + The benefit of this simple system, however, triumphed over the unlikelyhood + of that scenario.) The transpiler could be set to flag this possibility. + +6. Constructors are prepended with "c$". So + + public JLabel(String text) {...} + +becomes: + + Clazz.newMeth(C$, 'c$$S', function (text) {...}); + +Field disambiguation involves prepending. In Java, a class and its subclass +can both have the same field name, such as + + boolean visible; + +When this happens, it is called "shadowing", and though not recommended, Java allows +it. The Java2Script transpiler will prepend such shadowing fields with "$" so that the +subclass instance has both "visible" (for use in its methods inherited from its +superclass) and "$visible" (for its own methods). Thus, we might see in Java: + + this.visible = super.visible; + +while in SwingJS we will see: + + this.$visible=this.visible; + +since JavaScript does not have the "super" keyword. + + + +Parameterless methods such as toString() are appended with "$" to become toString$(). +The one exception to this rule is private methods, which are saved in (truly) private +array in the class (and are not accessible by reflection). Private parameterless +methods retain their simple Java name, since they cannot conflict with field names. + +This renaming of methods has a few consequences, which are discussed more fully below. +See particularly the section on "qualified field and method names", where it is described +how you can use packages or classes or interfaces with ".api.js" in them to represent JavaScript +objects for which all method names are to be left unqualified. Note that it is not +possible to cherry-pick methods to be unqualified; only full packages, classes or +interfaces can hold this status. + +The swingjs.api.js package in particular contains a number of useful interfaces that +you can import into your project for JavaScript-specific capabilities. + + +Applet vs. Application +---------------------- + +One of the very cool aspects of SwingJS is that it doesn't particularly matter if a browser-based +Java app is an "applet" or an "application". We don't need JNLP (Java Network Launch Protocol) +because now we can just start up any Java application in a browser just as easily as any applet. +The associative array that passes information to the SwingJS applet (information that formerly +might have been part of the APPLET tag, such as width, height, and codebase, always referred to +in our writing as "the Info array") allows the option to specify the JApplet/Applet "code" +class or the application "main" class. Either one will run just fine. + + +Performance +----------- + +Obviously, there are limitations. One is performance, but we have seen reproducible +performance at 1/6 - 1/3 the speed of Java. Achieving this performance may require +some refactoring of the Java to make it more efficient in both Java and JavaScript. +"for" loops need to be more carefully crafted; use of "new" and "instanceof" need to be +minimized in critical areas. Note that method overloading -- that is, the same method name +with different parameters, such as read(int) and read(byte) -- is no longer any problem. + + +Threads +------- + +Although there is only a single thread in JavaScript, meaning Thread.wait(), Thread.sleep(int) and +Thread.notify() cannot be reproduced, we have found that this is not a serious limitation. +For example, javax.swing.Timer() works perfectly in JavaScript. All it means is that threads +that use sleep(int) or notify() must be refactored to allow Timer-like callbacks. That is, +they must allow full exit and re-entry of Thread.run(), not the typical while/sleep motif. + +The key is to create a state-based run() that can be exited and re-entered in JavaScript. + + +Static fields +------------- + +Final static primitive "constant" fields (String, boolean, int, etc.) such as + +static final int TEST = 3; +static final String MY_STRING = "my " + "string"; + +are converted to their primitive form automatically by the Eclipse Java compiler +and do not appear in the JavaScript by their names. + +Other static fields are properties of their class and can be used as expected. + +Note, however, that SwingJS runs all "Java" code on a page in a common "jvm" +(like older versions of Java). So, like the older Java schema, the JavaScript +equivalents of both applets and applications will share all of their static +fields and methods. This includes java.lang.System. + +Basically, SwingJS implementations of Java run in a browser page-based sandbox +instead of an applet-specific one. + +In general, this is no problem. But if we are to implement pages with +multiple applets present, we must be sure to only have static references +that are "final" or specifically meant to be shared in a JavaScript +environment only (since they will not be shared in Java). + +A simple solution, if static non-constant references are needed, is to attach the +field to Thread.currentThread.threadGroup(), which is an applet-specific reference. +Be sure, if you do this, that you use explicit setters and getters: + +For example, + +private static String myvar; + +... + +public void setMyVar(String x) { + ThreadGroup g = Thread.currentThread().threadGroup(); + /** + * @j2sNative g._myvar = x; + * + */ + { + myvar = x; + } +} + +public String getMyVar() { + ThreadGroup g = Thread.currentThread().threadGroup(); + /** + * @j2sNative return g._myvar || null; + * + */ + { + return myvar; + } +} + + in Java will get and set x the same in JavaScript and in Java. + + +A convenient way to do this in general is to supply a singleton class with +explicitly private-only constructors and then refer to it in Java and in JavaScript +instead of using static field, referring to myclass.getIntance().xxx instead of +myclass.xxx in Java (and JavaScript). + +This was done extensively in the Jalview project. See jalview.bin.Instance. + + +Helper Packages -- swingjs/ and javajs/ +--------------------------------------- + +The SwingJS library is the swingjs/ package. There are interfaces that may be of assistance +in swingjs/api, but other than that, it is not recommended that developers access classes in +this package. The "public" nature of their methods is really an internal necessity. + +In addition to swingjs/, though, there are several useful classes in the javajs/ package +that could be very useful. This package is a stand-alone package that can be +cloned in any Java project that also would be great to have in any JavaScript project +-- SwingJS-related or not. Functionality ranges from reading and writing various file +formats, including PDF, BMP, PNG, GIF, JPG, JSON, ZIP, and CompoundDocument formats. + +A variety of highly efficient three- and four-dimensional point, vector, matrix, and +quaternion classes are included, as they were developed for JSmol and inherited from that +project. + +Of particular interest should be javajs/async/, which includes + +javajs.async.Async +javajs.async.AsyncColorChooser +javajs.async.AsyncDialog +javajs.async.AsyncFileChooser + +See javajs.async.Async JavaDoc comments for a full description of +these useful classes. + + +Modal Dialogs +------------- + +Although true modal dialogs are not possible with only one thread, a functional equivalent -- +asynchronous modal dialogs -- is relatively easy to set up. All the JOptionPane dialogs will +return PropertyChangeEvents to signal that they have been disposed of and containing the results. +See below and classes in the javajs.async package. + + +Native calls +------------ + +Native calls in Java are calls to operating system methods that are not in Java. JavaScript +has no access to these, of course, and they must all be replaced by JavaScript equivalents. +Fortunately, they are not common, and those that are present in Java (for example, in calculating +checksums in ZIP file creation) are at a low enough level that most developers do not utilize them +or do not even have access to them. All native calls in Java classes have been replaced by +Java equivalents. + + +Swing GUI Peers and UIClasses +----------------------------- + +One of the biggest adaptations introduced in SwingJS is in the area of the graphical +user interface. The issue here is complex but workable. In Java there are two background +concepts -- the Component "peer" (one per "heavy-weight" component, such as a Frame) and the +component "uiClass" (one per component, such as JButton or JTextField). + +Peers are native objects of the operating system. These are the virtual buttons and text areas +that the user is interacting with at a very base level. Their events are being passed on to +Java or the browser by the operating system. UI classes provide a consistent "look and feel" +for these native objects, rendering them onto the native window canvas and handling all +user-generated events. They paint the borders, the backgrounds, the highlights, of every +control you see in Java. There is one-to-one correspondence of Swing classes and UI classes. +Setting the Look and Feel for a project amounts to selecting the directory from which to draw +these UI classes. The UI classes can be found in the javax.swing.plaf ("platform look and feel") +package. + +Early on in the development of SwingJS, we decided not to fully reproduce the painfully detailed +bit-by-bit painting of controls as is done in Java. Instead, we felt it was wiser to utilize the standard +HTML5 UI capabilities as much as possible, using DIV, and INPUT especially, with extensive use +of CSS and sometimes jQuery (menus, and sliders, for example). Thus, we have created a new +set of UIs -- the "HTML5 Look and Feel". These classes can be found in swingjs.plaf. Besides being +more adaptable, this approach allows far more versatility to SwingJS developers, allowing them +to modify the GUI to suit their needs if desired. + +In SwingJS, since we have no access to native peers except through the browser DOM, +it seemed logical to merge the peer and UI idea. So instead of having one peer per heavy-weight control and +one UI class instance for each control type, we just have one UI class instance per control, and +that UI class instance is what is being referred to when a "peer" is notified. + +In some ways this is a throw back to when all of Swing's components were subclasses of +specific AWT components such as Button and List. These "heavy-weight components" all had their +own individual native peers and thus automatically took on the look and feel provided by the OS. +Later Swing versions implemented full look and feel for all peers, leaving only JDialog, JFrame, +and a few other classes to have native peers. But in SwingJS we have again a 1:1 map of component +and UI class/peer instance. + +The origin of most issues (read "bugs") in relation to the GUI will probably be found in the +swingjs.plaf JSxxxxUI.java code. + + +Swing-only Components -- no longer an issue +------------------------------------------- + +Swing was introduced into Java well after the Java Abstract Window Toolkit (AWT) was well +established. As such, its designers chose to allow AWT controls such as Button and List to be used +alongside their Swing counterparts JButton and JList. Reading the code, it is clear that this +design choice posed a huge headache for Swing class developers. + +For SwingJS, we decided from the beginning NOT to allow this mixed-mode programming and +instead to require that all components be Swing components. + +However, this is no longer an issue. All AWT components in SwingJS are now subclasses of +javax.swing.JComponent. So far, we have found no problem with this. + + +The a2s Adapter Package +----------------------- + +Originally, we thought that we would restrict ourselves to JApplets only. That is, only +Swing-based applets. But as we worked, we discovered that there are a lot of great +applets out there that are pre-Swing pure-AWT java.applet.Applet applets. Our problem was +that we also wanted it to be possible to quickly adapt these applets to JavaScript as well. + +The solution turned out to be simple: Write a package (a2s) that recreates the interface for +non-Swing components as subclasses of Swing components. Thus, a2s.Button subclasses javax.swing.JButton +but also accepts all of the methods of java.awt.Button. This works amazingly well, with a few +special adaptations to the core javax.swing to be "AWT-aware." All AWT components now subclass +a2s components, which in turn subclass JComponents. So no changes in code are necessary. We have +successfully transpiled over 500 applets using this strategy. (Kind of surprising, actually, that +the original Java developers did not see that option. But we have a hindsight advantage here.) + + +Working with Files +================== + +Simple String file names are not optimal for passing information about +read files within SwingJS applications. + +All work with files should either use Path or File objects exclusively. +These objects, after a file is read or checked for existence, will already +contain the file byte[] data. Doing something like this: + +File f = File("./test.dat"); +boolean isOK = f.exists(); + +will load f with its byte[] data, if the file exists. + +But if after that, we use: + +File f2 = new File(f.getAbsolutePath()); + +f2 will not contain that data. Such copying should be done as: + +File f2 = new File(f); + +in which case, the byte[] data will be transferred. + + +SwingJS uses the following criteria to determine if File.exists() returns true: + +(1) if this File object has been used directly to read data, or +(2) if reading data using this File object is successful. + +Note that you cannot check to see if a file exists before input or if it +was actually written or if it already exists prior to writing in SwingJS. + +Thus, you should check each use of file.exists() carefully, and if necessary, provide a J2sNative +block that gives an appropriate "OK" message, for example: + +(/** @j2sNative 1 ? false : */ outputfile.exits()) + +or + +(/** @j2sNative 1 ? true : */ inputfile.exits()) + +Temporary files can be created in SwingJS. SwingJS will maintain a pseudo-filesystem for files +created with File.createTempFile(). This is useful in that closure of writing to a temporary file +does not generate a pseudo-download to the user's machine. + + +UNIMPLEMENTED CLASSES BY DESIGN +=============================== + +The SwingJS implementation of the following classes are present +in a way that gracefully bypasses their functionality: + +accessibility +security +serialization + + + +TODO LIST FOR UNIMPLEMENTED CLASSES +=================================== + +JEditorPane (minimal implementation) - DONE 12/2018; some issues still +JSplitPane - DONE 8/2018 +JTabbedPane - DONE 10/2018 +JTree - done 12/2019 + + +MINOR ISSUES--required some rewriting/refactoring by Bob and Udo +================================================================ + +Thread.currentThread() == dispatchThread + + +MINOR ISSUES--requiring some rewriting/refactoring outside of SwingJS +===================================================================== + +See below for a full discussion. + +HashMap, Hashtable, and HashSet iterator ordering +interning, new String("xxx") vs "xxx" +Names with "$" and "_" +positive integers do not add to give negative numbers +ArrayIndexOutOfBounds +java.awt.Color +native methods +javax.swing.JFileDialog +key focus +LookAndFeel and UI Classes +System.exit(0) does not stop all processes +list cell renderers must be JComponents +myClass.getField not implemented +"window" and other reserved JavaScript names +reserved field and method names +qualified field and method names +missing Math methods +Component.getGraphics(), Graphics.dispose() +Graphics.setClip() + +MAJOR ISSUES--for Bob and Udo within SwingJS +============================================ + +fonts +OS-dependent classes +AWT component peers +some aspects of reflection + +MAJOR ISSUES--to be resolved by implementers +============================================ + +fonts +threads +modal dialogs +image loading +BigDecimal not fully implemented +no format internationalization +no winding rules +text-related field implementation +Formatter/Regex limitations +integer 1/0 == Infinity + +======================================================================== + +DISCUSS +======= + +Table row/col sorter needs checking after removal of java.text.Collator references + +I had to move all of SunHints class to RenderingHints, or the +two classes could not be loaded. Shouldn't be a problem, I think. The sun classes are +not accessible to developers in Java anyway, since they are generally package private. + +========================================================================== + +////////////////////////////////////////////////////////////////////////////// + +UNIMPLEMENTED CLASSES +===================== + +accessibility +------------- + +All Accessibility handling has been commented out to save the download footprint. +This removes the need for sun.misc.SharedSecrets as well. +Nothing says we could not implement accessibility. We just didn't. + + +security +-------- + +All JavaScript security is handled by the browser natively. +Thus, Java security checking is no longer necessary, and +java.security.AccessController has been simplified to work without +native security checking. + +Note that private methods in a class are REALLY private. + + +serialization +------------- + +All serialization has been removed. It was never very useful for Swing anyway, +because one needs exactly the same Java version to save and restore serialized objects. + + +keyboard accelerators and mnemonics +----------------------------------- + +This work was completed in the spring of 2019. Note that in a browser, some +key strokes, particularly CTRL-keys, are not available. Bummer. + + +MINOR ISSUES--required some rewriting/refactoring by Bob and Udo +================================================================ + + +Thread.currentThread() == dispatchThread +---------------------------------------- + +changed to JSToolkit.isDispatchThread() + + +MINOR ISSUES--requiring some rewriting/refactoring outside of SwingJS +===================================================================== + +HashMap, Hashtable, and HashSet iterator ordering +------------------------------------------------- + +In Java, iterators for HashMap, Hashtable, and HashSet do not guarantee any particular order. +From the HashMap documentation for Java 8: + + This class makes no guarantees as to the order of the map; in particular, it does not + guarantee that the order will remain constant over time. + +Likewise, for HashSet (because it is simply a convenience method for HashMap: + + [HashSet] makes no guarantees as to the iteration order of the set. + +JavaScript's Map object is different. It is basically a LinkedHashMap, so it guarantees iteration +in order of object addition. + +Starting with java2script 3.2.9.v1, these classes use the JavaScript Map object rather than hash codes +whenever all keys are strictly of JavaScript typeof "string". If any key is introduced that is not a string, the +implementation falls back to using hash codes, the same as Java. + +Note strings created using new String("xxxx") are NOT typeof "string"; they are typeof "object". + +The result is significantly faster performance (3-12 x faster) than originally, and up to 3 x faster +performance in JavaScript than in Java itself. Right. Faster than Java. + +The JavaScript Map implementation is implemented UNLESS the constructor used is the one that +specifies both initial capacity and load factor in their constructor. Thus, + +new Hashtable() +new HashMap() +new HashMap(16) +new HashSet() + +all use the JavaScript Map. But + +new Hashtable(11, 0.75f) +new HashMap(16, 0.75f) +new HashSet(16, 0.75f) + +do not. + +This design allows for opting out of the JavaScript Map use in order to retain the exact behavior of +iterators in JavaScript as in Java. + + +interning, new String("xxx") vs "xxx" +------------------------------------- + +Note that the following are true in JavaScript: + +typeof new String("xxxx") == "object" +typeof "xxxx" == "string" +var s = "x";typeof ("xxx" + s) == "string" + +There is no equivalence to this behavior in Java, where a String is a String is a String. + +Be aware that SwingJS does not always create a JavaScript String object using JavaScript's +new String(...) constructor. It only does this for Java new String("xxxx") or new String(new String()). + +In all other cases, new String(...) (in Java) results in a simple "xxxx" string in JavaScript. +That is, it will be JavaScript typeof "string", not typeof "object". + +The reason for this design is that several classes in the Java core use toString() +methods that return new String(), and those classes that do that would cause a JavaScript error +if implicitly stringified if new String() returned a JavaScript String object. + +This is fine in JavaScript + +test1 = function() { return { toString:function(){ return "OK" } } } +"testing" + new test1() +>> "testingOK" + +But for whatever reason in JavaScript: + +test2 = function() { return { toString:function(){ return new String("OK") } } } +"testing" + new test2() +>> Uncaught TypeError: Cannot convert object to primitive value + +The lesson here is never to use + + return new String("..."); + +in a Java toString() method. In Java it will be fine; in JavaScript it will also be fine as long as +that method is never called in JavaScript implicitly in the context of string concatenation. + +A note about interning. Consider the following six Java constructions, where we have a == "x"; + +"xxx" +"xx" + "x" +new String("xxx").intern() + +new String("xxx") +"xx" + a.toString() +"xx" + a + +All six of these will return java.lang.String for .getClass().getName(). +However, the first three are String literals, while the last three are String objects. +Thus: + "xxx" == "xxx" + "xxx" == "xx" + "x" + "xxx" == new String("xxx").intern() + +but none of the other three are equivalent to "xxx" or each other: + + "xxx" != new String("xxx") + "xxx" != "xx" + a.toString() + "xxx" != "xx" + a + new String("xxx") != new String("xxx") + "xx" + a != new String("xxx") + +etc. + +As in Java, in SwingJS, all of the following Java assertions pass as true: + + assert("xxx" == "xx" + "x"); + assert("xxx" == ("xx" + a).intern()); + assert("xxx" === new String("xxx").intern()); + +and both of these do as well: + + assert(new String("xxx") != "xxx"); + assert(new String("xxx") != new String("xxx")); + +But the following two fail to assert true: + + assert("xxx" != "xx" + a); + assert("xxx" != "xx" + a.toString()); + +because in JavaScript, both of these right-side expressions evaluate to a simple "interned" string. + +In Java, however, these assertions are true because Java implicitly "boxes" String +concatentaion as a String object, not a literal. + +Most of us know not to generally use == with Strings unless they are explicitly interned. +Where this problem may arise, though, is in IdentityHashMap, which compares objects using +System.identityHashCode(), which is not the same for different objects or their string literal equivalents. + +My recommendation, if you need to use IdentityHashMap with strings is to always use an explicit String.intern() +for any keys -- unless you really want to keep every string as separate keys even if they are the same sequence, +in which case, use new String(). This will work in Java and in JavaScript. + +Be aware when working with strings that come from SwingJS and are being used by other JavaScript modules +that those that are String objects will return "object" for the JavaScript typeof operator, not "string". + +The easy way to ensure this is no problem is to concatenate strings with "" to force immediate interning: + + var x = aJavaObject.getString() + ""; + +unless you are certain that the string is being returned is a raw JavaScript string. + +Names with "$" and "_" +---------------------- + +For the most part, this should be no problem. + +Note that the use of $ and _ in Java field names has always been discouraged: +[https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html] + + You may find some situations where auto-generated names will contain the dollar sign, + but your variable names should always avoid using it. A similar convention + exists for the underscore character; while it's technically legal to begin your + variable's name with "_", this practice is discouraged. + +Some impacts of transpiling method names with full qualification: + +1) SwingJS will introduce fields that start with $ or _. These will not conflict + if the above convention is followed. + +2) Fields that have the same Java name as a method are not an issue. + +3) Fields that have a Java name with $ that matches a transpiled method name, + such as toString$, will need to be refactored in Java to not have that name collision. + +4) Fields in a subclass that have the same name as private fields in a superclass + represent a name collision, because the superclass method needs to call its private + field even if invoked from a subclass. The solution was to modify the subclass field + name using one or more prepended $. + +5) Use of Class.getDeclaredMethods() reflection will return Method objects having the transpiled + name, not the Java name. This could require some j2sNative adjustment + to strip the $... parameters from the name if that is needed. + +6) Use of Method.getParameterTypes() should work fine, provided class names + do not contain "_". This is because the transpiler converts "." to "_" when + creating the fully qualified JavaScript name. + + +positive integers do not add to give negative numbers +----------------------------------------------------- + +In Java, the following is true: + + 2000000000 + 2000000000 == -294967296 + +But in SwingJS, that will be 4000000000. So, for example, the following +strategy will fail in SwingJS: + + int newLength = lineBuf.length * 2; + if (newLength < 0) { + newLength = Integer.MAX_VALUE; + } + +"-1" in JavaScript is not 0xFFFFFFFF. + +And one must take care to not compare a negative number with a 32-bit mask. So + +(b & 0xFF000000) == 0xFF000000 + +is true in Java for (int) b = -1, but is false in JavaScript, because 0xFF000000 is 4278190080, +while (-1 & 0xFF000000) is, strangely enough, -16777216, and, in fact, + +(0xFF000000 & 0xFF000000) != 0xFF000000 + +because -16777216 is not 4278190080. + +The fix is that one must compare similar operations: + +if ((b & 0xFF000000) == (0xFF000000 & 0xFF000000)) ..... + +Importantly, the JavaScript Int32Array does behave properly. From +the Firefox developer console: + +>> x = new Int32Array(1) +<- Int32Array(1) [ 0 ] +>> x[0] = 4000000000 +<- 4000000000 +>> x[0] +<- -294967296 + +Notice that, perhaps unexpectedly, the following two constructs produce +different results in JavaScript: + +x = new Int32Array(1); +b = x[0] = 4000000000; + +(b will be 4000000000) + +and + +x = new Int32Array(1); +x[0] = 4000000000; +b = x[0]; + +(b will be -294967296) + + +SwingJS leverages array typing to handle all byte and short arithmetic so as +to ensure that any byte or short operation in JavaScript does give the same +result in Java. The design decision to not also do this with integer math was +a trade-off between performance and handling edge cases. + + +ArrayIndexOutOfBounds +--------------------- + +You cannot implicitly throw an ArrayIndexOutOfBoundsException in JavaScript. +JavaScript will simply return "undefined", not throw an Exception. So: + +boolean notAGoodIdeaIsOutOfBounds(String[] sa, int i) { + try { + return (sa[i] == sa[i]); + } catch (ArrayIndexOutOfBoundsException e) { + return false; + } +} + +will work in Java but not in JavaScript. Code should not depend upon this sort +of trap anyway, if you ask me. + +Throwable vs Error vs Exception +------------------------------- + +True JavaScript errors are trapped as Throwable, whereas you can still trap +Error and Exception as well. So if you want to be sure to catch any JavaScript +error, use try{}catch (Throwable t){}, not try{}catch (Exception e){}. + +j +ava.awt.Color +-------------- + +ColorSpace: only "support" CS_sRGB. + + TODO -- any volunteers?? + + +javax.swing.JFileDialog +----------------------- + +HTML5 cannot expose a file reading directory structure. But you certainly +can still do file reading and writing. It just works a little differently. +It's a simple modification: + + b = new JButton("FileOpenDialog"); + b.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + JFileChooser fc = new JFileChooser(); + Test_Dialog.this.onDialogReturn(fc.showOpenDialog(Test_Dialog.this)); + // Java will wait until the dialog is closed, then enter the onDialogReturn method. + // JavaScript will exit with NaN immediately, and then call back with its actual value + // asynchronously. + } + + }); + + public void onDialogReturn(int value) { + if (value != Math.floor(value)) + return; // in JavaScript, this will be NaN, indicating the dialog has been opened + // If we are here, the dialog has closed, in both Java and JavaScript. + System.out.println("int value is " + value); + } + + + @Override + public void propertyChange(PropertyChangeEvent event) { + Object val = event.getNewValue(); + String name = event.getPropertyName(); + System.out.println(name); + switch (event.getSource().getClass().getName()) { + case "javax.swing.JOptionPane": + switch (name) { + case "inputValue": + onDialogReturn(val); + return; + case "value": + if (val instanceof Integer) + onDialogReturn(((Integer) val).intValue()); + else + onDialogReturn(val); + return; + } + break; + case "javax.swing.ColorChooserDialog": + switch (name) { + case "SelectedColor": + onDialogReturn(val); + return; + } + break; + case "javax.swing.JFileChooser": + switch (name) { + case "SelectedFile": + File file = (File) val; + byte[] array = (val == null ? null : /** @j2sNative file.秘bytes || */ + null); + onDialogReturn("fileName is '" + file.getName() + "'\n\n" + new String(array)); + return; + } + break; + } + System.out.println( + event.getSource().getClass().getName() + " " + event.getPropertyName() + ": " + event.getNewValue()); + } + + +Developers are encouraged to create a separate class that handles general calls to JFileDialog. +An example class can be found in the SwingJS distribution as + +/sources/net.sf.j2s.java.core/src/javajs/async/AsyncFileChooser.java. + + +javax.swing.JOptionPane dialogs +------------------------------- + +For this action to work, the parentComponent must implement +propertyChangeListener, and any call to JOptionPanel should allow for +an asynchronous response, meaning that there is no actionable code following the +call to the dialog opening. + +In addition, for compatibility with the Java version, implementation should +wrap the call to getConfirmDialog or getOptionDialog in a method call to +handle the Java: + +onDialogReturn(JOptionPane.showConfirmDialog(parentFrame, +messageOrMessagePanel, "title", JOptionPane.OK_CANCEL_OPTION)); + +Then parentFrame.propertyChange(event) should also call onDialogReturn. + +This will then work in both Java and JavaScript. + +Note that there is an int and an Object version of onDialogReturn(). + + +In JavaScript: + +The initial return from JOptionPane.showConfirmDialog and showMessageDialog +will be (SwingJS) JDialog.ASYNCHRONOUS_INTEGER (NaN), testable as an impossible +Java int value using ret != -(-ret) if the parent implements PropertyChangeListener, or -1 +(CLOSE_OPTION) if not. + +For showOptionDialog (which returns Object) or showInputDialog (which returns +String), the initial return will be (SwingJS) JDialog.ASYNCHRONOUS_OBJECT, testable as +((Object) ret) instanceof javax.swing.plaf.UIResource if the parent implements +PropertyChangeListeneer, or null if not. + +The second return will be the desired return. + +In Java: + +The initial return will be the one and only modal final return. + + + +For full compatibility, The calling method must not continue beyond this +call. + +All of the standard Java events associated with Components are also +available. + +Certain fall back mechanisms are possible, where onReturn does not exist, but +only for the following cases: + + +For showMessageDialog, for WARNING_MESSAGE and ERROR_MESSAGE, a simple +JavaScript alert() is used, returning 0 (OK_OPTION) or -1 (CLOSED_OPTION). + +For showInputDialog, if the message is a string, a simple JavaScript prompt() +with input box is used, returning the entered string or null. + +For showConfirmDialog, a simple JavaScript confirm() is used, in which case: + +for YES_NO_OPTION: YES_OPTION or NO_OPTION + +for YES_NO_CANCEL_OPTION: YES_OPTION or CANCEL_OPTION + +for OK_CANCEL_OPTION or any other: OK_OPTION or CANCEL_OPTION + +Note that you should implement a response for CLOSED_OPTION for +showConfirmDialog. For other dialogs, a null return indicates the dialog was +closed, just as for Java. + +Developers are encouraged to create a separate class that handles general calls. +An example class can be found in the SwingJS distribution as src/javajs/async/AsyncDialog.java. +Very simple modifications to the Java allows asynchronous operation using AsyncDialog. Here +is a simple "do you want to close this frame" example, where you can see that what we have +done is to set the reply into an ActionListener that is defined in the constructor of +the AsyncDisplay object: + +// Original: +// +// private void promptQuit() { +// int sel = JOptionPane.showConfirmDialog(null, PROMPT_EXIT, NAME, JOptionPane.YES_NO_OPTION); +// switch (sel) { +// case JOptionPane.YES_OPTION: +// resultsTab.clean(); +// seqs.dispose(); +// if (fromMain) { +// System.exit(0); +// } +// break; +// } +// } + + private void promptQuitAsync() { + new AsyncDialog(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + int sel = ((AsyncDialog)e.getSource()).getOption(); + switch (sel) { + case JOptionPane.YES_OPTION: + resultsTab.clean(); + seqs.dispose(); + if (fromMain) { + System.exit(0); + } + break; + } + }}).showConfirmDialog(null, PROMPT_EXIT, NAME, JOptionPane.YES_NO_OPTION); + } + +Very simple! + + +native methods +-------------- + +The J2S compiler ignores all static native method declarations. +Anything of this nature needs to be implemented in JavaScript if it is needed, +using j2sNative blocks: + +/** + * @j2sNative + * + * var putYourJavaScriptCodeHere + * + */ + + Note that if you follow that directly with a {...} block, then + the javadoc code will run in JavaScript, and the {...} code will run in Java. + + +key Focus +--------- + +As of June, 2019, the keyboard focus manager is fully implemented. +The one catch is that JTextPane and JTextArea, which already consume +VK_TAB in Java, cannot use CTRL-TAB to continue a tabbing cycle around +the components in a window. Instead, CTRL-TAB is absorbed by the browser. + + +LookAndFeel and UI Classes +-------------------------- + +SwingJS implements the native browser look and feel as swingjs.plaf.HTML5LookAndFeel. +There are small differences between all look and feels -- MacOS, Windows, SwingJS. + +Expert developers know how to coerce changes in the UI by subclassing the UI for a +component. This probably will not work in SwingJS. + +Note that LookAndFeel in Java usually determines canvas size in a Frame because +different operating systems (Mac OS vs Windows vs HTML5) will have +different edge sizes on their frames. If you want to ensure a component size, +use getContentPane().setPreferredSize(). + + +System.exit(0) does not stop all processes +------------------------------------------ + +Although System.ext(int) has been implemented in JavaScript, it just closes the +frames, stops all pending javax.swing.Timer objects in the queue, and runs any +threads added using Runtime.getRuntime().addShutdownHook(Thread). +It may not stop all "threads." So don't rely on that. +Applications are responsible for shutting down prior to executing System.exit(0). + + +myClass.getField not implemented +-------------------------------- + +java.lang.reflect.Field is implemented minimally. It is not +certain that Field.getDeclaringClass() will work. If you just want a +value of a field, you can do this: + +/** + *@j2sNative + * + * return myClass[name] + */ + +But that is not a java.lang.reflection.Field object. + + +"window" and other reserved JavaScript names +-------------------------------------------- + +No reserved top-level JavaScript name is allowed for a package name. So, for example, +one must rename packages such as "window" or "document" to names such as "win" or "doc". + +reserved field and method names +------------------------------- + +In order to minimize the chance of added SwingJS field and method names colliding with ones +developers might use in subclassing Java classes, we have added U+79D8 (first character of Mandarin +"secret") to the characters already disrecommended by Java documentation ("$" and "_"). The only problem +would be if you use that character followed by certain English words in certain classes. For example +\u79D8canvas for JComponents (in java.awt.JSComponent) and \u79D8byte (in java.io.File). + +qualified field and method names +-------------------------------- + +Method names in SwingJS are fully qualified, meaning two methods with the same Java name but different +parameters, such as write(int) and write(double), must not have the same name in JavaScript. (In this +case, we will have write$I and write$D.) However, in certain cases it may be desirable to leave the +method names unqualified. In particular, when an interface actually represents a JavaScript object, +the transpiler can leave a method name unqualified. The default situation for this is a class name +includes ".api.js" (case-sensitive). This means that any method in any class in a package js within +a package api, or any private interface js that has an outer interface api, will have all-unqualified +methods. An example of this is swingjs.plaf.JSComboPopupList, which needs to communicate with a jQuery +object directly using the following interface: + + private interface api { + + interface js extends JQueryObject { + + abstract js j2sCB(Object options); + + abstract Object[] j2sCB(String method); + + abstract Object[] j2sCB(String method, Object o); + + abstract Object[] j2sCB(String method, int i); + + abstract int j2sCB(String OPTION, String name); + + } + } + +Notice that all these variants of j2sCB() will call the same method in JavaScript by design. + + +missing Math methods +-------------------- + +java.lang.Math is worked out, but some methods are missing, either because they +involve long integer value that are inaccessible in JavaScript, or because I just +didn't implement them. This is a result of continued Java development. +It is easy enough to add these methods if you have the source. They go into j2sClazz.js, +which is combined with other initial libraries into swingjs2.js by build_site.xml + + +Component.getGraphics(), Graphics.dispose() +------------------------------------------- + +Use of component.getGraphics() is discouraged in Java and in SwingJS. +Specifically in SwingJS, any call to component.getGraphics() or +BufferedImage.createGraphics() or Graphics.create(...) should be matched with graphics.dispose(), +particularly when it is called outside the context of a paint(Graphics) +call from the system. + +If you see your graphics scrolling down the page with each repaint, +look for where you have used Component.getGraphics() and not Graphics.dispose(). +For example, this will definitely NOT work in SwingJS: + + this.paint(getGraphics()) + +and really should not work in Java, either, as it is technically a resource memory leak. + +Instead, if you really do not want to use repaint(), use this: + + Graphics g = getGraphics(); + paint(g); + g.dispose(); + + + +Graphics.setClip() +------------------ + +The HTML5 canvas.clip() method is permanent. You can only reset the clip using +save/restore. This is different from Java, where you can temporarily change it using + + Shape oldClip = Graphics.getClip(); + Graphics.setClip(newClip); + ... + Graphics.setClip(oldClip); + +If you need to do something like this, you must schedule the paints +to not have overlapping clip needs. + + +MAJOR ISSUES--for Bob and Udo within SwingJS +============================================ + +fonts +----- + +Fonts and FontMetrics will all be handled in JavaScript. Font matching will +not be exact, and composite (drawn) fonts will not be supported. + +SwingJS handles calls such as font.getFontMetrics(g).stringWidth("xxx") by +creating a
containing that text, placing it in an obscure location on +the page, and reading div.getBoundingClientRect(). This is a VERY precise +value, but can be a pixel or two off from what Java reports for the same font. + + +OS-dependent classes +-------------------- + +Static classes such as: + + java.awt.Toolkit + java.awt.GraphicsEnvironment + + +which are created using Class.forName are implemented using classes in the swingjs package. + +AWTAccessor is not implemented. + + +AWT component peers and component "ui" user interfaces +------------------------------------------------------ + +ComponentPeer is a class that represents a native AWT component. +Components with such peers are called "heavy-weight" components. +They are expected to do the dirty work of graphics drawing. + +Java Swing implements peers only for JApplet, JDialog, JFrame, and JWindow. +References to such objects have been removed, but clearly there must be +some connection to similar DOM objects, even for "light-weight" components. + + + +MAJOR ISSUES--to be resolved by implementers +============================================ + +fonts +----- + +Glyph/composite/outline fonts are not supported. + + + +threads +------- + +Thread locking and synchronization are not relevant to JavaScript. +Thus, anything requiring "notify.." or "waitFor.." could be a serious issue. + +All threading must be "faked" in JavaScript. Specifically not available is: + + Thread.sleep() + +javax.swing.AbstractButton#doClick(pressTime) will not work, as it requires Thread.sleep(); + +However, java.lang.Thread itself is implemented and used extensively. + +Methods thread.start() and thread.run() both work fine. + +For simple applications that use Thread.sleep() just to have a delay, as in a frame rate, for +example, one can use javax.swing.Timer instead. That is fully implemented. + +Likewise, java.util.Timer can be replaced with no loss of performance with javax.Swing.Timer. +Note that java.util.TimerTask is implemented, but it can also be replaced by an implementation of Runnable. + +task = new TimerTask(){....}; +t = new java.util.Timer(); +t.schedule(task, 0, 1); + +becomes + +task = new TimerTask(){....}; // or task = new Runnable() {...} +t = new javax.swing.Timer(1, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + task.run(); + } +}; +t.setInitialDelay(0); // not particularly necessary +t.start(); + +In addition, SwingJS provides swingjs.JSThread, which can be subclassed +if desired. This class allows simple + + while(!interrupted()){ + wait() + ... + } + +action through an asynchronous function run1(mode). For example: + + protected void run1(int mode) { + try { + while (true) + switch (mode) { + case INIT: + // once-through stuff here + mode = LOOP; + break; + case LOOP: + if (!doDispatch || isInterrupted()) { + mode = DONE; + } else { + Runnable r = new Runnable() { + public void run() { + // put the loop code here + } + }; + dispatchAndReturn(r); + if (isJS) + return; + } + break; + // add more cases as needed + case DONE: + // finish up here + if (isInterrupted()) + return; + // or here + break; + } + } finally { + // stuff here to be executed after each loop in JS or at the end in Java + } + } + +image loading +------------- +- All image loading in SwingJS is synchronous. A MediaTracker call will immediately return "complete". + However, it still may take one system clock tick to fully load images. Thus, it is recommended that + images be preloaded in the static block of the applet if it is necessary that they be available in init(). + This is only an issue if you are trying to access the pixel buffer of the image in JavaScript. + +- Applet.getImage(path, name) will return null if the image does not exist. + +- BufferedImage: only "support" imageType RGB and ARGB + + -BH: This is a temporary edit, just to get us started. Certainly GRAY will be needed + + +BigInteger and BigDecimal +------------------------- + +java.math.BigInteger is fully supported; java.math.BigDecimal is roughed +in and not fully tested (07/2019). + +Both classes present significant issues for JavaScript, as they are based in +Java's 64-bit long for all their operations. Here is the JavaDoc note I added +to BigInteger: + + * SwingJS note: Because of the limitations of JavaScript with regard + * to long-integer bit storage as a double, this implementation drops + * the integer storage bit length to 24, giving 48 for long and leaving + * the last 16 bits clear for the exponent of the double number. This should + * not affect performance significantly. It does increase the storage + * size by about 33%. By bringing an "int" to 3 bytes, we can easily construct + * and use byte[] data intended for the original BitSet. + +"Easily" may be a bit strong there. This was a serious challenge. + +BigDecimal seems to run normally, but in order to do that, my hack involves +reducing the size of an integer that is allowed to be stored as such and not +in byte[] as a BigInteger. I'm sure there is a performance hit, but it does work. + +no format internationalization +------------------------------ + +For now, just en for number and date formatters + +no winding rules +---------------- + + When filling a graphic, only nonzero winding rule is implemented in HTML5 Canvas2D. + + + +text-related field implementation +--------------------------------- + +Text fields are: + +JTextField (JavaScript ) +JTextArea (JavaScript