From 76aa5675c7b1a5488593bd2ca51b8db910605518 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Fri, 7 Aug 2015 17:42:25 +0200 Subject: [client] Implement progress bar for uploads in main window --- .../openslx/dozmod/filetransfer/TransferEvent.java | 5 +- .../java/org/openslx/dozmod/gui/MainWindow.java | 21 +++- .../openslx/dozmod/gui/activity/ActivityPanel.java | 14 +-- .../openslx/dozmod/gui/activity/UploadPanel.java | 119 +++++++++++++++++++-- .../openslx/dozmod/gui/window/MainMenuWindow.java | 6 +- .../dozmod/gui/wizard/page/ImageUploadPage.java | 86 +-------------- 6 files changed, 146 insertions(+), 105 deletions(-) diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/filetransfer/TransferEvent.java b/dozentenmodul/src/main/java/org/openslx/dozmod/filetransfer/TransferEvent.java index 4206da81..af63b0c6 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/filetransfer/TransferEvent.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/filetransfer/TransferEvent.java @@ -14,7 +14,8 @@ public class TransferEvent { */ public final String speed; /** - * Estimated remaining time, human readable. null == not updated + * Estimated remaining time, human readable. null == not + * updated */ public final String remaining; /** @@ -44,7 +45,7 @@ public class TransferEvent { if (remainingRaw == 0) { this.remaining = null; } else { - this.remaining = FormatHelper.formatMilliseconds(remainingRaw, false); + this.remaining = FormatHelper.formatMilliseconds(remainingRaw + 30000, false); } this.errorMessage = errorMessage; } diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/MainWindow.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/MainWindow.java index d5b4d4e3..295cf413 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/MainWindow.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/MainWindow.java @@ -10,7 +10,6 @@ import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -22,11 +21,10 @@ import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; +import javax.swing.JSeparator; import org.apache.log4j.Logger; import org.apache.thrift.TException; -import org.openslx.bwlp.thrift.iface.TAuthorizationException; -import org.openslx.bwlp.thrift.iface.TInternalServerError; import org.openslx.dozmod.App; import org.openslx.dozmod.Config; import org.openslx.dozmod.Config.SavedSession; @@ -202,6 +200,8 @@ public abstract class MainWindow { mainWindow.getContentPane().add(win, BorderLayout.PAGE_START); } activityPanel.setLayout(new BoxLayout(activityPanel, BoxLayout.PAGE_AXIS)); + activityPanel.setVisible(false); + activityPanel.add(new JSeparator()); mainWindow.getContentPane().add(activityPanel, BorderLayout.PAGE_END); // center the window on the primary monitor @@ -271,8 +271,19 @@ public abstract class MainWindow { } public static void addUpload(UploadWizardState state) { - activities.add(new UploadPanel(activityPanel, state)); - activityPanel.validate(); + UploadPanel panel = new UploadPanel(state); + activities.add(panel); + activityPanel.add(panel); + activityPanel.setVisible(true); + mainWindow.validate(); + } + + public static void removeActivity(ActivityPanel panel) { + activities.remove(panel); + activityPanel.remove(panel); + if (activities.isEmpty()) + activityPanel.setVisible(false); + mainWindow.validate(); } private static void createMenu() { diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/activity/ActivityPanel.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/activity/ActivityPanel.java index eb651fef..768ee82d 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/activity/ActivityPanel.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/activity/ActivityPanel.java @@ -2,14 +2,10 @@ package org.openslx.dozmod.gui.activity; import javax.swing.JPanel; -public abstract class ActivityPanel extends JPanel { - - private final JPanel container; +import org.openslx.dozmod.gui.MainWindow; - public ActivityPanel(JPanel container) { - this.container = container; - container.add(this); - } +@SuppressWarnings("serial") +public abstract class ActivityPanel extends JPanel { /** * If this activity wants to prevent the user from closing the application, @@ -20,4 +16,8 @@ public abstract class ActivityPanel extends JPanel { */ public abstract boolean wantConfirmQuit(); + protected final void close() { + MainWindow.removeActivity(this); + } + } diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/activity/UploadPanel.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/activity/UploadPanel.java index 430f6ae6..46ffb51c 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/activity/UploadPanel.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/activity/UploadPanel.java @@ -1,5 +1,6 @@ package org.openslx.dozmod.gui.activity; +import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GridLayout; @@ -13,20 +14,43 @@ import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; +import org.apache.log4j.Logger; +import org.openslx.dozmod.filetransfer.TransferEvent; +import org.openslx.dozmod.filetransfer.TransferEventListener; +import org.openslx.dozmod.gui.Gui; import org.openslx.dozmod.gui.control.BlockProgressBar; +import org.openslx.dozmod.gui.helper.MessageType; import org.openslx.dozmod.state.UploadWizardState; +import org.openslx.thrifthelper.ThriftManager; +import org.openslx.util.QuickTimer; +import org.openslx.util.QuickTimer.Task; @SuppressWarnings("serial") -public class UploadPanel extends ActivityPanel { +public class UploadPanel extends ActivityPanel implements TransferEventListener { + + private static final Logger LOGGER = Logger.getLogger(UploadPanel.class); private final JLabel lblStatus; + private final JLabel lblError; + + private final JLabel lblSpeed; + + private final JLabel lblRemaining; + private final BlockProgressBar progress; private final UploadWizardState state; - public UploadPanel(JPanel container, UploadWizardState state) { - super(container); + private final UploadPanel panel = this; + + private final Color defaultLabelColor; + + private int errorCountdown = 0; + + private final JButton btnClose; + + public UploadPanel(UploadWizardState state) { this.state = state; setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); @@ -42,9 +66,9 @@ public class UploadPanel extends ActivityPanel { header.add(Box.createHorizontalGlue()); header.add(new JLabel(state.diskFile.getName())); header.add(Box.createHorizontalStrut(10)); - JButton button = new JButton("Knopf"); - button.addActionListener(new ButtonAction()); - header.add(button); + btnClose = new JButton("Abbrechen"); + btnClose.addActionListener(new ButtonAction()); + header.add(btnClose); add(header); // ProgressBar JPanel progressWrapper = new JPanel(); @@ -54,17 +78,98 @@ public class UploadPanel extends ActivityPanel { progress = new BlockProgressBar(null); progressWrapper.add(progress); add(progressWrapper); + // Speed & error + JPanel footer = new JPanel(); + footer.setLayout(new BoxLayout(footer, BoxLayout.LINE_AXIS)); + lblError = new JLabel(); + lblSpeed = new JLabel("-"); + lblRemaining = new JLabel("-"); + lblSpeed.setMinimumSize(new Dimension(50, 0)); + lblRemaining.setMinimumSize(new Dimension(60, 0)); + footer.add(lblError); + footer.add(Box.createGlue()); + footer.add(lblSpeed); + footer.add(Box.createRigidArea(new Dimension(6, 6))); + footer.add(lblRemaining); + add(footer); + defaultLabelColor = lblError.getForeground(); + state.uploadTask.addListener(this); } @Override public boolean wantConfirmQuit() { - return false; + return state != null && state.uploadTask != null && !state.uploadTask.isCanceled(); } private class ButtonAction implements ActionListener { @Override public void actionPerformed(ActionEvent e) { + if (!state.uploadTask.isCanceled()) { + if (!Gui.showMessageBox(panel, "Wollen Sie diesen Transfer wirklich abbrechen?", + MessageType.QUESTION_YESNO, null, null)) + return; + state.uploadTask.cancel(); + QuickTimer.scheduleOnce(new Task() { + @Override + public void fire() { + try { + ThriftManager.getSatClient().cancelUpload(state.transferInformation.getToken()); + } catch (Exception ex) { + LOGGER.debug("Remote error while canceling upload for " + state.uuid, ex); + } + } + }); + } + state.uploadTask.removeListener(panel); + close(); } } + @Override + public void update(final TransferEvent event) { + Gui.asyncExec(new Runnable() { + @Override + public void run() { + // Any error message? + if (event.errorMessage != null && !event.errorMessage.isEmpty()) { + lblError.setText(event.errorMessage); + lblError.setForeground(Color.RED); + errorCountdown = 20; + } else if (errorCountdown > 0) { + errorCountdown--; + if (errorCountdown == 10) { + lblError.setForeground(defaultLabelColor); + } else if (errorCountdown == 0) { + lblError.setText(""); + } + } + // Status? + if (event.state != null) { + switch (event.state) { + case ERROR: + errorCountdown = 20; + break; + case FINISHED: + btnClose.setText("Schließen"); + lblRemaining.setText("-"); + state.uploadTask.removeListener(panel); + break; + } + lblStatus.setText(event.state.toString()); + } + // Remaining + Speed + if (event.remainingRaw != 0) { + lblRemaining.setText(event.remaining); + } + if (event.speedRaw != 0) { + lblSpeed.setText(event.speed); + } + // Progress bar + if (event.progress != null) { + progress.setStatus(event.progress); + } + panel.validate(); + } + }); + } } diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/MainMenuWindow.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/MainMenuWindow.java index a4a73510..066ef54c 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/MainMenuWindow.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/MainMenuWindow.java @@ -19,6 +19,7 @@ import org.openslx.util.QuickTimer.Task; import com.google.gson.Gson; +@SuppressWarnings("serial") public class MainMenuWindow extends MainMenuWindowLayout { public MainMenuWindow() { @@ -60,7 +61,7 @@ public class MainMenuWindow extends MainMenuWindowLayout { private class GResult { private String tbUrl; } - + private int loadImageToControl(int start, GResult[] results, final JButton control) { if (start >= results.length) start = results.length - 1; @@ -101,7 +102,8 @@ public class MainMenuWindow extends MainMenuWindowLayout { String term = terms[(int) Math.floor(Math.random() * terms.length)] + "+" + terms[(int) Math.floor(Math.random() * terms.length)]; try { - URL oracle = new URL("http://ajax.googleapis.com/ajax/services/search/images?v=1.0&rsz=8&q=" + term); + URL oracle = new URL( + "http://ajax.googleapis.com/ajax/services/search/images?v=1.0&rsz=8&q=" + term); Reader reader = new InputStreamReader(oracle.openStream()); Gson gson = new Gson(); GMain data = gson.fromJson(reader, GMain.class); diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/ImageUploadPage.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/ImageUploadPage.java index afb0fed8..e7f9700f 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/ImageUploadPage.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/ImageUploadPage.java @@ -20,10 +20,9 @@ import javax.swing.filechooser.FileNameExtensionFilter; import org.apache.log4j.Logger; import org.openslx.bwlp.thrift.iface.TImageDataException; import org.openslx.dozmod.Config; -import org.openslx.dozmod.filetransfer.TransferEvent; -import org.openslx.dozmod.filetransfer.TransferEventListener; import org.openslx.dozmod.filetransfer.UploadTask; import org.openslx.dozmod.gui.Gui; +import org.openslx.dozmod.gui.MainWindow; import org.openslx.dozmod.gui.helper.MessageType; import org.openslx.dozmod.gui.wizard.Wizard; import org.openslx.dozmod.gui.wizard.layout.ImageUploadPageLayout; @@ -31,8 +30,6 @@ import org.openslx.dozmod.state.UploadWizardState; import org.openslx.dozmod.thrift.MetaDataCache; import org.openslx.dozmod.thrift.Session; import org.openslx.thrifthelper.ThriftManager; -import org.openslx.util.QuickTimer; -import org.openslx.util.QuickTimer.Task; import org.openslx.util.Util; import org.openslx.util.vm.VmMetaData.HardDisk; import org.openslx.util.vm.VmwareMetaData; @@ -241,20 +238,6 @@ public class ImageUploadPage extends ImageUploadPageLayout { + state.diskFile.getAbsolutePath(), MessageType.ERROR, LOGGER, e); return false; } - // -- add listener for upload status/progress -- - state.uploadTask.addListener(new TransferEventListener() { - @Override - public void update(final TransferEvent event) { - final TransferEventListener listener = this; - Gui.asyncExec(new Runnable() { - @Override - public void run() { - // always callback to gui - processTransferStatus(listener, event); - } - }); - } - }); new Thread(state.uploadTask).start(); do { Util.sleep(5); @@ -265,74 +248,13 @@ public class ImageUploadPage extends ImageUploadPageLayout { if (state.uploadTask.getTransferCount() == 0) { Gui.showMessageBox(this, "Aufbau der Verbindung zum Hochladen fehlgeschlagen", MessageType.ERROR, LOGGER, null); + state.uploadTask.cancel(); + state.uploadTask = null; return false; } + MainWindow.addUpload(state); // -- check image creation -- blockProgressBar.setVisible(true); return true; } - - /** - * Evaluates the transfer's state and show feedback to the user based on the - * state. - * - * @param listener - */ - private void processTransferStatus(TransferEventListener listener, TransferEvent event) { - if (!getTopLevelAncestor().isVisible()) { - if (state.uploadTask != null) { - state.uploadTask.removeListener(listener); - } - return; - } - if (!isVisible()) - return; - // always update progress bar - if (event.progress != null) { - // TODO: Maybe only display percentage in the wizard pages once we have the status bar in mainwindow - blockProgressBar.setStatus(event.progress); - } - if (event.state == null) - return; - // TODO: Move user interaction to central listener when we have it - switch (event.state) { - case FINISHED: - Gui.showMessageBox(this, "Upload abgeschlossen.", MessageType.INFO, LOGGER, null); - break; - case ERROR: - if (state.uploadTask != null && state.uploadTask.isCanceled()) - return; - Gui.showMessageBox(this, "Fehler beim Upload: " + event.errorMessage, MessageType.ERROR, LOGGER, - null); - // user wants to try again, just reset transferInformation ... - state.uploadTask = null; - break; - case WORKING: - case IDLE: - break; - default: - LOGGER.warn("Unhandled transfer state: " + event.state); - break; - } - } - - // TODO: In main control in main window.... - private void cancelUpload() { - LOGGER.debug("Cancelling upload ..."); - // first tell the server about this - QuickTimer.scheduleOnce(new Task() { - @Override - public void fire() { - try { - ThriftManager.getSatClient().cancelUpload(state.transferInformation.getToken()); - } catch (Exception e) { - LOGGER.debug("Remote error while canceling upload for " + state.uuid, e); - } - // Then cancel the task - state.uploadTask.cancel(); - } - }); - setPageComplete(false); - blockProgressBar.setVisible(false); - } } -- cgit v1.2.3-55-g7522