import jalview.schemes.ResidueColourScheme;
import jalview.schemes.TCoffeeColourScheme;
import jalview.util.MessageManager;
+import jalview.util.dialogrunner.RunResponse;
import jalview.viewmodel.AlignmentViewport;
import jalview.viewmodel.ViewportRanges;
import jalview.ws.DBRefFetcher;
String format = currentFileFormat == null ? null
: currentFileFormat.getName();
- JalviewFileChooser chooser = JalviewFileChooser
+ final JalviewFileChooser chooser = JalviewFileChooser
.forWrite(Cache.getProperty("LAST_DIRECTORY"), format);
-
+ final AlignFrame us = this;
chooser.setFileView(new JalviewFileView());
chooser.setDialogTitle(
MessageManager.getString("label.save_alignment_to_file"));
chooser.setToolTipText(MessageManager.getString("action.save"));
- int value = chooser.showSaveDialog(this);
-
-
- if (value == JalviewFileChooser.APPROVE_OPTION)
+ chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
{
- currentFileFormat = chooser.getSelectedFormat();
- while (currentFileFormat == null)
- {
- JvOptionPane.showInternalMessageDialog(Desktop.desktop,
- MessageManager.getString(
- "label.select_file_format_before_saving"),
- MessageManager.getString("label.file_format_not_specified"),
- JvOptionPane.WARNING_MESSAGE);
+ @Override
+ public void run()
+ {
currentFileFormat = chooser.getSelectedFormat();
- value = chooser.showSaveDialog(this);
- if (value != JalviewFileChooser.APPROVE_OPTION)
+ while (currentFileFormat == null)
{
- return;
+ JvOptionPane.showInternalMessageDialog(Desktop.desktop,
+ MessageManager.getString(
+ "label.select_file_format_before_saving"),
+ MessageManager
+ .getString("label.file_format_not_specified"),
+ JvOptionPane.WARNING_MESSAGE);
+ currentFileFormat = chooser.getSelectedFormat();
+ chooser.showSaveDialog(us);
}
- }
- fileName = chooser.getSelectedFile().getPath();
+ fileName = chooser.getSelectedFile().getPath();
- Cache.setProperty("DEFAULT_FILE_FORMAT", currentFileFormat.getName());
+ Cache.setProperty("DEFAULT_FILE_FORMAT",
+ currentFileFormat.getName());
- Cache.setProperty("LAST_DIRECTORY", fileName);
- saveAlignment(fileName, currentFileFormat);
- }
+ Cache.setProperty("LAST_DIRECTORY", fileName);
+ saveAlignment(fileName, currentFileFormat);
+ }
+ }).showSaveDialog(this);
}
public boolean saveAlignment(String file, FileFormatI format)
chooser.setToolTipText(
MessageManager.getString("label.load_tree_file"));
- int value = chooser.showOpenDialog(null);
-
- if (value == JalviewFileChooser.APPROVE_OPTION)
- {
- String filePath = chooser.getSelectedFile().getPath();
- Cache.setProperty("LAST_DIRECTORY", filePath);
- NewickFile fin = null;
- try
- {
- fin = new NewickFile(filePath, DataSourceType.FILE);
- viewport.setCurrentTree(showNewickTree(fin, filePath).getTree());
- } catch (Exception ex)
- {
- JvOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(),
- MessageManager.getString("label.problem_reading_tree_file"),
- JvOptionPane.WARNING_MESSAGE);
- ex.printStackTrace();
- }
- if (fin != null && fin.hasWarningMessage())
- {
- JvOptionPane.showMessageDialog(Desktop.desktop,
- fin.getWarningMessage(),
- MessageManager
- .getString("label.possible_problem_with_tree_file"),
- JvOptionPane.WARNING_MESSAGE);
- }
- }
+ chooser.response(
+ new jalview.util.dialogrunner.RunResponse(JalviewFileChooser.APPROVE_OPTION)
+ {
+ @Override
+ public void run()
+ {
+ String filePath = chooser.getSelectedFile().getPath();
+ Cache.setProperty("LAST_DIRECTORY", filePath);
+ NewickFile fin = null;
+ try
+ {
+ fin = new NewickFile(new FileParse(
+ chooser.getSelectedFile(), DataSourceType.FILE));
+ viewport.setCurrentTree(
+ showNewickTree(fin, filePath).getTree());
+ } catch (Exception ex)
+ {
+ JvOptionPane.showMessageDialog(Desktop.desktop,
+ ex.getMessage(),
+ MessageManager.getString(
+ "label.problem_reading_tree_file"),
+ JvOptionPane.WARNING_MESSAGE);
+ ex.printStackTrace();
+ }
+ if (fin != null && fin.hasWarningMessage())
+ {
+ JvOptionPane.showMessageDialog(Desktop.desktop,
+ fin.getWarningMessage(),
+ MessageManager.getString(
+ "label.possible_problem_with_tree_file"),
+ JvOptionPane.WARNING_MESSAGE);
+ }
+ }
+ }).openDialog(this);
}
public TreePanel showNewickTree(NewickFile nf, String treeTitle)
import jalview.util.MessageManager;
import jalview.util.Platform;
import jalview.util.UrlConstants;
+import jalview.util.dialogrunner.RunResponse;
import jalview.viewmodel.AlignmentViewport;
import jalview.ws.params.ParamManager;
import jalview.ws.utils.UrlDownloadClient;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
-import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
public Desktop()
{
/**
- * A note to implementors. It is ESSENTIAL that any activities that might
- * block are spawned off as threads rather than waited for during this
- * constructor.
+ * A note to implementors. It is ESSENTIAL that any activities that might block
+ * are spawned off as threads rather than waited for during this constructor.
*/
instance = this;
doVamsasClientCheck();
// This line prevents Windows Look&Feel resizing all new windows to maximum
// if previous window was maximised
- desktop.setDesktopManager(
- new MyDesktopManager(
- (Platform.isWindows() ? new DefaultDesktopManager()
- : Platform.isAMac()
- ? new AquaInternalFrameManager(
- desktop.getDesktopManager())
- : desktop.getDesktopManager())));
+ desktop.setDesktopManager(new MyDesktopManager(
+ (Platform.isWindows() ? new DefaultDesktopManager()
+ : Platform.isAMac()
+ ? new AquaInternalFrameManager(
+ desktop.getDesktopManager())
+ : desktop.getDesktopManager())));
Rectangle dims = getLastKnownDimensions("");
if (dims != null)
* @j2sNative
*/
{
- final Desktop me = this;
- // Thread off the news reader, in case there are connection problems.
- addDialogThread(new Runnable()
- {
+ final Desktop me = this;
+ // Thread off the news reader, in case there are connection problems.
+ addDialogThread(new Runnable()
+ {
@Override
public void run()
{
showNews.setVisible(true);
Cache.log.debug("Completed news thread.");
}
- });
+ });
}
}
}
/**
- * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
- * the window
+ * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
+ * window
*
* @param frame
*/
MessageManager.getString("label.open_local_file"));
chooser.setToolTipText(MessageManager.getString("action.open"));
- chooser.setCallback(new Runnable()
+ chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
{
@Override
new FileLoader().LoadFile(viewport, selectedFile,
DataSourceType.FILE, format);
}
- });
-
- int value = chooser.showOpenDialog(this);
- if (value == JFileChooser.APPROVE_OPTION)
- {
- chooser.getCallback().run();
- }
-
+ }).openDialog(this);
}
/**
String dialogOption = "label.input_alignment_from_url";
desktop.dialogData = new Object[] { dialogOption, viewport, history };
- desktop.onDialogReturn(
- JvOptionPane.showInternalConfirmDialog(desktop, panel,
- MessageManager.getString(dialogOption),
+ desktop.onDialogReturn(JvOptionPane.showInternalConfirmDialog(desktop,
+ panel, MessageManager.getString(dialogOption),
JvOptionPane.OK_CANCEL_OPTION));
// no code may follow this, as SwingJS will not block
}
-
/**
* Opens the CutAndPaste window for the user to paste an alignment in to
*
/**
* Gather expanded views (separate AlignFrame's) with the same sequence set
- * identifier back in to this frame as additional views, and close the
- * expanded views. Note the expanded frames may themselves have multiple
- * views. We take the lot.
+ * identifier back in to this frame as additional views, and close the expanded
+ * views. Note the expanded frames may themselves have multiple views. We take
+ * the lot.
*
* @param source
*/
/**
* Proxy class for JDesktopPane which optionally displays the current memory
- * usage and highlights the desktop area with a red bar if free memory runs
- * low.
+ * usage and highlights the desktop area with a red bar if free memory runs low.
*
* @author AMW
*/
JvOptionPane.showInternalMessageDialog(Desktop.desktop,
MessageManager.formatMessage("label.couldnt_locate",
new Object[]
- { url }),
+ { url }),
MessageManager.getString("label.url_not_found"),
JvOptionPane.WARNING_MESSAGE);
}
}
-
/**
* Accessor method to quickly get all the AlignmentFrames loaded.
*
}
/**
- * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
- * binding when opened
+ * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
+ * when opened
*/
protected void addQuitHandler()
{
}
/**
- * This will return the first AlignFrame holding the given viewport instance.
- * It will break if there are more than one AlignFrames viewing a particular
- * av.
+ * This will return the first AlignFrame holding the given viewport instance. It
+ * will break if there are more than one AlignFrames viewing a particular av.
*
* @param viewport
* @return alignFrame for viewport
/**
* Explode the views in the given SplitFrame into separate SplitFrame windows.
- * This respects (remembers) any previous 'exploded geometry' i.e. the size
- * and location last time the view was expanded (if any). However it does not
+ * This respects (remembers) any previous 'exploded geometry' i.e. the size and
+ * location last time the view was expanded (if any). However it does not
* remember the split pane divider location - this is set to match the
* 'exploding' frame.
*
List<DataSourceType> protocols, DropTargetDropEvent evt,
Transferable t) throws Exception
{
-
+
// BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
-// DataFlavor[] flavors = t.getTransferDataFlavors();
-// for (int i = 0; i < flavors.length; i++) {
-// if (flavors[i].isFlavorJavaFileListType()) {
-// evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
-// List<File> list = (List<File>) t.getTransferData(flavors[i]);
-// for (int j = 0; j < list.size(); j++) {
-// File file = (File) list.get(j);
-// byte[] data = getDroppedFileBytes(file);
-// fileName.setText(file.getName() + " - " + data.length + " " + evt.getLocation());
-// JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
-// target.setText(new String(data));
-// }
-// dtde.dropComplete(true);
-// return;
-// }
-//
+ // DataFlavor[] flavors = t.getTransferDataFlavors();
+ // for (int i = 0; i < flavors.length; i++) {
+ // if (flavors[i].isFlavorJavaFileListType()) {
+ // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+ // List<File> list = (List<File>) t.getTransferData(flavors[i]);
+ // for (int j = 0; j < list.size(); j++) {
+ // File file = (File) list.get(j);
+ // byte[] data = getDroppedFileBytes(file);
+ // fileName.setText(file.getName() + " - " + data.length + " " +
+ // evt.getLocation());
+ // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
+ // target.setText(new String(data));
+ // }
+ // dtde.dropComplete(true);
+ // return;
+ // }
+ //
DataFlavor uriListFlavor = new DataFlavor(
"text/uri-list;class=java.lang.String"), urlFlavour = null;
try
{
- java.net.URL url = (URL) t.getTransferData(urlFlavour);
+ java.net.URL url = (URL) t.getTransferData(urlFlavour);
// nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
// means url may be null.
- if (url != null)
- {
- protocols.add(DataSourceType.URL);
- files.add(url.toString());
- Cache.log.debug("Drop handled as URL dataflavor "
- + files.get(files.size() - 1));
+ if (url != null)
+ {
+ protocols.add(DataSourceType.URL);
+ files.add(url.toString());
+ Cache.log.debug("Drop handled as URL dataflavor "
+ + files.get(files.size() - 1));
return;
}
else
"Please ignore plist error - occurs due to problem with java 8 on OSX");
}
;
- }
+ }
} catch (Throwable ex)
{
Cache.log.debug("URL drop handler failed.", ex);
&& (source.endsWith(".lnk") || source.endsWith(".url")
|| source.endsWith(".site")))
{
- try {
+ try
+ {
Object obj = files.get(f);
- File lf = (obj instanceof File ? (File) obj : new File((String) obj));
+ File lf = (obj instanceof File ? (File) obj
+ : new File((String) obj));
// process link file to get a URL
Cache.log.debug("Found potential link file: " + lf);
WindowsShortcut wscfile = new WindowsShortcut(lf);
files.set(f, fullname);
Cache.log.debug("Parsed real filename " + fullname
+ " to extract protocol: " + protocols.get(f));
- }
- catch (Exception ex)
+ } catch (Exception ex)
{
- Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
+ Cache.log.error(
+ "Couldn't parse " + files.get(f) + " as a link file.",
+ ex);
}
}
}
}
/**
- * Answers a (possibly empty) list of any structure viewer frames (currently
- * for either Jmol or Chimera) which are currently open. This may optionally
- * be restricted to viewers of a specified class, or viewers linked to a
- * specified alignment panel.
+ * Answers a (possibly empty) list of any structure viewer frames (currently for
+ * either Jmol or Chimera) which are currently open. This may optionally be
+ * restricted to viewers of a specified class, or viewers linked to a specified
+ * alignment panel.
*
* @param apanel
* if not null, only return viewers linked to this panel
import jalview.gui.JvOptionPane;
import jalview.util.MessageManager;
import jalview.util.Platform;
+import jalview.util.dialogrunner.DialogRunnerI;
+import jalview.util.dialogrunner.Response;
+import jalview.util.dialogrunner.RunResponse;
import java.awt.Component;
import java.awt.Dimension;
*
*/
public class JalviewFileChooser extends JFileChooser
- implements PropertyChangeListener
+ implements PropertyChangeListener, DialogRunnerI
{
+ jalview.util.dialogrunner.DialogRunner<JalviewFileChooser> runner = new jalview.util.dialogrunner.DialogRunner<>(
+ this);
/**
* Factory method to return a file chooser that offers readable alignment file
* formats
}
}
- private Runnable theCallback;
-
- public void setCallback(Runnable callback)
- {
- this.theCallback = callback;
- }
-
- public Runnable getCallback()
- {
- return theCallback;
- }
-
@Override
public void propertyChange(PropertyChangeEvent evt)
{
+ // TODO other properties need runners...
switch (evt.getPropertyName())
{
case "SelectedFile":
- theCallback.run();
+ runner.run(APPROVE_OPTION);
break;
}
}
return f;
}
+ public void openDialog(Component parent)
+ {
+ int value = showOpenDialog(this);
+ runner.run(value);
+ }
+
/**
*
* @param formats
return null;
}
- @Override
- public int showSaveDialog(Component parent) throws HeadlessException
+ Component saveparent;
+ RunResponse overwriteCheck = new RunResponse(
+ JalviewFileChooser.APPROVE_OPTION)
{
- this.setAccessory(null);
+ @Override
+ public void run()
+ {
+ // JBP Note - this code was executed regardless of 'SAVE' being pressed
+ // need to see if there were side effects
+ if (getFileFilter() instanceof JalviewFileFilter)
+ {
+ JalviewFileFilter jvf = (JalviewFileFilter) getFileFilter();
- setDialogType(SAVE_DIALOG);
+ if (!jvf.accept(getSelectedFile()))
+ {
+ String withExtension = getSelectedFile() + "."
+ + jvf.getAcceptableExtension();
+ setSelectedFile(new File(withExtension));
+ }
+ }
+ // All good, so we continue to save
+ returned = new Response(JalviewFileChooser.APPROVE_OPTION);
+
+ // TODO: ENSURE THAT FILES SAVED WITH A ':' IN THE NAME ARE REFUSED AND THE
+ // USER PROMPTED FOR A NEW FILENAME
+ /**
+ * @j2sNative
+ */
+ {
+ if (getSelectedFile().exists())
+ {
+ // TODO JAL-3048 - may not need to raise this for browser saves
+
+ // yes/no cancel
+ int confirm = JvOptionPane.showConfirmDialog(saveparent,
+ MessageManager.getString("label.overwrite_existing_file"),
+ MessageManager.getString("label.file_already_exists"),
+ JvOptionPane.YES_NO_OPTION);
- int ret = showDialog(parent, MessageManager.getString("action.save"));
+ if (confirm != JvOptionPane.YES_OPTION)
+ {
+ returned = new Response(JalviewFileChooser.CANCEL_OPTION);
+ }
+ }
+ }
+ };
+ };
+ @Override
+ public int showSaveDialog(Component parent) throws HeadlessException
+ {
+ this.setAccessory(null);
- if (getFileFilter() instanceof JalviewFileFilter)
+ /*
+ * Save dialog is opened until user picks a file format
+ */
+ if (!runner.isRegistered(overwriteCheck))
{
- JalviewFileFilter jvf = (JalviewFileFilter) getFileFilter();
-
- if (!jvf.accept(getSelectedFile()))
- {
- String withExtension = getSelectedFile() + "."
- + jvf.getAcceptableExtension();
- setSelectedFile(new File(withExtension));
- }
+ // first call for this instance
+ runner.firstResponse(overwriteCheck);
}
- // TODO: ENSURE THAT FILES SAVED WITH A ':' IN THE NAME ARE REFUSED AND THE
- // USER PROMPTED FOR A NEW FILENAME
- if ((ret == JalviewFileChooser.APPROVE_OPTION)
- && getSelectedFile().exists())
+ else
{
- int confirm = JvOptionPane.showConfirmDialog(parent,
- MessageManager.getString("label.overwrite_existing_file"),
- MessageManager.getString("label.file_already_exists"),
- JvOptionPane.YES_NO_OPTION);
-
- if (confirm != JvOptionPane.YES_OPTION)
- {
- ret = JalviewFileChooser.CANCEL_OPTION;
- }
+ // reset response flags
+ runner.resetResponses();
}
- return ret;
+ setDialogType(SAVE_DIALOG);
+ saveparent = parent;
+
+ int value = showDialog(parent, MessageManager.getString("action.save"));
+
+ runner.run(value);
+ return value;
}
void recentListSelectionChanged(Object selection)
}
+ @Override
+ public JalviewFileChooser response(RunResponse action)
+ {
+ return runner.response(action);
+ }
+
}
"status.cancelled_image_export_operation", type.name));
}
}
-
+ // TODO JAL-3048 refactor to method called by constructor or callback
if (file != null)
{
try
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.util.dialogrunner;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * daft gymnastics to allow Dialogs to extend from a Swing class and use this
+ * class to implement chained Response run() definition and execution.
+ *
+ * There is probably a better way of doing this.
+ *
+ * @author jprocter
+ *
+ * @param <T>
+ * the actual dialog that will be shown - which will also initiate the
+ * response chain.
+ */
+public class DialogRunner<T extends DialogRunnerI> implements DialogRunnerI
+{
+
+ private Map<Response, List<RunResponse>> callbacks = new java.util.HashMap<>();
+
+ public T dialog;
+
+ public DialogRunner(T ourDialog)
+ {
+ dialog = ourDialog;
+ }
+
+ /**
+ * clear all 'was ran' flags so responses can be called again, and firstRun will
+ * trigger response execution
+ */
+ public void resetResponses()
+ {
+ for (List<RunResponse> lr : callbacks.values())
+ {
+ for (RunResponse response : lr)
+ {
+ response.reset();
+ }
+ }
+ responses.clear();
+ firstRunWasCalled = false;
+ }
+
+ @Override
+ public T response(RunResponse action)
+ {
+ return addResponse(false, action);
+ }
+
+ /**
+ * insert a response at the beginning of the chain for the action. Useful to add
+ * pre-action validations local to the Dialog class
+ *
+ * @param action
+ * @return
+ */
+ public T firstResponse(RunResponse action)
+ {
+ return addResponse(true, action);
+ }
+
+ protected T addResponse(boolean prePend, RunResponse action)
+ {
+ List<RunResponse> laction = callbacks.get(action.ourTrigger);
+ if (laction == null)
+ {
+ laction = new ArrayList<>();
+ callbacks.put(action.ourTrigger, laction);
+ }
+ if (prePend)
+ {
+ laction.add(0,action);
+ } else {
+ laction.add(action);
+ }
+ return dialog;
+ }
+
+ /**
+ *
+ * @param action
+ * @return true if action is a registered callback
+ */
+ public boolean isRegistered(RunResponse action)
+ {
+ List<RunResponse> resp = callbacks.get(action.ourTrigger);
+ if (resp != null)
+ {
+ for (RunResponse r : resp)
+ {
+ if (r == action)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ /**
+ * handle a response
+ *
+ * @param responseCode
+ */
+ public void run(int responseCode)
+ {
+ run(new Response(responseCode));
+ }
+
+ public void run(String responseString)
+ {
+ run(new Response(responseString));
+ }
+
+ public void run(Object responseObj)
+ {
+ run(new Response(responseObj));
+ }
+
+ /**
+ * start of response handling.
+ *
+ * @param responseCode
+ */
+ public void firstRun(int responseCode)
+ {
+ doFirstRun(new Response(responseCode));
+ }
+
+ public void firstRun(String responseString)
+ {
+ doFirstRun(new Response(responseString));
+ }
+
+ public void firstRun(Object responseObj)
+ {
+ doFirstRun(new Response(responseObj));
+ }
+
+
+ boolean firstRunWasCalled = false;
+
+ private void doFirstRun(Response response)
+ {
+ if (firstRunWasCalled)
+ {
+ return;
+ }
+ firstRunWasCalled = true;
+ run(response);
+ }
+
+ private void run(Response response)
+ {
+ responses.add(response);
+ List<RunResponse> laction = callbacks.get(response);
+
+ if (laction == null)
+ {
+ System.err.println("Doing nothing for " + response);
+ return;
+ }
+ boolean wasRun = false;
+ int num = 0;
+ for (RunResponse action : laction)
+ {
+ num++;
+ // find next action to execute
+ if (!action.wasRun)
+ {
+ System.err
+ .println("Executing action (" + num + ") for " + response);
+ wasRun = true;
+ action.wasRun = true;
+ action.run();
+ if (action.returned != null)
+ {
+ run(action.returned);
+ }
+ break;
+ }
+ }
+ if (!wasRun)
+ {
+ System.err.println("Did nothing for " + response);
+ }
+ }
+
+ List<Response> responses = new ArrayList<>();
+
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.util.dialogrunner;
+
+/**
+ * functional pattern for blocking dialog response handling
+ *
+ * @author jprocter
+ *
+ */
+public interface DialogRunnerI<T extends DialogRunnerI>
+{
+
+ /**
+ * define a new response for this dialog. eg. dialog.response(new
+ * RunResponse(OK_PRessed) { run()...}).response(new RunResponse(CANCEL_PRESSED)
+ * { ... });
+ *
+ * @param action
+ * @return the dialog
+ */
+ T response(RunResponse action);
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.util.dialogrunner;
+
+public class Response
+{
+ int type = 0; // int = 0, String = 1, Object = 2;
+
+ int intresp;
+
+ String stringresp;
+
+ Object objresp;
+
+ public Response(int response)
+ {
+ type = 0;
+ intresp = response;
+ }
+
+ public Response(String response)
+ {
+ type = 1;
+ stringresp = response;
+ }
+
+ public Response(Object response)
+ {
+ if (response instanceof String)
+ {
+ type = 1;
+ stringresp = (String) response;
+ return;
+ }
+ if (response instanceof Integer)
+ {
+ type = 0;
+ intresp = ((Integer) response).intValue();
+ return;
+ }
+ objresp = response;
+ type = 2;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == null || !(obj instanceof Response))
+ {
+ return false;
+ }
+ ;
+ if (((Response) obj).type == type)
+ {
+ switch (type)
+ {
+ case 0:
+ return ((((Response) obj).intresp) == intresp);
+ case 1:
+ return (((Response) obj).stringresp.equals(stringresp));
+ case 2:
+ return (((Response) obj).objresp).equals(objresp);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ switch (type)
+ {
+ case 0:
+ return Integer.valueOf(intresp).hashCode();
+ case 1:
+ return stringresp.hashCode();
+ case 2:
+ return objresp.hashCode();
+ }
+ return super.hashCode();
+ }
+
+ @Override
+ public String toString()
+ {
+ switch (type)
+ {
+ case 0:
+ return "DialogRunner int: " + intresp;
+ case 1:
+ return "DialogRunner str: '" + stringresp + "'";
+ case 2:
+ return "DialogRunner obj: " + objresp.toString();
+ }
+ return "Unconfigured response.";
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.util.dialogrunner;
+
+/**
+ * A Runnable that is kind of like a future, that allows a sequence of Runabbles
+ * to be conditionally executed by DialogRunner
+ *
+ * @author jprocter
+ *
+ */
+public abstract class RunResponse implements Runnable
+{
+ /**
+ * Response that triggers the Run method
+ */
+ public Response ourTrigger;
+
+ /**
+ * set by run() on exit
+ */
+ public Response returned = null;
+
+ /**
+ * set by dialog runner
+ */
+ public boolean wasRun = false;
+
+ public RunResponse(int trigger)
+ {
+ ourTrigger = new Response(trigger);
+ }
+
+ public RunResponse(Object trigger)
+ {
+ ourTrigger = new Response(trigger);
+ }
+
+ public RunResponse(String trigger)
+ {
+ ourTrigger = new Response(trigger);
+ }
+
+ public RunResponse(Response trigger)
+ {
+ ourTrigger = trigger;
+ }
+
+ public void reset()
+ {
+ wasRun = false;
+ returned = null;
+
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Runner for " + ourTrigger;
+ }
+}
--- /dev/null
+package jalview.util.dialogrunner;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class DialogRunnerTest
+{
+ public class MockDialog implements DialogRunnerI
+ {
+ DialogRunner<MockDialog> runner = new DialogRunner<>(this);
+
+ @Override
+ public MockDialog response(RunResponse action)
+ {
+ return runner.response(action);
+ }
+
+ public void doDialog(String resp)
+ {
+ runner.firstRun(resp);
+ }
+ }
+
+ MockDialog dialog = new MockDialog();
+
+ @Test
+ public void testDialogRunner()
+ {
+ RunResponse ok, cancel, help, ineed;
+ final Response ooh = new Response("OOOOoooOOOOH!"),
+ r_ok = new Response("OK"), r_cancel = new Response("CANCEL"),
+ r_done = new Response("DONE"), r_help = new Response("HELP"),
+ r_ddoit = new Response("DIDNT DOIT"),
+ r_needsb = new Response("I NEED SOMEBODY");
+
+ ok = new RunResponse("OK")
+ {
+
+ @Override
+ public void run()
+ {
+ returned = new Response("DONE");
+ }
+ };
+ final RunResponse befok = new RunResponse("OK")
+ {
+
+ @Override
+ public void run()
+ {
+ returned = new Response("OK");
+ }
+ };
+
+ cancel = new RunResponse("CANCEL")
+ {
+ @Override
+ public void run()
+ {
+ returned = r_ddoit;
+ }
+ };
+ help = new RunResponse("HELP")
+ {
+ @Override
+ public void run()
+ {
+ returned = r_needsb;
+
+ }
+ };
+ ineed = new RunResponse(r_needsb)
+ {
+ @Override
+ public void run()
+ {
+ returned = ooh;
+ }
+ };
+
+ Assert.assertFalse(dialog.runner.isRegistered(ok));
+
+ dialog.response(ok).response(cancel).response(help).response(ineed);
+
+ Assert.assertTrue(dialog.runner.isRegistered(ok));
+
+ Assert.assertFalse(dialog.runner.firstRunWasCalled);
+ dialog.doDialog("OK");
+ // OK called, nothing else.
+ Assert.assertTrue(dialog.runner.firstRunWasCalled);
+ Assert.assertTrue(ok.wasRun);
+ Assert.assertEquals(ok.returned, r_done);
+ Assert.assertFalse(cancel.wasRun);
+ Assert.assertEquals(dialog.runner.responses.size(), 2);
+
+ // do it again - check it doesn't trigger again
+ ok.wasRun = false;
+ dialog.doDialog("OK");
+ Assert.assertFalse(ok.wasRun);
+
+ // reset - everything false/null
+ dialog.runner.resetResponses();
+ Assert.assertFalse(dialog.runner.firstRunWasCalled);
+ Assert.assertFalse(ok.wasRun);
+ Assert.assertNull(ok.returned);
+ Assert.assertEquals(dialog.runner.responses.size(), 0);
+
+ // cancel called ..
+ dialog.doDialog("HELP");
+ Assert.assertTrue(dialog.runner.firstRunWasCalled);
+ Assert.assertFalse(ok.wasRun);
+ Assert.assertEquals(ineed.returned, ooh);
+ Assert.assertEquals(dialog.runner.responses.size(), 3);
+
+ // TODO: test prepend and chained execution of tasks for a response.
+ Assert.assertFalse(dialog.runner.isRegistered(befok));
+ dialog.runner.firstResponse(befok);
+
+ Assert.assertTrue(dialog.runner.isRegistered(befok));
+ Assert.assertTrue(dialog.runner.isRegistered(ok));
+
+ dialog.runner.resetResponses();
+
+ dialog.doDialog("OK");
+ Assert.assertTrue(befok.wasRun);
+ Assert.assertTrue(ok.wasRun);
+ Assert.assertEquals(dialog.runner.responses.size(), 3);
+ }
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.util.dialogrunner;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class ResponseTest
+{
+ @Test
+ public void testResonse() {
+ Response intr=new Response(1),intrCopy=new Response(1);
+ Response strr=new Response("1"),strrcopy=new Response("1");
+ Response objr=new Response(Double.valueOf(1d));
+ Assert.assertTrue(intr.equals(intrCopy));
+ Assert.assertTrue(strr.equals(strrcopy));
+ Assert.assertFalse(intr.equals(strr));
+ Assert.assertFalse(intr.equals(objr));
+ Assert.assertFalse(strr.equals(objr));
+ Assert.assertEquals(intr.toString(), "DialogRunner int: 1");
+ Assert.assertEquals(strr.toString(), "DialogRunner str: '1'");
+ Assert.assertEquals(objr.toString(), "DialogRunner obj: 1.0");
+ }
+}
--- /dev/null
+package jalview.util.dialogrunner;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class RunResponseTest
+{
+ @Test
+ public void testRunResponse()
+ {
+
+ RunResponse rr = new RunResponse("OK")
+ {
+ @Override
+ public void run()
+ {
+ returned = new Response("DONE");
+ }
+ };
+ Assert.assertEquals(rr.ourTrigger, new Response("OK"));
+ Assert.assertNotEquals(rr.ourTrigger, new Response("NOTOK"));
+ Assert.assertNull(rr.returned);
+ Assert.assertFalse(rr.wasRun);
+ // trivial ..
+ rr.wasRun = true;
+ rr.run();
+ Assert.assertTrue(rr.wasRun);
+
+ Assert.assertEquals(rr.returned, new Response("DONE"));
+ rr.reset();
+ Assert.assertNull(rr.returned);
+ Assert.assertFalse(rr.wasRun);
+
+ Assert.assertEquals(rr.toString(), "Runner for " + new Response("OK"));
+
+ // just test the other constructors
+ RunResponse rr12 = new RunResponse(12)
+ {
+ @Override
+ public void run()
+ {
+ returned = new Response("DONE");
+ }
+ };
+ RunResponse rrpi = new RunResponse(new Double(3.142))
+ {
+ @Override
+ public void run()
+ {
+ returned = new Response("DONE");
+ }
+ };
+ Assert.assertEquals(rr12.ourTrigger, new Response(12));
+ Assert.assertEquals(rrpi.ourTrigger,
+ new Response(Double.valueOf(3.142)));
+}
+}