package bluej.debugmgr;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.control.TextField;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;

import bluej.Config;
import bluej.debugger.gentype.GenTypeDeclTpar;
import bluej.debugger.gentype.GenTypeParameter;
import bluej.debugger.gentype.JavaType;
import bluej.debugger.gentype.TextType;
import bluej.debugmgr.objectbench.ObjectBenchEvent;
import bluej.debugmgr.objectbench.ObjectBenchInterface;
import bluej.debugmgr.objectbench.ObjectBenchListener;
import bluej.utility.javafx.JavaFXUtil;
import bluej.utility.javafx.dialog.DialogPaneAnimateError;
import bluej.views.CallableView;
import bluej.views.TypeParamView;
import bluej.views.View;
import threadchecker.OnThread;
import threadchecker.Tag;


| Superclass for interactive call dialogs (method calls or free | form calls. | | @author Michael Kolling | @OnThread(Tag.FXPlatform) public abstract class CallDialog extends Dialog<Void> implements ObjectBenchListener{ protected static final String emptyFieldMsg = Config.getString("error.methodCall.emptyField"); protected static final String emptyTypeFieldMsg = Config.getString("error.methodCall.emptyTypeField"); private Label errorLabel; protected ParameterList parameterList; protected ParameterList typeParameterList; protected final ObjectBenchInterface bench; protected String defaultParamValue = ""; private Pane descPanel; protected TextField focusedTextField; protected CallHistory history; private DialogPaneAnimateError dialogPane; public CallDialog(Window parent, ObjectBenchInterface objectBench, String title) { initOwner(parent); setTitle(title); initModality(Modality.NONE); setResizable(true); bench = objectBench; bench.addObjectBenchListener(this); }
| The Ok button was pressed. | public abstract void handleOK();
| SetWaitCursor - Sets the cursor to "wait" style cursor or back to default |*/ public void setWaitCursor(boolean wait) { getDialogPane().setCursor(wait ? Cursor.WAIT : Cursor.DEFAULT); } /** * Set the enabled state of the OK button public void setOKEnabled(boolean state) { dialogPane.getOKButton().setDisable(!state); }
| SetMessage - Sets a status bar style message for the dialog mainly | for reporting back compiler errors upon method calls. | public void setErrorMessage(String message) { int index = message.indexOf("location:"); if (index != -1) { message = message.substring(0,index-1); } String messageFinal = message; JavaFXUtil.runNowOrLater(() -> errorLabel.setText(messageFinal)); } | The object was selected interactively (by clicking | on it with the mouse pointer). | @Override @OnThread(Tag.FXPlatform) public void objectEvent(ObjectBenchEvent obe) { NamedValue value = obe.getValue(); String name = value.getName(); insertText(name); }
| Returns the formal type parameters for the class that declares this method. | @return Array of typeParamViews | protected static TypeParamView[] getFormalTypeParams(CallableView callable) { View clazz = callable.getDeclaringView(); return clazz.getTypeParams(); }
| Creates a panel of parameters for a method | protected Pane createParameterPanel(String prefix) { CallableView method = getCallableView(); Class<?>[] paramClasses = getArgTypes(false); String[] paramNames = method.getParamNames(); String[] paramTypes = method.getParamTypeStrings(); parameterList = new ParameterList(paramClasses.length, defaultParamValue, f -> this.focusedTextField = f, this::fireOK); for (int i = 0; i < paramTypes.length; i++) { if (method.isVarArgs() && i == (paramClasses.length - 1)) { List<String> historyList = history.getHistory(paramClasses[i].getComponentType()); parameterList.addVarArgsTypes(paramTypes[i], paramNames == null ? null : paramNames[i]); parameterList.setHistory(i, historyList); } else { parameterList.addNormalParameter(paramTypes[i], paramNames == null ? null : paramNames[i], history.getHistory(paramClasses[i])); } } return createParameterPanel(prefix + "(", ")", parameterList); } protected void fireOK() { dialogPane.getOKButton().fire(); }
| Creates a panel of parameters. | | @param startString The string prepended before the first parameter. Typically something like ( or < | @param endString The string appended after the last parameter. Typically something like ) or > | @param parameterList A list containing the components for the parameter panel | @return A pane containing the method signature's nodes, where the parameters are input boxes. | protected Pane createParameterPanel(String startString, String endString, ParameterList parameterList) { GridPane parameterPanel = new GridPane(); parameterPanel.getStyleClass().add("grid"); Label startParenthesis = new Label(startString); startParenthesis.setAlignment(Pos.BASELINE_LEFT); parameterPanel.add(startParenthesis, 0, 0); GridPane.setValignment(startParenthesis, VPos.BASELINE); for (int i = 0; i < parameterList.formalCount(); i++) { ObservableList<? extends Node> components = parameterList.getNodesForFormal(i); if (components.size() == 1) { Node child = components.get(0); parameterPanel.add(child, 1, i); } else { GridPane varargsPane = new GridPane(); varargsPane.getStyleClass().add("grid"); varargsPane.setAlignment(Pos.BASELINE_LEFT); GridPane.setValignment(varargsPane, VPos.BASELINE); arrangeVarargsComponents(varargsPane, components); components.addListener((ListChangeListener<Node>) c -> { arrangeVarargsComponents(varargsPane, c.getList()); getDialogPane().getScene().getWindow().sizeToScene(); }); ColumnConstraints column2 = new ColumnConstraints(); column2.setHgrow(Priority.ALWAYS); varargsPane.getColumnConstraints().addAll(new ColumnConstraints(), column2, new ColumnConstraints(), new ColumnConstraints() ); parameterPanel.add(varargsPane, 1, i); } Label type = new Label( (i == (parameterList.formalCount() - 1)) ? endString : ","); type.setAlignment(Pos.BOTTOM_LEFT); parameterPanel.add(type, 2, i); GridPane.setValignment(type, VPos.BOTTOM); } ColumnConstraints column2 = new ColumnConstraints(); column2.setHgrow(Priority.ALWAYS); parameterPanel.getColumnConstraints().addAll(new ColumnConstraints(), column2, new ColumnConstraints()); return parameterPanel; }
| Arranges the varags components on a grid pane. | Each row has the components of one parameter: | '+' to add another one before, | combobox as a field to enter values and | 'x' to delete it, | The last row will have an extra component: | '+' to add another one after. | | Only the second column should be resizable. | | @param varargsPane The grid pane containing the components | @param components The parameters' components | private void arrangeVarargsComponents(GridPane varargsPane, ObservableList<? extends Node> components) { varargsPane.getChildren().clear(); int lastComponentIndex = components.size() - 1; for (int j = 0; j < lastComponentIndex; j++) { varargsPane.add(components.get(j), j % 3, j / 3); } varargsPane.add(components.get(lastComponentIndex), 3, (lastComponentIndex - 1) / 3); }
| GetArgTypes - Get an array with the classes of the parameters for this | method. "null" if there are no parameters. <br> |* If varArgsExpanded is set to true, the varargs will be expanded to the * number of variable arguments that have been typed into the dialog. For * instance, if the only argument is a vararg of type String and two strings | has been typed in, this method will return an array of two String | classes. | | @param varArgsExpanded | if set to true, varargs will be expanded. | public Class[] getArgTypes(boolean varArgsExpanded) { CallableView method = getCallableView(); Class<?>[] params = method.getParameters(); boolean hasVarArgs = method.isVarArgs() && parameterList != null && parameterList.actualCount() >= params.length; if (hasVarArgs && varArgsExpanded) { int totalParams = parameterList.actualCount(); Class<?>[] allParams = new Class[totalParams]; System.arraycopy(params, 0, allParams, 0, params.length); Class<?> varArgType = params[params.length - 1].getComponentType(); for (int i = params.length - 1; i < totalParams; i++) { allParams[i] = varArgType; } return allParams; } else { return params; } }
| Get arguments from param entry fields as array of strings. | May be null (if there are no arguments). | public String[] getArgs() { String[] args = null; if (parameterList != null) { args = new String[parameterList.actualCount()]; for (int i = 0; i < parameterList.actualCount(); i++) { args[i] = parameterList.getActualParameter(i).getEditor().getText(); } } return args; }
| Returns false if any of the parameter fields are empty | public boolean parameterFieldsOk() { if (parameterList != null) { for (int i = 0; i < parameterList.actualCount(); i++) { String arg = parameterList.getActualParameter(i).getEditor().getText(); if (arg == null || arg.trim().equals("")) { JavaFXUtil.setPseudoclass("bj-dialog-error", true, parameterList.getActualParameter(i).getEditor()); return false; } JavaFXUtil.setPseudoclass("bj-dialog-error", false, parameterList.getActualParameter(i).getEditor()); } } return true; }
| Returns false if some of the typeParameter fields are empty. | That is: if one or more type parameters, but not all, are typed in | public boolean typeParameterFieldsOk() { boolean oneIsTypedIn = false; boolean oneIsEmpty = false; if (typeParameterList != null) { List<TextField> empties = new ArrayList<>(); for (int i = 0; i < typeParameterList.actualCount(); i++) { TextField field = typeParameterList.getActualParameter(i).getEditor(); JavaFXUtil.setPseudoclass("bj-dialog-error", false, field); String arg = field.getText(); if (arg == null || arg.trim().equals("")) { oneIsEmpty = true; empties.add(field); } else { oneIsTypedIn = true; } if (oneIsEmpty && oneIsTypedIn) { empties.forEach(f -> JavaFXUtil.setPseudoclass("bj-dialog-error", true, field)); return false; } } } return true; }
| Build the Swing dialog. | protected void makeDialog(Pane centerPanel) { VBox dialogPanel = new VBox(); JavaFXUtil.addStyleClass(dialogPanel, "call-dialog-content"); descPanel = new VBox(); errorLabel = JavaFXUtil.withStyleClass(new Label(" "), "dialog-error-label"); dialogPanel.getChildren().addAll(descPanel, new Separator(), centerPanel, errorLabel); dialogPane = new DialogPaneAnimateError(errorLabel, () -> { }); Config.addDialogStylesheets(dialogPane); setDialogPane(dialogPane); getDialogPane().getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL); dialogPane.getOKButton().addEventFilter(ActionEvent.ACTION, e -> { handleOK(); e.consume(); }); getDialogPane().setContent(dialogPanel); setOnHidden(e -> bench.removeObjectBenchListener(this)); }
| SetDescription - display a new description in the dialog | protected void setDescription(Node label) { descPanel.getChildren().setAll(label); }
| Insert text into edit field (JComboBox) that has focus. | public void insertText(String text) { if (parameterList != null) { if (focusedTextField != null) { focusedTextField.setText(text); ((Stage)focusedTextField.getScene().getWindow()).toFront(); focusedTextField.requestFocus(); } } } @OnThread(Tag.FXPlatform) public void saveCallHistory() { if (parameterList != null) { Class<?>[] paramClasses = getArgTypes(true); for (int i = 0; i < parameterList.actualCount(); i++) { history.addCall(paramClasses[i], parameterList.getActualParameter(i).getEditor().getText()); } } if (typeParameterList != null) { CallableView callable = getCallableView(); TypeParamView[] formalTypeParams = getFormalTypeParams(callable); String[] typeParams = getTypeParams(); for (int i = 0; i < typeParams.length; i++) { history.addCall(formalTypeParams[i], typeParams[i]); } for (int i = 0; i < typeParams.length; i++) { List<String> historyList = history.getHistory(formalTypeParams[i]); typeParameterList.setHistory(i, historyList); } } }
| For a generic class this will return the type parameters if any has been | typed in. Otherwise it will just return an empty array. | | @return A String array containing the type parameters as typed by the | user | public String[] getTypeParams() { if (typeParameterList == null) { return new String[0]; } String[] typeParams = new String[typeParameterList.actualCount()]; for (int i = 0; i < typeParameterList.actualCount(); i++) { typeParams[i] = typeParameterList.getActualParameter(i).getEditor().getText(); if (typeParams[i] == null || typeParams[i].equals("")) { return new String[0]; } } return typeParams; }
| GetArgTypes - Get an array with the types of the parameters for this | method. This takes into account mapping from type parameter names to | their types as supplied in the constructor or setInstanceInfo call.<p> | | If varArgsExpanded is set to true, the varargs will be expanded to the | number of variable arguments that have been typed into the dialog. For | instance, if the only argument is a vararg of type String and two | strings have been typed in, this method will return an array of two | String classes. | | @param varArgsExpanded | if set to true, varargs will be expanded. | public JavaType[] getArgGenTypes(boolean varArgsExpanded) { CallableView method = getCallableView(); boolean raw = targetIsRaw(); Map<String,GenTypeParameter> typeParameterMap = getTargetTypeArgs(); Map<String,GenTypeParameter> typeMap = new HashMap<>(); if (typeParameterMap != null) { typeMap.putAll(typeParameterMap); } String [] typeParams = getTypeParams(); TypeParamView[] formalTypeParamViews = getFormalTypeParams(method); int len = typeParams.length; for (int i = 0; i < len; i++) { TypeParamView view = formalTypeParamViews[i]; GenTypeDeclTpar formalType = view.getParamType(); JavaType actualType = new TextType(typeParams[i]); typeMap.put(formalType.getTparName(), actualType); } JavaType[] params = method.getParamTypes(raw); for (int i = 0; i < params.length; i++) { params[i] = params[i].mapTparsToTypes(typeMap).getUpperBound(); } if (hasVarArgs(method, params) && varArgsExpanded) { int totalParams = parameterList.actualCount(); JavaType[] allParams = new JavaType[totalParams]; System.arraycopy(params, 0, allParams, 0, params.length); JavaType varArgType = params[params.length - 1].getArrayComponent(); for (int i = params.length - 1; i < totalParams; i++) { allParams[i] = varArgType; } return allParams; } else { return params; } } private boolean hasVarArgs(CallableView method, JavaType[] params) { if (!method.isVarArgs()) { return false; } if (parameterList == null) { return false; } if (parameterList.actualCount() < params.length) { return false; } if (getArgs().length == 1 && isEmptyArg(getArgs()[0]) ) { return false; } return true; } private boolean isEmptyArg(String value) { String[] emptyArgs = {"{ }", "{}", ""}; return Arrays.asList(emptyArgs).contains(value.trim()); }
| Get the user-supplied instance name (constructor dialogs). Returns null for method dialogs. | protected String getNewInstanceName() { return null; } protected abstract CallableView getCallableView(); protected boolean targetIsRaw() { return false; } protected Map getTargetTypeArgs() { return Collections.emptyMap(); } }

.   CallDialog
.   handleOK
.   setOKEnabled
.   setErrorMessage
.   objectEvent
.   getFormalTypeParams
.   createParameterPanel
.   fireOK
.   createParameterPanel
.   arrangeVarargsComponents
.   getArgTypes
.   getArgs
.   parameterFieldsOk
.   typeParameterFieldsOk
.   makeDialog
.   setDescription
.   insertText
.   saveCallHistory
.   getTypeParams
.   getArgGenTypes
.   hasVarArgs
.   isEmptyArg
.   getNewInstanceName
.   getCallableView
.   targetIsRaw
.   getTargetTypeArgs




606 neLoCode + 56 LoComm