// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.client.explorer.commands;
import java.util.Date;
import com.google.appinventor.client.Ode;
import com.google.appinventor.client.OdeAsyncCallback;
import static com.google.appinventor.client.Ode.MESSAGES;
import com.google.appinventor.shared.rpc.RpcResult;
import com.google.appinventor.shared.rpc.project.ProjectNode;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.appinventor.client.output.MessagesOutput;
import com.google.appinventor.client.explorer.commands.MiniProgressBar;
/**
* Command for displaying a barcode for the target of a project.
*
* <p/>This command is often chained with SaveAllEditorsCommand and BuildCommand.
*
* @author markf@google.com (Mark Friedman)
*/
public class ShowProgressBarCommand extends ChainableCommand {
// The build target
private int counter = 0;
private int currentProgress = 0;
// 0 means just initialize, 1 means click once, 2 means click twice
private int progressBarShow = 0;
private String target;
private ChainableCommand nextCommand;
private final String buildRequestTime;
private static final int WAIT_INTERVAL_MILLIS = 5000;
private ProjectNode projectNode;
private ProgressBarDialogBox minPB;
private String serviceName;
/**
* Creates a new command for showing a barcode for the target of a project.
*
* @param target the build target
* @param nextCommand
* @param serviceName
*/
public ShowProgressBarCommand(String target,ChainableCommand nextCommand, String serviceName) {
// Since we don't know when the barcode dialog is finished, we can't
// support a command after this one.
super(nextCommand); // no next command
this.target = target;
this.nextCommand = nextCommand;
this.buildRequestTime = DateTimeFormat.getMediumDateTimeFormat().format(new Date());
this.serviceName = serviceName;
}
@Override
public boolean willCallExecuteNextCommand() {
return true;
}
@Override
//the main function to be called
public void execute(final ProjectNode node) {
final Ode ode = Ode.getInstance();
if (counter<1) {
projectNode = node;
minPB = new ProgressBarDialogBox();
minPB.center();
executeNextCommand(node);
}
counter++;
//call back function - dynamic DialogBox
OdeAsyncCallback<RpcResult> callback = new OdeAsyncCallback<RpcResult>(MESSAGES.buildError()) // failure message
{
@Override
public void onSuccess(RpcResult result) {
minPB.addMessages(node.getName(),result);
if (result.succeeded()) {
minPB.hide();
} else if (progressBarShow != 2 ) {
// Build isn't done yet
Timer timer = new Timer() {
@Override
public void run() {
execute(node); }
};
// TODO(user): Maybe do an exponential backoff here.
timer.schedule(WAIT_INTERVAL_MILLIS);
}
}
@Override
public void onFailure(Throwable caught) {
super.onFailure(caught);
executionFailedOrCanceled();}
};
ode.getProjectService().getBuildResult(node.getProjectId(), target, callback);
}
class ProgressBarDialogBox extends DialogBox{
public ClickHandler buttonHandler;
public Button dismissButton = new Button(MESSAGES.dismissButton());
public HTML warningLabel;
public VerticalPanel contentPanel;
public HorizontalPanel buttonPanel = new HorizontalPanel();
public HorizontalPanel warningPanel = new HorizontalPanel();
public MiniProgressBar mpb = new MiniProgressBar(0,100,0);
//constructor
ProgressBarDialogBox() {
super(false, true);
setStylePrimaryName("ode-DialogBox");
setText(projectNode.getName() + " " + MESSAGES.ProgressBarFor());
//click handler for the mini html buttons
buttonHandler = new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
hide();
progressBarShow++;
}
};
//declare the ok button
dismissButton.addClickHandler(buttonHandler);
buttonPanel.setHorizontalAlignment(HorizontalPanel.ALIGN_CENTER);
dismissButton.setVisible(false); // we don't need the button unless we get an error
//warning label
warningLabel = new HTML("");
warningLabel.setWordWrap(true);
warningLabel.setWidth("60em"); // set width to get the text to wrap
//warning panel
warningPanel.setHorizontalAlignment(HorizontalPanel.ALIGN_LEFT);
warningPanel.add(warningLabel);
// button panel
buttonPanel.add(dismissButton);
buttonPanel.setSize("100%", "24px");
//content panel
contentPanel = new VerticalPanel();
contentPanel.add(mpb);
contentPanel.add(warningPanel);
contentPanel.add(buttonPanel);
setWidget(contentPanel);
}
public void clear() {
warningLabel.setHTML("");
}
public void addMessages(String projectName, RpcResult result) {
if (result.succeeded()) {
show();
mpb.setProgress(100);
if(serviceName == "DownloadAction") {
warningLabel.setHTML("<br />The APK file will be saved in the download folder.");
} else if (serviceName == "DownloadToPhoneAction"){
warningLabel.setHTML("<br />The APK file will be installed in the phone.");
} else {
warningLabel.setHTML("<br />Waiting for the barcode.");
}
} else {
try {
currentProgress = Math.max(currentProgress,
Integer.parseInt(result.getOutput()));
mpb.setProgress(currentProgress);
if (currentProgress <= 10) {
warningLabel.setHTML("<br />Preparing application icon");
} else if (currentProgress < 15) {
warningLabel.setHTML("<br />Determining permissions");
} else if (currentProgress < 20) {
warningLabel.setHTML("<br />Generating application information");
} else if (currentProgress < 35) {
warningLabel.setHTML("<br />Compiling part 1");
} else if (currentProgress < 85) {
warningLabel.setHTML("<br />Compiling part 2 (please wait)");
} else if (currentProgress < 90) {
warningLabel.setHTML("<br />Preparing final package");
} else if (currentProgress <= 95) {
warningLabel.setHTML("<br />Building APK");
} else {
if(serviceName == "DownloadAction") {
warningLabel.setHTML("<br />The APK file will be saved in your downloads folder.");
} else if (serviceName == "DownloadToPhoneAction") {
warningLabel.setHTML("<br />The APK file will be installed in the phone.");
} else {
warningLabel.setHTML("<br />Waiting for the barcode.");
}
}
} catch (NumberFormatException e) {
// If the result is an error message, then the number parse will fail,
// so we pick up the case of a compilation failure here.
mpb.setProgress(0);
// show the dismiss button to dismiss error
dismissButton.setVisible(true);
warningLabel.setHTML(MESSAGES.unableToCompile(result.getOutput()));
}
}
}
}
}