From 2cbf9d005db462396fa1dc0750aa63a2e6cd0735 Mon Sep 17 00:00:00 2001 From: Jim Procter Date: Wed, 11 Jul 2018 13:25:36 +0100 Subject: [PATCH] JAL-3048 refactored export settings to bean+dialog with callbacks - basically works but could do with more cleanup --- src/jalview/api/AlignExportSettingI.java | 51 ++-- src/jalview/bin/Jalview.java | 3 +- src/jalview/datamodel/AlignExportSettingBeanI.java | 52 +++++ src/jalview/gui/AlignExportSettings.java | 144 +++++++++--- src/jalview/gui/AlignFrame.java | 246 ++++++++++---------- src/jalview/io/HTMLOutput.java | 44 +++- src/jalview/io/JSONFile.java | 5 +- src/jalview/jbgui/GAlignExportSettings.java | 27 --- 8 files changed, 339 insertions(+), 233 deletions(-) create mode 100644 src/jalview/datamodel/AlignExportSettingBeanI.java diff --git a/src/jalview/api/AlignExportSettingI.java b/src/jalview/api/AlignExportSettingI.java index 18f529b..31d0940 100644 --- a/src/jalview/api/AlignExportSettingI.java +++ b/src/jalview/api/AlignExportSettingI.java @@ -21,53 +21,30 @@ package jalview.api; +import jalview.datamodel.AlignExportSettingBeanI; +import jalview.datamodel.AlignmentExportData; + +import java.awt.event.ActionListener; + /** - * Abstract interface implemented by Alignment Export dialog to retrieve user - * configurations - * - * @author tcnofoegbu + * additional methods implemented by the export settings dialog * */ -public interface AlignExportSettingI +public interface AlignExportSettingI extends AlignExportSettingBeanI { - /** - * Checks if hidden sequences should be exported - * - * @return - */ - public boolean isExportHiddenSequences(); + AlignmentExportData getAlignExportData(); + /** - * Checks if hidden columns shoulb be exported - * - * @return + * the export data action to be performed - make sure you check isCancelled in this method first + * @param actionListener */ - public boolean isExportHiddenColumns(); - /** - * Checks if Annotations should be exported, note this is available for - * complex flat file exports like JSON, HTML, GFF - * - * @return - */ - public boolean isExportAnnotations(); + public void addActionListener(ActionListener actionListener); /** - * Checks if SequenceFeatures should be exported, note this is available for - * complex flat file exports like JSON, HTML, GFF - * - * @return + * show the dialog */ - public boolean isExportFeatures(); - - /** - * Checks if SequenceGroups should be exported, note this is available for - * complex flat file exports like JSON, HTML, GFF - * - * @return - */ - public boolean isExportGroups(); - - public boolean isCancelled(); + public void doShowSettings(); } diff --git a/src/jalview/bin/Jalview.java b/src/jalview/bin/Jalview.java index 018adb1..e890cb8 100755 --- a/src/jalview/bin/Jalview.java +++ b/src/jalview/bin/Jalview.java @@ -749,7 +749,8 @@ public class Jalview continue; } - if (af.saveAlignment(file, format)) + af.saveAlignment(file, format); + if (af.isSaveAlignmentSuccessful()) { System.out.println("Written alignment in " + format + " format to " + file); diff --git a/src/jalview/datamodel/AlignExportSettingBeanI.java b/src/jalview/datamodel/AlignExportSettingBeanI.java new file mode 100644 index 0000000..77b704e --- /dev/null +++ b/src/jalview/datamodel/AlignExportSettingBeanI.java @@ -0,0 +1,52 @@ +package jalview.datamodel; + +/** + * * Abstract interface implemented by Alignment Export dialog to retrieve user + * configurations + * + * @author tcnofoegbu + * + */ +public interface AlignExportSettingBeanI +{ + + /** + * Checks if hidden sequences should be exported + * + * @return + */ + public boolean isExportHiddenSequences(); + + /** + * Checks if hidden columns shoulb be exported + * + * @return + */ + public boolean isExportHiddenColumns(); + + /** + * Checks if Annotations should be exported, note this is available for + * complex flat file exports like JSON, HTML, GFF + * + * @return + */ + public boolean isExportAnnotations(); + + /** + * Checks if SequenceFeatures should be exported, note this is available for + * complex flat file exports like JSON, HTML, GFF + * + * @return + */ + public boolean isExportFeatures(); + + /** + * Checks if SequenceGroups should be exported, note this is available for + * complex flat file exports like JSON, HTML, GFF + * + * @return + */ + public boolean isExportGroups(); + + public boolean isCancelled(); +} diff --git a/src/jalview/gui/AlignExportSettings.java b/src/jalview/gui/AlignExportSettings.java index 201570e..fbe12d8 100644 --- a/src/jalview/gui/AlignExportSettings.java +++ b/src/jalview/gui/AlignExportSettings.java @@ -21,16 +21,20 @@ package jalview.gui; import jalview.api.AlignExportSettingI; +import jalview.api.AlignViewportI; import jalview.bin.Jalview; +import jalview.datamodel.AlignExportSettingBeanI; +import jalview.datamodel.AlignmentExportData; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.HiddenSequences; import jalview.io.FileFormatI; import jalview.jbgui.GAlignExportSettings; import jalview.util.MessageManager; +import jalview.util.dialogrunner.RunResponse; import java.awt.event.ActionEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; +import java.awt.event.ActionListener; -import javax.swing.JDialog; import javax.swing.JOptionPane; @SuppressWarnings("serial") @@ -39,86 +43,154 @@ public class AlignExportSettings extends GAlignExportSettings { boolean cancelled = false; - JDialog dialog; + JvOptionPane dialog; - public AlignExportSettings(boolean hasHiddenSeq, boolean hasHiddenCols, - FileFormatI format) + AlignmentPanel alignPanel; + + /** + * settings provided at construction override the GUI + */ + AlignExportSettingBeanI override=null; + + public AlignExportSettings(AlignmentPanel alignmentPanel, + FileFormatI format, AlignExportSettingBeanI exportSettings) { - super(hasHiddenSeq, hasHiddenCols, format); - if (!Jalview.isHeadlessMode() && isShowDialog()) - { + super(alignmentPanel.getAlignViewport().hasHiddenRows(), + alignmentPanel.getAlignViewport().hasHiddenColumns(), format); + this.alignPanel = alignmentPanel; + override = exportSettings; + } + + /** + * @param viewport + * @return a bean with data for export + */ + @Override + public AlignmentExportData getAlignExportData() + { + // settings.isExportAnnotations(); - JOptionPane pane = new JOptionPane(null, JOptionPane.DEFAULT_OPTION, - JvOptionPane.DEFAULT_OPTION, null, new Object[] - { this }); - dialog = pane.createDialog(Desktop.desktop, - MessageManager.getString("label.export_settings")); - dialog.addWindowListener(new WindowAdapter() - { - @Override - public void windowClosing(WindowEvent e) - { - cancelled = true; - } - }); - dialog.pack(); - dialog.setVisible(true); - dialog.setContentPane(this); - dialog.validate(); + AlignmentI alignmentToExport = null; + String[] omitHidden = null; + AlignViewportI viewport = alignPanel.getAlignViewport(); + + alignmentToExport = viewport.getAlignment(); + if (viewport.hasHiddenColumns() && !isExportHiddenColumns()) + { + omitHidden = viewport.getViewAsString(false, + isExportHiddenSequences()); + } + + int[] alignmentStartEnd = new int[2]; + if (viewport.hasHiddenRows() && isExportHiddenSequences()) + { + alignmentToExport = viewport.getAlignment().getHiddenSequences() + .getFullAlignment(); + } + else + { + alignmentToExport = viewport.getAlignment(); } + alignmentStartEnd = viewport.getAlignment().getHiddenColumns() + .getVisibleStartAndEndIndex(alignmentToExport.getWidth()); + AlignmentExportData ed = new AlignmentExportData(alignmentToExport, + omitHidden, alignmentStartEnd, this); + return ed; } @Override public void ok_actionPerformed(ActionEvent e) { cancelled = false; - dialog.setVisible(false); - dialog.dispose(); } @Override public void cancel_actionPerformed(ActionEvent e) { cancelled = true; - dialog.setVisible(false); - dialog.dispose(); } @Override public boolean isExportHiddenSequences() { - return chkHiddenSeqs.isSelected(); + return override!=null ? override.isExportHiddenSequences() : chkHiddenSeqs.isSelected(); } @Override public boolean isExportHiddenColumns() { - return chkHiddenCols.isSelected(); + return override!=null ? override.isExportHiddenColumns() : chkHiddenCols.isSelected(); } @Override public boolean isExportAnnotations() { - return chkExportAnnots.isSelected(); + return override!=null ? override.isExportAnnotations() : chkExportAnnots.isSelected(); } @Override public boolean isExportFeatures() { - return chkExportFeats.isSelected(); + return override!=null ? override.isExportFeatures() : chkExportFeats.isSelected(); } @Override public boolean isExportGroups() { - return chkExportGrps.isSelected(); + return override!=null ? override.isExportGroups() : chkExportGrps.isSelected(); } @Override public boolean isCancelled() { - return cancelled; + return override!=null ? override.isCancelled() : cancelled; + } + + ActionListener afterShownAction = null; + + @Override + public void addActionListener(ActionListener actionListener) + { + afterShownAction = actionListener; + } + + @Override + public void doShowSettings() + { + if (!Jalview.isHeadlessMode() && override==null && isShowDialog()) + { + + dialog = JvOptionPane.newOptionDialog(alignPanel); + + dialog.response(new RunResponse(JvOptionPane.OK_OPTION) + { + public void run() + { + ok_actionPerformed(null); + afterShownAction.actionPerformed(null); + } + }).defaultResponse(new Runnable() + { + @Override + public void run() + { + cancelled=true; + afterShownAction.actionPerformed(null); + } + }); + String ok = MessageManager.getString("action.ok"), + cancel = MessageManager.getString("action.cancel"); + dialog.showInternalDialog(this, + MessageManager.getString("label.export_settings"), + JOptionPane.DEFAULT_OPTION, JvOptionPane.DEFAULT_OPTION, null, + new Object[] + { ok, cancel }, ok); + } + else + { + afterShownAction.actionPerformed(null); + } } } diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index af00998..1401a28 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -45,6 +45,7 @@ import jalview.commands.RemoveGapColCommand; import jalview.commands.RemoveGapsCommand; import jalview.commands.SlideSequencesCommand; import jalview.commands.TrimRegionCommand; +import jalview.datamodel.AlignExportSettingBeanI; import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; @@ -54,7 +55,6 @@ import jalview.datamodel.AlignmentOrder; import jalview.datamodel.AlignmentView; import jalview.datamodel.ColumnSelection; import jalview.datamodel.HiddenColumns; -import jalview.datamodel.HiddenSequences; import jalview.datamodel.PDBEntry; import jalview.datamodel.SeqCigar; import jalview.datamodel.Sequence; @@ -1200,10 +1200,45 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, }).showSaveDialog(this); } - public boolean saveAlignment(String file, FileFormatI format) + private boolean lastSaveSuccessful = false; + + private FileFormatI lastFormatSaved; + + private String lastFilenameSaved; + + /** + * Raise a dialog or status message for the last call to saveAlignment. + * + * @return true if last call to saveAlignment(file, format) was successful. + */ + public boolean isSaveAlignmentSuccessful() { - boolean success = true; + if (!lastSaveSuccessful) + { + JvOptionPane.showInternalMessageDialog(this, MessageManager + .formatMessage("label.couldnt_save_file", new Object[] + { lastFilenameSaved }), + MessageManager.getString("label.error_saving_file"), + JvOptionPane.WARNING_MESSAGE); + } + else + { + + statusBar.setText(MessageManager.formatMessage( + "label.successfully_saved_to_file_in_format", new Object[] + { lastFilenameSaved, lastFormatSaved })); + + } + return lastSaveSuccessful; + } + + public void saveAlignment(String file, FileFormatI format) + { + lastSaveSuccessful = false; + lastFilenameSaved = file; + lastFormatSaved = format; + AlignFrame us = this; if (FileFormat.Jalview.equals(format)) { String shortName = title; @@ -1214,66 +1249,66 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, shortName.lastIndexOf(java.io.File.separatorChar) + 1); } - success = new Jalview2XML().saveAlignment(this, file, shortName); - - statusBar.setText(MessageManager.formatMessage( - "label.successfully_saved_to_file_in_format", new Object[] - { fileName, format })); - + lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file, + shortName); } else { - AlignmentExportData exportData = getAlignmentForExport(format, - viewport, null); - if (exportData.getSettings().isCancelled()) + AlignExportSettingI settings = getAlignmentForExport(format, + alignPanel, null); + settings.addActionListener(new ActionListener() { - return false; - } - FormatAdapter f = new FormatAdapter(alignPanel, - exportData.getSettings()); - String output = f.formatSequences(format, exportData.getAlignment(), // class - // cast - // exceptions - // will - // occur in the distant future - exportData.getOmitHidden(), exportData.getStartEndPostions(), - f.getCacheSuffixDefault(format), - viewport.getAlignment().getHiddenColumns()); - - if (output == null) - { - success = false; - } - else - { - try - { - PrintWriter out = new PrintWriter(new FileWriter(file)); - - out.print(output); - out.close(); - this.setTitle(file); - statusBar.setText(MessageManager.formatMessage( - "label.successfully_saved_to_file_in_format", new Object[] - { fileName, format.getName() })); - } catch (Exception ex) + @Override + public void actionPerformed(ActionEvent e) { - success = false; - ex.printStackTrace(); + + if (settings.isCancelled()) + { + lastSaveSuccessful = false; + return; + } + AlignmentExportData exportData = settings.getAlignExportData(); + FormatAdapter f = new FormatAdapter(alignPanel, + exportData.getSettings()); + String output = f.formatSequences(format, + exportData.getAlignment(), // class + // cast + // exceptions + // will + // occur in the distant future + exportData.getOmitHidden(), + exportData.getStartEndPostions(), + f.getCacheSuffixDefault(format), + viewport.getAlignment().getHiddenColumns()); + + if (output == null) + { + lastSaveSuccessful = false; + } + else + { + try + { + PrintWriter out = new PrintWriter(new FileWriter(file)); + + out.print(output); + out.close(); + us.setTitle(file); + statusBar.setText(MessageManager.formatMessage( + "label.successfully_saved_to_file_in_format", + new Object[] + { fileName, format.getName() })); + } catch (Exception ex) + { + lastSaveSuccessful = false; + ex.printStackTrace(); + } + } } - } - } + }); - if (!success) - { - JvOptionPane.showInternalMessageDialog(this, MessageManager - .formatMessage("label.couldnt_save_file", new Object[] - { fileName }), - MessageManager.getString("label.error_saving_file"), - JvOptionPane.WARNING_MESSAGE); + settings.doShowSettings(); } - - return success; } /** @@ -1287,75 +1322,50 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { FileFormatI fileFormat = FileFormats.getInstance() .forName(e.getActionCommand()); - AlignmentExportData exportData = getAlignmentForExport(fileFormat, - viewport, null); - if (exportData.getSettings().isCancelled()) + AlignExportSettingI settings = getAlignmentForExport(fileFormat, + alignPanel, null); + settings.addActionListener(new ActionListener() { - return; - } - CutAndPasteTransfer cap = new CutAndPasteTransfer(); - cap.setForInput(null); - try - { - FileFormatI format = fileFormat; - cap.setText(new FormatAdapter(alignPanel, exportData.getSettings()) - .formatSequences(format, exportData.getAlignment(), - exportData.getOmitHidden(), - exportData.getStartEndPostions(), - viewport.getAlignment().getHiddenColumns())); - Desktop.addInternalFrame(cap, MessageManager - .formatMessage("label.alignment_output_command", new Object[] - { e.getActionCommand() }), 600, 500); - } catch (OutOfMemoryError oom) - { - new OOMWarning("Outputting alignment as " + e.getActionCommand(), - oom); - cap.dispose(); - } + @Override + public void actionPerformed(ActionEvent e) + { + if (settings.isCancelled()) + { + return; + } + AlignmentExportData exportData = settings.getAlignExportData(); + CutAndPasteTransfer cap = new CutAndPasteTransfer(); + cap.setForInput(null); + try + { + FileFormatI format = fileFormat; + cap.setText(new FormatAdapter(alignPanel, settings) + .formatSequences(format, exportData.getAlignment(), + exportData.getOmitHidden(), + exportData.getStartEndPostions(), + viewport.getAlignment().getHiddenColumns())); + Desktop.addInternalFrame(cap, MessageManager.formatMessage( + "label.alignment_output_command", new Object[] + { fileFormat.getName() }), 600, 500); + } catch (OutOfMemoryError oom) + { + new OOMWarning("Outputting alignment as " + fileFormat.getName(), + oom); + cap.dispose(); + } + // TODO Auto-generated method stub + } + }); + settings.doShowSettings(); } - public static AlignmentExportData getAlignmentForExport( - FileFormatI format, AlignViewportI viewport, - AlignExportSettingI exportSettings) + public static AlignExportSettingI getAlignmentForExport( + FileFormatI format, AlignmentPanel alignPanel, + AlignExportSettingBeanI exportSettings) { - AlignmentI alignmentToExport = null; - AlignExportSettingI settings = exportSettings; - String[] omitHidden = null; - - HiddenSequences hiddenSeqs = viewport.getAlignment() - .getHiddenSequences(); - - alignmentToExport = viewport.getAlignment(); - boolean hasHiddenSeqs = hiddenSeqs.getSize() > 0; - if (settings == null) - { - settings = new AlignExportSettings(hasHiddenSeqs, - viewport.hasHiddenColumns(), format); - } - // settings.isExportAnnotations(); - - if (viewport.hasHiddenColumns() && !settings.isExportHiddenColumns()) - { - omitHidden = viewport.getViewAsString(false, - settings.isExportHiddenSequences()); - } - - int[] alignmentStartEnd = new int[2]; - if (hasHiddenSeqs && settings.isExportHiddenSequences()) - { - alignmentToExport = hiddenSeqs.getFullAlignment(); - } - else - { - alignmentToExport = viewport.getAlignment(); - } - alignmentStartEnd = viewport.getAlignment().getHiddenColumns() - .getVisibleStartAndEndIndex(alignmentToExport.getWidth()); - AlignmentExportData ed = new AlignmentExportData(alignmentToExport, - omitHidden, alignmentStartEnd, settings); - return ed; + return new AlignExportSettings(alignPanel, format, exportSettings); } /** diff --git a/src/jalview/io/HTMLOutput.java b/src/jalview/io/HTMLOutput.java index bf8c431..3a7b441 100644 --- a/src/jalview/io/HTMLOutput.java +++ b/src/jalview/io/HTMLOutput.java @@ -21,12 +21,15 @@ package jalview.io; import jalview.api.AlignExportSettingI; +import jalview.datamodel.AlignExportSettingBeanI; import jalview.datamodel.AlignmentExportData; import jalview.exceptions.NoFileSelectedException; import jalview.gui.AlignmentPanel; import jalview.gui.IProgressIndicator; import jalview.util.MessageManager; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -53,20 +56,24 @@ public abstract class HTMLOutput implements Runnable } } + String _bioJson=null; public String getBioJSONData() { - return getBioJSONData(null); + if (_bioJson==null) { + getBioJSONData(null); + } + return _bioJson; } - public String getBioJSONData(AlignExportSettingI exportSettings) + public void getBioJSONData(AlignExportSettingBeanI exportSettings) { if (!isEmbedData()) { - return null; + return; } if (exportSettings == null) { - exportSettings = new AlignExportSettingI() + exportSettings = new AlignExportSettingBeanI() { @Override public boolean isExportHiddenSequences() @@ -103,17 +110,30 @@ public abstract class HTMLOutput implements Runnable { return false; } + }; } - AlignmentExportData exportData = jalview.gui.AlignFrame - .getAlignmentForExport(FileFormat.Json, ap.getAlignViewport(), + AlignExportSettingI exportDataSettings = jalview.gui.AlignFrame + .getAlignmentForExport(FileFormat.Json, ap, exportSettings); - String bioJSON = new FormatAdapter(ap, exportData.getSettings()) - .formatSequences(FileFormat.Json, exportData.getAlignment(), - exportData.getOmitHidden(), - exportData.getStartEndPostions(), ap.getAlignViewport() - .getAlignment().getHiddenColumns()); - return bioJSON; + exportDataSettings.addActionListener(new ActionListener() + { + + @Override + public void actionPerformed(ActionEvent e) + { + AlignmentExportData exportData = exportDataSettings.getAlignExportData(); + _bioJson = new FormatAdapter(ap, exportData.getSettings()) + .formatSequences(FileFormat.Json, exportData.getAlignment(), + exportData.getOmitHidden(), + exportData.getStartEndPostions(), ap.getAlignViewport() + .getAlignment().getHiddenColumns()); + + } + + + }); + exportDataSettings.doShowSettings(); } /** diff --git a/src/jalview/io/JSONFile.java b/src/jalview/io/JSONFile.java index fda22dc..f957e06 100644 --- a/src/jalview/io/JSONFile.java +++ b/src/jalview/io/JSONFile.java @@ -29,6 +29,7 @@ import jalview.api.FeatureRenderer; import jalview.api.FeatureSettingsModelI; import jalview.api.FeaturesDisplayedI; import jalview.bin.BuildDetails; +import jalview.datamodel.AlignExportSettingBeanI; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; @@ -123,13 +124,13 @@ public class JSONFile extends AlignFile implements ComplexAlignFile try { AlignmentPojo jsonAlignmentPojo = new AlignmentPojo(); - AlignExportSettingI exportSettings = getExportSettings(); + AlignExportSettingBeanI exportSettings = getExportSettings(); // if no export settings were supplied use the following with all values // defaulting to true if (exportSettings == null) { - exportSettings = new AlignExportSettingI() + exportSettings = new AlignExportSettingBeanI() { @Override public boolean isExportHiddenSequences() diff --git a/src/jalview/jbgui/GAlignExportSettings.java b/src/jalview/jbgui/GAlignExportSettings.java index fe5a520..cfa57c8 100644 --- a/src/jalview/jbgui/GAlignExportSettings.java +++ b/src/jalview/jbgui/GAlignExportSettings.java @@ -62,10 +62,6 @@ public abstract class GAlignExportSettings extends JPanel protected JCheckBox chkExportGrps = new JCheckBox(); - JButton btnOk = new JButton(); - - JButton btnCancel = new JButton(); - private boolean hasHiddenSeq, hasHiddenCols, isComplexAlignFile, showDialog; @@ -93,8 +89,6 @@ public abstract class GAlignExportSettings extends JPanel chkExportFeats .setText(MessageManager.getString("action.export_features")); chkExportGrps.setText(MessageManager.getString("action.export_groups")); - btnOk.setText(MessageManager.getString("action.ok")); - btnCancel.setText(MessageManager.getString("action.cancel")); chkAll.setText(MessageManager.getString("action.select_all")); hiddenRegionConfPanel.setLayout(hiddenRegionLayout); @@ -110,24 +104,6 @@ public abstract class GAlignExportSettings extends JPanel } }); - btnOk.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - ok_actionPerformed(e); - } - }); - - btnCancel.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - cancel_actionPerformed(e); - } - }); - // hiddenRegionConfPanel.add(chkAll, BorderLayout.NORTH); hiddenRegionConfPanel.add(chkHiddenSeqs, BorderLayout.CENTER); hiddenRegionConfPanel.add(chkHiddenCols, BorderLayout.SOUTH); @@ -150,9 +126,6 @@ public abstract class GAlignExportSettings extends JPanel optionsPanel.add(hiddenRegionConfPanel); } - actionPanel.add(btnCancel); - actionPanel.add(btnOk); - add(optionsPanel, BorderLayout.NORTH); add(actionPanel, BorderLayout.SOUTH); -- 1.7.10.2