package greenfoot.guifx.export;
import bluej.Config;
import bluej.debugger.gentype.ConstructorReflective;
import bluej.debugger.gentype.Reflective;
import bluej.pkgmgr.Project;
import bluej.pkgmgr.target.ClassTarget;
import bluej.utility.javafx.FXCustomizedDialog;
import bluej.utility.javafx.JavaFXUtil;
import bluej.utility.Utility;
import greenfoot.export.Exporter;
import static greenfoot.export.Exporter.ExportFunction;
import greenfoot.export.mygame.ExportInfo;
import greenfoot.export.mygame.ScenarioInfo;
import greenfoot.export.ScenarioSaver;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javafx.application.Platform;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TabPane;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Window;
import threadchecker.OnThread;
import threadchecker.Tag;
import javax.swing.*;
| A dialog allowing the user to export a scenario in a variety of ways.
|
| @author Amjad Altadmri
|
@OnThread(Tag.FXPlatform)
public class ExportDialog extends FXCustomizedDialog<Void>{
private static final String dialogTitle = Config.getApplicationName() + ": "
+ Config.getString("export.dialog.title");
private final Project project;
private final ScenarioSaver scenarioSaver;
private final ScenarioInfo scenarioInfo;
private final ClassTarget currentWorld;
private final Image snapshot;
private int uploadSize;
private final BooleanProperty exportingProperty = new SimpleBooleanProperty(false);
private BooleanBinding tabInvalidity;
private final TabPane tabbedPane = new TabPane();
private final Label progressLabel = new Label();
private final ProgressBar progressBar = new ProgressBar();
private final Map<ExportFunction, ExportTab> exportTabs = new LinkedHashMap<>();
private final Button exportButton = new Button(Config.getString("export.dialog.export"));
| Creates a new instance of the export dialog.
|
| @param parent The parent window.
| @param project The project that will be shared.
| @param scenarioSaver The listener that will enable us to save the scenario when exporting.
| @param scenarioInfo The previously stored scenario info in the properties file.
| @param currentWorld The class target of the current active world.
| @param snapshot A snapshot of the world.
| @throws ExportException if the current world is null or cannot be instantianted.
|
public ExportDialog(Window parent, Project project, ScenarioSaver scenarioSaver,
ScenarioInfo scenarioInfo, ClassTarget currentWorld, Image snapshot)
throws ExportException
{
super(parent, dialogTitle, "export-dialog");
this.project = project;
this.scenarioSaver = scenarioSaver;
this.scenarioInfo = scenarioInfo;
this.currentWorld = currentWorld;
this.snapshot = snapshot;
setModal(true);
makeDialog();
}
| Create the dialog interface.
|
| @throws ExportException if the world hasn't been instantiated, or cannot be instantiated
| because there is no suitable constructor.
|
private void makeDialog() throws ExportException
{
BorderPane contentPane = new BorderPane();
setContentPane(contentPane);
contentPane.setTop(tabbedPane);
progressBar.setProgress(-1);
progressBar.setVisible(false);
progressBar.setPrefWidth(100);
progressLabel.setVisible(false);
getDialogPane().getButtonTypes().add(ButtonType.CLOSE);
Button closeButton = (Button) getDialogPane().lookupButton(ButtonType.CLOSE);
closeButton.setOnAction(event ->
Config.putPropString("greenfoot.lastExportPane", getSelectedFunction().name()));
closeButton.disableProperty().bind(exportingProperty);
exportButton.setOnAction(event -> doExport());
HBox bottomBox = new HBox(exportButton, progressLabel, progressBar);
bottomBox.getStyleClass().add("bottom-box");
contentPane.setBottom(bottomBox);
if (currentWorld == null)
{
throw new ExportException(Config.getString("export.noworld.dialog.msg"));
}
boolean hasZeroArgConstructor = false;
Reflective currentWorldType = currentWorld.getTypeReflective();
if (currentWorldType != null)
{
List<ConstructorReflective> constructors = currentWorldType.getDeclaredConstructors();
hasZeroArgConstructor = constructors.stream().anyMatch(con -> con.getParamTypes().isEmpty());
}
if (! hasZeroArgConstructor)
{
throw new ExportException(Config.getString("export.noconstructor.dialog.msg"));
}
createTabs();
if (snapshot != null)
{
ExportPublishTab publishPane = (ExportPublishTab) exportTabs.get(ExportFunction.PUBLISH);
publishPane.setImage(snapshot);
}
JavaFXUtil.addChangeListenerPlatform(tabbedPane.selectionModelProperty().get().selectedItemProperty(),
tab -> updateControls((ExportTab) tab));
selectTab(Config.getPropString("greenfoot.lastExportPane"));
}
| Display or hide the progress bar and status text. If 'showProgress' is
| true, an indeterminate progress bar is shown, otherwise hidden.
| If 'text' is null, the text is hidden, otherwise shown.
| This method can be invoked from a worker thread.
|
| @param showProgress True to show an indeterminate progress bar, otherwise false.
| @param text The message to be shown next to progress bar. Could be null,
| which means do not show any message.
|
@OnThread(Tag.Any)
public void setProgress(final boolean showProgress, final String text)
{
Platform.runLater(() -> {
progressBar.setVisible(showProgress);
if (!showProgress)
{
progressBar.setProgress(-1);
}
if (text == null)
{
progressLabel.setVisible(false);
}
else
{
progressLabel.setText(text);
progressLabel.setVisible(true);
}
});
}
| Set the text for the export/share button.
|
public void setExportButtonText(String s)
{
exportButton.setText(s);
}
| The export button was pressed. Do the exporting now.
|
private void doExport()
{
if (getSelectedTab().prePublish())
{
ExportInfo info = getSelectedTab().getExportInfo();
exportingProperty.set(true);
scenarioSaver.doSave();
new ExportThread(info).start();
}
}
| A separate thread to execute the actual exporting.
|
class ExportThread
extends Thread
{
private final double snapshotWidth;
private final double snapshotHeight;
private final String displayName;
private final ExportFunction function;
private final ExportInfo info;
| Construct an export thread, which will use the given ExportInfo information.
|
| @param info the information for export. The new thread assumes ownership of
| this object.
|
@OnThread(Tag.FXPlatform)
public ExportThread(ExportInfo info)
{
snapshotWidth = snapshot.getWidth();
snapshotHeight = snapshot.getHeight();
displayName = currentWorld.getDisplayName();
function = getSelectedFunction();
this.info = info;
}
@Override
@OnThread(value = Tag.Worker, ignoreParent = true)
public void run()
{
try
{
Exporter exporter = Exporter.getInstance();
exporter.doExport(project, ExportDialog.this, scenarioSaver, info, function,
displayName, snapshotWidth, snapshotHeight);
}
finally
{
Platform.runLater(() -> exportingProperty.set(false));
}
}
}
| Clear the status text, but only if we are not in the middle of a task.
|
private void clearStatus()
{
if (!progressBar.isVisible())
{
progressLabel.setVisible(false);
}
}
| Return the identifier for the specific export function selected.
|
private ExportFunction getSelectedFunction()
{
return getSelectedTab().getFunction();
}
| Return the identifier for the specific export function selected.
|
private ExportTab getSelectedTab()
{
return (ExportTab) tabbedPane.getSelectionModel().getSelectedItem();
}
| Select a tab based on a function name.
|
| @param name The name of the function which match the tab to be selected.
|
private void selectTab(String name)
{
ExportTab tab = exportTabs.get(ExportFunction.getFunction(name));
tabbedPane.getSelectionModel().select(tab);
updateControls(tab);
}
| Call when the selection of the exportTabs changes to update related controls.
|
| @param tab The selected export tab.
|
private void updateControls(ExportTab tab)
{
exportButton.disableProperty().unbind();
tabInvalidity = tab.validProperty.not();
exportButton.disableProperty().bind(tabInvalidity.or(exportingProperty));
exportButton.setText(Config.getString("export.dialog.export"));
clearStatus();
}
| Create all the export tabs that should appear as part of this dialogue.
|
private void createTabs()
{
Window asWindow = this.asWindow();
String projectName = project.getProjectName();
File defaultExportDir = project.getProjectDir().getParentFile();
addTab(new ExportPublishTab(project, this, scenarioSaver, scenarioInfo));
addTab(new ExportAppTab(asWindow, scenarioInfo, projectName, defaultExportDir));
addTab(new ExportProjectTab(asWindow, scenarioInfo, projectName, defaultExportDir));
tabbedPane.getTabs().setAll(exportTabs.values());
tabbedPane.tabMinWidthProperty()
.bind(widthProperty().divide(tabbedPane.getTabs().size()).subtract(30));
}
| Adds a tab to the exportTabs map, by placing the function of the tab
| as the key to the tab stored in the value.
|
| @param exportTab An Export tab to be added to the exportTabs map.
|
private void addTab(ExportTab exportTab)
{
exportTabs.put(exportTab.getFunction(), exportTab);
}
| Tell this dialog that the publish (to the Gallery) has finished and whether it was successful.
|
| @param success True if the publish to the Gallery was successful, otherwise false.
| @param msg The message to be shown next to progress bar. Could be null, which
| means do not show any message.
|
public void publishFinished(boolean success, String msg)
{
getSelectedTab().postPublish(success);
setProgress(false, msg);
if (success)
{
SwingUtilities.invokeLater(() -> Utility.openWebBrowser(Config.getPropString("greenfoot.gameserver.address") + "/home"));
}
}
| We now know the upload size.
| @param bytes The maximum number of bytes will be transmitted
|
public void setUploadSize(int bytes)
{
uploadSize = bytes;
progressBar.setProgress(0);
}
| The upload is progressing, a certain number of bytes were just transmitted.
| @param bytes The number of bytes just transmitted
|
public void progressMade(int bytes)
{
progressBar.setProgress(progressBar.getProgress() + ((double)bytes / uploadSize));
}
}
. ExportDialog
. makeDialog
. setProgress
. setExportButtonText
. doExport
top,
use,
map,
interface ExportThread
. ExportThread
. run
. clearStatus
. getSelectedFunction
. getSelectedTab
. selectTab
. updateControls
. createTabs
. addTab
. publishFinished
. setUploadSize
. progressMade
376 neLoCode
+ 45 LoComm