mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GT-2376: added new task monitor service
This commit is contained in:
parent
538cbc1226
commit
f57af0b730
28 changed files with 1363 additions and 558 deletions
|
@ -67,6 +67,7 @@ public class DialogComponentProvider
|
|||
protected JButton dismissButton;
|
||||
private boolean isAlerting;
|
||||
private JLabel statusLabel;
|
||||
private JLabel subStatusLabel;
|
||||
private JPanel statusProgPanel; // contains status panel and progress panel
|
||||
private Timer showTimer;
|
||||
private TaskScheduler taskScheduler;
|
||||
|
@ -608,6 +609,11 @@ public class DialogComponentProvider
|
|||
public void setStatusText(String text) {
|
||||
setStatusText(text, MessageType.INFO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubStatusText(String text) {
|
||||
setSubStatusText(text, MessageType.INFO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text in the dialog's status line using the specified message type to control
|
||||
|
@ -621,12 +627,24 @@ public class DialogComponentProvider
|
|||
setStatusText(message, type, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubStatusText(String message, MessageType type) {
|
||||
setSubStatusText(message, type, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatusText(String message, MessageType type, boolean alert) {
|
||||
|
||||
String text = StringUtils.isBlank(message) ? " " : message;
|
||||
SystemUtilities.runIfSwingOrPostSwingLater(() -> doSetStatusText(text, type, alert));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubStatusText(String message, MessageType type, boolean alert) {
|
||||
|
||||
String text = StringUtils.isBlank(message) ? " " : message;
|
||||
SystemUtilities.runIfSwingOrPostSwingLater(() -> doSetSubStatusText(text, type, alert));
|
||||
}
|
||||
|
||||
private void doSetStatusText(String text, MessageType type, boolean alert) {
|
||||
|
||||
|
@ -641,6 +659,20 @@ public class DialogComponentProvider
|
|||
alertMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private void doSetSubStatusText(String text, MessageType type, boolean alert) {
|
||||
|
||||
SystemUtilities.assertThisIsTheSwingThread(
|
||||
"Setting text must be performed on the Swing thread");
|
||||
|
||||
subStatusLabel.setText(text);
|
||||
subStatusLabel.setForeground(getStatusColor(type));
|
||||
updateStatusToolTip();
|
||||
|
||||
if (alert) {
|
||||
alertMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals for this dialog to visually draw the user's attention to the status text
|
||||
|
@ -679,11 +711,13 @@ public class DialogComponentProvider
|
|||
// normal Swing mechanism may not have yet happened).
|
||||
mainPanel.validate();
|
||||
statusLabel.setVisible(false); // disable painting in this dialog so we don't see double
|
||||
subStatusLabel.setVisible(false);
|
||||
Animator animator = AnimationUtils.pulseComponent(statusLabel, 1);
|
||||
animator.addTarget(new TimingTargetAdapter() {
|
||||
@Override
|
||||
public void end() {
|
||||
statusLabel.setVisible(true);
|
||||
subStatusLabel.setVisible(true);
|
||||
alertFinishedCallback.call();
|
||||
isAlerting = false;
|
||||
}
|
||||
|
@ -755,12 +789,7 @@ public class DialogComponentProvider
|
|||
private void showProgressBar(String localTitle, boolean hasProgress, boolean canCancel) {
|
||||
taskMonitorComponent.setTaskName(localTitle);
|
||||
taskMonitorComponent.showProgress(hasProgress);
|
||||
if (canCancel) {
|
||||
taskMonitorComponent.showCancelButton(true);
|
||||
}
|
||||
else {
|
||||
taskMonitorComponent.showCancelButton(false);
|
||||
}
|
||||
taskMonitorComponent.setCancelButtonVisibility(canCancel);
|
||||
progressCardLayout.show(statusProgPanel, PROGRESS);
|
||||
rootPanel.validate();
|
||||
}
|
||||
|
@ -799,18 +828,29 @@ public class DialogComponentProvider
|
|||
public void clearStatusText() {
|
||||
SystemUtilities.runIfSwingOrPostSwingLater(() -> {
|
||||
statusLabel.setText(" ");
|
||||
subStatusLabel.setText(" ");
|
||||
updateStatusToolTip();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the current status in the dialogs status line=
|
||||
* Returns the current status in the dialogs status line
|
||||
*
|
||||
* @return the status text
|
||||
*/
|
||||
public String getStatusText() {
|
||||
return statusLabel.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the secondary status message
|
||||
*
|
||||
* @return the secondary status message
|
||||
*/
|
||||
public String getSubStatusText() {
|
||||
return subStatusLabel.getText();
|
||||
}
|
||||
|
||||
protected JLabel getStatusLabel() {
|
||||
return statusLabel;
|
||||
}
|
||||
|
@ -901,6 +941,14 @@ public class DialogComponentProvider
|
|||
updateStatusToolTip();
|
||||
}
|
||||
});
|
||||
|
||||
subStatusLabel = new JLabel();
|
||||
subStatusLabel.setName("subStatusLabel");
|
||||
subStatusLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
subStatusLabel.setForeground(Color.blue);
|
||||
subStatusLabel.setFont(subStatusLabel.getFont().deriveFont(Font.ITALIC));
|
||||
subStatusLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||
subStatusLabel.setFont(subStatusLabel.getFont().deriveFont(11.0f));
|
||||
|
||||
// use a strut panel so the size of the message area does not change if we make
|
||||
// the message label not visible
|
||||
|
@ -908,6 +956,7 @@ public class DialogComponentProvider
|
|||
|
||||
panel.add(Box.createVerticalStrut(height), BorderLayout.WEST);
|
||||
panel.add(statusLabel, BorderLayout.CENTER);
|
||||
panel.add(subStatusLabel, BorderLayout.SOUTH);
|
||||
return panel;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.util.task;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.util.AnimatedIcon;
|
||||
import resources.ResourceManager;
|
||||
|
||||
/**
|
||||
* Panel that displays an animation of the Ghidra dragon chomping bits.
|
||||
*/
|
||||
public class ChompingBitsAnimationPanel extends JPanel {
|
||||
|
||||
public ChompingBitsAnimationPanel() {
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
List<Icon> iconList = new ArrayList<>();
|
||||
iconList.add(ResourceManager.loadImage("images/eatbits1.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/eatbits2.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/eatbits3.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/eatbits4.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/eatbits5.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/eatbits6.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/eatbits7.png"));
|
||||
AnimatedIcon icon = new AnimatedIcon(iconList, 200, 0);
|
||||
setSize(new Dimension(200, 100));
|
||||
add(new JLabel(icon));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.util.task;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.util.AnimatedIcon;
|
||||
import resources.ResourceManager;
|
||||
|
||||
/**
|
||||
* Panel that displays an animation of a spinning hourglass
|
||||
*/
|
||||
public class HourglassAnimationPanel extends JPanel {
|
||||
|
||||
public HourglassAnimationPanel() {
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
List<Icon> iconList = new ArrayList<>();
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_01.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_02.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_02.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_03.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_03.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_04.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_04.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_05.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_05.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_06.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_06.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_07.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_07.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_08.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_08.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_09.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_10.png"));
|
||||
iconList.add(ResourceManager.loadImage("images/hourglass24_11.png"));
|
||||
AnimatedIcon progressIcon = new AnimatedIcon(iconList, 150, 0);
|
||||
|
||||
add (new JLabel(progressIcon), BorderLayout.CENTER);
|
||||
}
|
||||
}
|
|
@ -245,7 +245,7 @@ public class RunManager {
|
|||
* @param showCancel true means to show the cancel button
|
||||
*/
|
||||
public void showCancelButton(boolean showCancel) {
|
||||
monitor.showCancelButton(showCancel);
|
||||
monitor.setCancelButtonVisibility(showCancel);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.util.task;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
/**
|
||||
* {@link TaskMonitor} that restricts users from being able to update the progress bar. The class
|
||||
* is initialized with another, fully-featured monitor and forwards all requests to it,
|
||||
* but squashes calls to methods that are not allowed.
|
||||
* <p>
|
||||
* Note: Two instances of this class are deemed equal if they have the same {@link #parentMonitor},
|
||||
* hence the override of {@link #hashCode()} and {@link #equals(Object)}.
|
||||
*/
|
||||
public class SecondaryTaskMonitor implements TaskMonitor {
|
||||
|
||||
private TaskMonitor parentMonitor;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param parentMonitor the fully-functional task monitor this is based off of
|
||||
*/
|
||||
public SecondaryTaskMonitor(TaskMonitor parentMonitor) {
|
||||
this.parentMonitor = parentMonitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to ensure that clients who have this type of monitor will only update the
|
||||
* secondary message when using this method
|
||||
*
|
||||
* @param message the message string to display
|
||||
*/
|
||||
@Override
|
||||
public void setMessage(String message) {
|
||||
if (parentMonitor instanceof TaskDialog) {
|
||||
((TaskDialog) parentMonitor).setSecondaryMessage(message);
|
||||
}
|
||||
parentMonitor.setMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelEnabled(boolean enable) {
|
||||
parentMonitor.setCancelEnabled(enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInitialized(boolean init) {
|
||||
parentMonitor.setInitialized(init);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelEnabled() {
|
||||
return parentMonitor.isCancelEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return parentMonitor.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void cancel() {
|
||||
parentMonitor.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void clearCanceled() {
|
||||
parentMonitor.clearCanceled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCanceled() throws CancelledException {
|
||||
parentMonitor.checkCanceled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCancelledListener(CancelledListener listener) {
|
||||
parentMonitor.addCancelledListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCancelledListener(CancelledListener listener) {
|
||||
parentMonitor.removeCancelledListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaximum() {
|
||||
return parentMonitor.getMaximum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getProgress() {
|
||||
return parentMonitor.getProgress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShowProgressValue(boolean showProgressValue) {
|
||||
// squash
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgress(long value) {
|
||||
// squash
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(long max) {
|
||||
// squash
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaximum(long max) {
|
||||
// squash
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIndeterminate(boolean indeterminate) {
|
||||
// squash
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementProgress(long incrementAmount) {
|
||||
// squash
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((parentMonitor == null) ? 0 : parentMonitor.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SecondaryTaskMonitor other = (SecondaryTaskMonitor) obj;
|
||||
if (!Objects.equals(parentMonitor, other.parentMonitor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -15,20 +15,20 @@
|
|||
*/
|
||||
package ghidra.util.task;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.DockingWindowManager;
|
||||
import docking.util.AnimatedIcon;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.label.GIconLabel;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.timer.GTimer;
|
||||
import resources.ResourceManager;
|
||||
|
||||
/**
|
||||
* Dialog that is displayed to show activity for a Task that is running outside of the
|
||||
|
@ -36,25 +36,48 @@ import resources.ResourceManager;
|
|||
*/
|
||||
public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||
|
||||
/** Timer used to give the task a chance to complete */
|
||||
private static final int SLEEPY_TIME = 10;
|
||||
|
||||
/** Amount of time to wait before showing the monitor dialog */
|
||||
private final static int MAX_DELAY = 200000;
|
||||
|
||||
public final static int DEFAULT_WIDTH = 275;
|
||||
|
||||
private Timer showTimer;
|
||||
private TaskMonitorComponent monitorComponent;
|
||||
private AtomicInteger taskID = new AtomicInteger();
|
||||
private boolean canCancel;
|
||||
private Runnable updateMessage;
|
||||
private Runnable closeDialog;
|
||||
private Runnable enableCancelButton;
|
||||
private String newMessage;
|
||||
private boolean cancelState = true;
|
||||
private Component centerOnComp;
|
||||
private Runnable shouldCancelRunnable;
|
||||
private boolean done;
|
||||
private boolean taskDone;
|
||||
private JPanel mainPanel;
|
||||
private ChompingBitsAnimationPanel chompingBitsPanel;
|
||||
private TaskMonitorComponent monitorComponent;
|
||||
|
||||
/** Creates new TaskDialog
|
||||
/** Runnable that updates the primary message label in the dialog */
|
||||
private Runnable updatePrimaryMessageRunnable;
|
||||
|
||||
/** Runnable that updates the secondary message label in the dialog */
|
||||
private Runnable updateSecondaryMessageRunnable;
|
||||
|
||||
/** If not null, then the value of the string has yet to be rendered */
|
||||
private String newPrimaryMessage;
|
||||
|
||||
/** If not null, then the value of the string has yet to be rendered */
|
||||
private String newSecondaryMessage;
|
||||
|
||||
/**
|
||||
* Indicates if this monitor has been initialized for progress updates. If this value
|
||||
* is set to true, the {@link TaskMonitorService} will not return the monitor to
|
||||
* another caller (only one client should be able to update progress at a time).
|
||||
*/
|
||||
private AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
|
||||
private SecondaryTaskMonitor secondaryTaskMonitor;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param centerOnComp component to be centered over when shown,
|
||||
* otherwise center over parent. If both centerOnComp and parent
|
||||
* are null, dialog will be centered on screen.
|
||||
|
@ -65,7 +88,9 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
|||
task.hasProgress());
|
||||
}
|
||||
|
||||
/** Creates a new TaskDialog.
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param task the Task that this dialog will be associated with
|
||||
*/
|
||||
public TaskDialog(Task task) {
|
||||
|
@ -73,18 +98,20 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Construct new TaskDialog.
|
||||
* Constructor
|
||||
*
|
||||
* @param title title for the dialog
|
||||
* @param canCancel true if the task can be canceled
|
||||
* @param isModal true if the dialog should be modal
|
||||
* @param hasProgress true if the dialog should show a progress bar
|
||||
*/
|
||||
public TaskDialog(String title, boolean canCancel, boolean isModal, boolean hasProgress) {
|
||||
this(null, title, isModal, canCancel, true /*hasProgress*/);
|
||||
this(null, title, isModal, canCancel, hasProgress);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct new TaskDialog.
|
||||
* Constructor
|
||||
*
|
||||
* @param centerOnComp component to be centered over when shown, otherwise center over
|
||||
* parent. If both centerOnComp is null, then the active window will be used
|
||||
* @param title title for the dialog
|
||||
|
@ -99,8 +126,21 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
|||
setup(canCancel, hasProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInitialized(boolean init) {
|
||||
this.initialized.set(init);
|
||||
}
|
||||
|
||||
private void setup(boolean canCancel, boolean hasProgress) {
|
||||
this.canCancel = canCancel;
|
||||
monitorComponent = new TaskMonitorComponent(false, false);
|
||||
chompingBitsPanel = new ChompingBitsAnimationPanel();
|
||||
|
||||
setCancelEnabled(canCancel);
|
||||
setRememberLocation(false);
|
||||
setRememberSize(false);
|
||||
setTransient(true);
|
||||
|
@ -108,13 +148,18 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
|||
close();
|
||||
dispose();
|
||||
};
|
||||
updateMessage = () -> {
|
||||
setStatusText(newMessage);
|
||||
updatePrimaryMessageRunnable = () -> {
|
||||
setStatusText(newPrimaryMessage);
|
||||
synchronized (TaskDialog.this) {
|
||||
newMessage = null;
|
||||
newPrimaryMessage = null;
|
||||
}
|
||||
};
|
||||
updateSecondaryMessageRunnable = () -> {
|
||||
setSubStatusText(newSecondaryMessage);
|
||||
synchronized (TaskDialog.this) {
|
||||
newSecondaryMessage = null;
|
||||
}
|
||||
};
|
||||
enableCancelButton = () -> TaskDialog.super.setCancelEnabled(cancelState);
|
||||
shouldCancelRunnable = () -> {
|
||||
int currentTaskID = taskID.get();
|
||||
|
||||
|
@ -124,9 +169,9 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
|||
}
|
||||
};
|
||||
|
||||
monitorComponent = new TaskMonitorComponent(false, false);
|
||||
mainPanel = new JPanel(new BorderLayout());
|
||||
addWorkPanel(mainPanel);
|
||||
|
||||
if (hasProgress) {
|
||||
installProgressMonitor();
|
||||
}
|
||||
|
@ -142,6 +187,11 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
|||
setHelpLocation(new HelpLocation("Tool", "TaskDialog"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a dialog asking the user if they really, really want to cancel the task
|
||||
*
|
||||
* @return true if the task should be cancelled
|
||||
*/
|
||||
protected boolean promptToVerifyCancel() {
|
||||
boolean userSaysYes = OptionDialog.showYesNoDialog(getComponent(), "Cancel?",
|
||||
"Do you really want to cancel \"" + getTitle() + "\"?") == OptionDialog.OPTION_ONE;
|
||||
|
@ -150,34 +200,24 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates the main work panel for the dialog
|
||||
* Adds the panel that contains the progress bar to the dialog
|
||||
*/
|
||||
private void installProgressMonitor() {
|
||||
SystemUtilities.runIfSwingOrPostSwingLater(() -> {
|
||||
mainPanel.removeAll();
|
||||
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(20, 10, 5, 10));
|
||||
panel.add(monitorComponent);
|
||||
mainPanel.add(panel, BorderLayout.NORTH);
|
||||
|
||||
mainPanel.add(monitorComponent, BorderLayout.CENTER);
|
||||
repack();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the panel that contains the chomping bits animation to the dialog. This should only be
|
||||
* called if the dialog has no need to display progress.
|
||||
*/
|
||||
private void installActivityDisplay() {
|
||||
SystemUtilities.runIfSwingOrPostSwingLater(() -> {
|
||||
mainPanel.removeAll();
|
||||
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setSize(new Dimension(200, 100));
|
||||
String[] filenames = { "images/eatbits1.png", "images/eatbits2.png",
|
||||
"images/eatbits3.png", "images/eatbits4.png", "images/eatbits5.png",
|
||||
"images/eatbits6.png", "images/eatbits7.png" };
|
||||
panel.add(
|
||||
new GIconLabel(new AnimatedIcon(ResourceManager.loadImages(filenames), 200, 0)));
|
||||
mainPanel.add(panel, BorderLayout.CENTER);
|
||||
|
||||
mainPanel.add(chompingBitsPanel, BorderLayout.CENTER);
|
||||
repack();
|
||||
});
|
||||
}
|
||||
|
@ -200,7 +240,9 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
|||
monitorComponent.setShowProgressValue(showProgressValue);
|
||||
}
|
||||
|
||||
/** Sets the percentage done.
|
||||
/**
|
||||
* Sets the percentage done
|
||||
*
|
||||
* @param param The percentage of the task completed.
|
||||
*/
|
||||
@Override
|
||||
|
@ -250,62 +292,58 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
|||
monitorComponent.setIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
/** Called if the user presses the cancel button on
|
||||
* the dialog
|
||||
*/
|
||||
@Override
|
||||
protected void cancelCallback() {
|
||||
synchronized (this) {
|
||||
if (!monitorComponent.isCancelEnabled() || monitorComponent.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(shouldCancelRunnable);
|
||||
}
|
||||
|
||||
/** Sets the message in the TaskDialog dialog
|
||||
* @param str The message string to be displayed
|
||||
*/
|
||||
@Override
|
||||
synchronized public void setMessage(String str) {
|
||||
boolean invoke = (newMessage == null);
|
||||
newMessage = str;
|
||||
boolean invoke = (newPrimaryMessage == null);
|
||||
if (invoke) {
|
||||
SwingUtilities.invokeLater(updateMessage);
|
||||
newPrimaryMessage = str;
|
||||
SwingUtilities.invokeLater(updatePrimaryMessageRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the enable state of the Cancel button.
|
||||
* @param enable the state to set the cancel button.
|
||||
* Updates the secondary message on the task monitor
|
||||
*
|
||||
* @param str the string to update
|
||||
*/
|
||||
@Override
|
||||
public void setCancelEnabled(boolean enable) {
|
||||
if (canCancel) {
|
||||
monitorComponent.setCancelEnabled(enable);
|
||||
SwingUtilities.invokeLater(enableCancelButton);
|
||||
synchronized public void setSecondaryMessage(String str) {
|
||||
boolean invoke = (newSecondaryMessage == null);
|
||||
if (invoke) {
|
||||
newSecondaryMessage = str;
|
||||
SwingUtilities.invokeLater(updateSecondaryMessageRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelEnabled(boolean enable) {
|
||||
monitorComponent.setCancelEnabled(enable);
|
||||
super.setCancelEnabled(enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelEnabled() {
|
||||
return canCancel && cancelState;
|
||||
return super.isCancelEnabled();
|
||||
}
|
||||
|
||||
public synchronized void taskProcessed() {
|
||||
done = true;
|
||||
taskDone = true;
|
||||
monitorComponent.notifyChangeListeners();
|
||||
SwingUtilities.invokeLater(closeDialog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reset() {
|
||||
done = false;
|
||||
taskDone = false;
|
||||
taskID.incrementAndGet();
|
||||
}
|
||||
|
||||
public synchronized boolean isCompleted() {
|
||||
return done;
|
||||
return taskDone;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -393,7 +431,7 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
|||
|
||||
@Override
|
||||
public synchronized void cancel() {
|
||||
if (!canCancel || monitorComponent.isCancelled()) {
|
||||
if (monitorComponent.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
// Mark as cancelled, must be detected by task which should terminate
|
||||
|
@ -432,18 +470,11 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addIssueListener(IssueListener listener) {
|
||||
monitorComponent.addIssueListener(listener);
|
||||
public synchronized TaskMonitor getSecondaryMonitor() {
|
||||
if (secondaryTaskMonitor == null) {
|
||||
secondaryTaskMonitor = new SecondaryTaskMonitor(this);
|
||||
}
|
||||
return secondaryTaskMonitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeIssueListener(IssueListener listener) {
|
||||
monitorComponent.removeIssueListener(listener);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportIssue(Issue issue) {
|
||||
monitorComponent.reportIssue(issue);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,75 +24,79 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
import javax.swing.*;
|
||||
|
||||
import docking.ToolTipManager;
|
||||
import docking.util.AnimatedIcon;
|
||||
import docking.widgets.EmptyBorderButton;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.label.GDHtmlLabel;
|
||||
import docking.widgets.label.GIconLabel;
|
||||
import ghidra.util.Issue;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.datastruct.WeakDataStructureFactory;
|
||||
import ghidra.util.datastruct.WeakSet;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.layout.VerticalLayout;
|
||||
import resources.Icons;
|
||||
import resources.ResourceManager;
|
||||
|
||||
/**
|
||||
* Component that contains a progress bar, a progress icon, and a cancel
|
||||
* button to cancel the task that is associated with this task monitor.
|
||||
* <p>
|
||||
* By default the progress bar and progress icon (spinning globe) are visible.
|
||||
*/
|
||||
public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
||||
|
||||
private WeakSet<CancelledListener> listeners =
|
||||
WeakDataStructureFactory.createCopyOnReadWeakSet();
|
||||
private WeakSet<IssueListener> issueListeners;
|
||||
private JButton cancelButton;
|
||||
private JPanel eastButtonPanel;
|
||||
|
||||
private JProgressBar progressBar;
|
||||
private JButton cancelButton;
|
||||
|
||||
private JPanel cancelPanel;
|
||||
private JPanel progressBarPanel;
|
||||
private JPanel mainContentPanel;
|
||||
private JPanel progressPanel;
|
||||
private JPanel activeProgressPanel;
|
||||
private JLabel imageLabel;
|
||||
|
||||
private String progressMessage;
|
||||
private String taskName;
|
||||
|
||||
private JLabel messageLabel;
|
||||
|
||||
private volatile boolean isCancelled;
|
||||
private String message;
|
||||
|
||||
|
||||
private long lastProgress = -1;
|
||||
private long progress;
|
||||
private long lastMax = -1;
|
||||
private long max;
|
||||
private long lastMaxProgress = -1;
|
||||
private long maxProgress;
|
||||
private long scaleFactor = 1;
|
||||
|
||||
private Runnable updateProgressPanelRunnable;
|
||||
private Runnable updateCancelButtonRunnable;
|
||||
private Runnable updateToolTipRunnable;
|
||||
private JLabel messageLabel;
|
||||
private Runnable shouldCancelRunnable;
|
||||
|
||||
private boolean showingProgress = true;
|
||||
private boolean showingIcon = true;
|
||||
private boolean showingCancelButton = true;
|
||||
private boolean cancelEnabled = true;
|
||||
private boolean paintProgressValue = true;
|
||||
|
||||
private AtomicBoolean isIndeterminate = new AtomicBoolean(false);
|
||||
private AtomicInteger taskID = new AtomicInteger();
|
||||
|
||||
private Timer updateTimer;
|
||||
private Runnable shouldCancelRunnable;
|
||||
|
||||
private boolean paintProgressValue = true;
|
||||
|
||||
private NumberFormat percentFormat = NumberFormat.getPercentInstance();
|
||||
private long scaleFactor = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new TaskMonitorComponent.
|
||||
* @param l listener that is notified when the task completes or the
|
||||
* user cancels the task
|
||||
* Constructor
|
||||
*/
|
||||
|
||||
public TaskMonitorComponent() {
|
||||
this(true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param includeTextField if true, the dialog can display a status progressMessage with progress details
|
||||
* @param includeCancelButton if true, a cancel button will be displayed
|
||||
*/
|
||||
public TaskMonitorComponent(boolean includeTextField, boolean includeCancelButton) {
|
||||
updateProgressPanelRunnable = () -> updateProgressPanel();
|
||||
updateCancelButtonRunnable = () -> updateCancelButton();
|
||||
|
@ -113,13 +117,25 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
|||
|
||||
buildProgressPanel(includeTextField, includeCancelButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCancelledListener(CancelledListener mcl) {
|
||||
listeners.add(mcl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset this monitor so that it can be reused.
|
||||
*/
|
||||
public synchronized void reset() {
|
||||
isCancelled = false;
|
||||
taskID.incrementAndGet();
|
||||
@Override
|
||||
public void removeCancelledListener(CancelledListener mcl) {
|
||||
listeners.remove(mcl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementProgress(long incrementAmount) {
|
||||
setProgress(progress + incrementAmount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -136,7 +152,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
|||
|
||||
@Override
|
||||
public synchronized void setMessage(String message) {
|
||||
this.message = message;
|
||||
this.progressMessage = message;
|
||||
startUpdateTimer();
|
||||
}
|
||||
|
||||
|
@ -148,13 +164,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
|||
progress = value;
|
||||
startUpdateTimer();
|
||||
}
|
||||
|
||||
private synchronized void startUpdateTimer() {
|
||||
if (!updateTimer.isRunning()) {
|
||||
updateTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initialize(long maxValue) {
|
||||
setMaximum(maxValue);
|
||||
|
@ -163,13 +173,13 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
|||
|
||||
@Override
|
||||
public void setMaximum(long max) {
|
||||
this.max = max;
|
||||
if (progress > this.max) {
|
||||
this.maxProgress = max;
|
||||
if (progress > this.maxProgress) {
|
||||
progress = max;
|
||||
}
|
||||
startUpdateTimer();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the <code>indeterminate</code> property of the progress bar,
|
||||
* which determines whether the progress bar is in determinate
|
||||
|
@ -201,17 +211,6 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if {@link #setIndeterminate(boolean)} with a value of <tt>true</tt> has
|
||||
* been called.
|
||||
*
|
||||
* @return true if {@link #setIndeterminate(boolean)} with a value of <tt>true</tt> has
|
||||
* been called.
|
||||
*/
|
||||
public boolean isIndeterminate() {
|
||||
return isIndeterminate.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setCancelEnabled(boolean enable) {
|
||||
if (cancelEnabled != enable) {
|
||||
|
@ -243,67 +242,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
|||
isCancelled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the progress bar should be visible.
|
||||
* @param b true if the progress bar should be visible
|
||||
*/
|
||||
public synchronized void showProgress(boolean b) {
|
||||
if (b != showingProgress) {
|
||||
showingProgress = b;
|
||||
SystemUtilities.runSwingLater(updateProgressPanelRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the task; the name shows up in the tool tip for
|
||||
* the cancel button.
|
||||
* @param name the name of the task
|
||||
*/
|
||||
public void setTaskName(String name) {
|
||||
taskName = name;
|
||||
SystemUtilities.runSwingLater(updateToolTipRunnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or not show the cancel button according to the showCancel param.
|
||||
*/
|
||||
public void showCancelButton(boolean showCancel) {
|
||||
|
||||
if (showCancel == showingCancelButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (showCancel) {
|
||||
add(eastButtonPanel, BorderLayout.EAST);
|
||||
}
|
||||
else {
|
||||
remove(eastButtonPanel);
|
||||
}
|
||||
showingCancelButton = showCancel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or not show the progress icon (spinning globe) according to
|
||||
* the showIcon param.
|
||||
*/
|
||||
public void showProgressIcon(final boolean showIcon) {
|
||||
if (showIcon == showingIcon) {
|
||||
return;
|
||||
}
|
||||
Runnable r = () -> {
|
||||
if (showIcon) {
|
||||
activeProgressPanel.add(imageLabel, BorderLayout.EAST);
|
||||
}
|
||||
else {
|
||||
activeProgressPanel.remove(imageLabel);
|
||||
}
|
||||
showingIcon = showIcon;
|
||||
};
|
||||
|
||||
SystemUtilities.runSwingNow(r);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setShowProgressValue(boolean showProgressValue) {
|
||||
this.paintProgressValue = showProgressValue;
|
||||
|
@ -312,19 +251,121 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
|||
|
||||
@Override
|
||||
public long getMaximum() {
|
||||
return max;
|
||||
return maxProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset this monitor so that it can be reused
|
||||
*/
|
||||
@Override
|
||||
public synchronized void reset() {
|
||||
isCancelled = false;
|
||||
taskID.incrementAndGet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if {@link #setIndeterminate(boolean)} with a value of <tt>true</tt> has
|
||||
* been called.
|
||||
*
|
||||
* @return true if {@link #setIndeterminate(boolean)} with a value of <tt>true</tt> has
|
||||
* been called.
|
||||
*/
|
||||
public boolean isIndeterminate() {
|
||||
return isIndeterminate.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the progress bar should be visible
|
||||
*
|
||||
* @param show true if the progress bar should be visible
|
||||
*/
|
||||
public synchronized void showProgress(boolean show) {
|
||||
if (show != showingProgress) {
|
||||
showingProgress = show;
|
||||
SystemUtilities.runSwingLater(updateProgressPanelRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the task; the name shows up in the tool tip for
|
||||
* the cancel button.
|
||||
*
|
||||
* @param name the name of the task
|
||||
*/
|
||||
public void setTaskName(String name) {
|
||||
taskName = name;
|
||||
SystemUtilities.runSwingLater(updateToolTipRunnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the visibility of the cancel button
|
||||
*
|
||||
* @param visible if true, show the cancel button; false otherwise
|
||||
*/
|
||||
public void setCancelButtonVisibility(boolean visible) {
|
||||
|
||||
if (visible == showingCancelButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
add(cancelPanel, BorderLayout.EAST);
|
||||
}
|
||||
else {
|
||||
remove(cancelPanel);
|
||||
}
|
||||
|
||||
repaint();
|
||||
showingCancelButton = visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visibility of the progress icon
|
||||
*
|
||||
* @param visible if true, display the progress icon
|
||||
*/
|
||||
public void showProgressIcon(boolean visible) {
|
||||
if (visible == showingIcon) {
|
||||
return;
|
||||
}
|
||||
Runnable r = () -> {
|
||||
if (visible) {
|
||||
mainContentPanel.add(progressPanel, BorderLayout.EAST);
|
||||
}
|
||||
else {
|
||||
mainContentPanel.remove(progressPanel);
|
||||
}
|
||||
showingIcon = visible;
|
||||
};
|
||||
|
||||
SystemUtilities.runSwingNow(r);
|
||||
}
|
||||
|
||||
protected void notifyChangeListeners() {
|
||||
Runnable r = () -> {
|
||||
for (CancelledListener mcl : listeners) {
|
||||
mcl.cancelled();
|
||||
}
|
||||
};
|
||||
SwingUtilities.invokeLater(r);
|
||||
}
|
||||
|
||||
private synchronized void startUpdateTimer() {
|
||||
if (!updateTimer.isRunning()) {
|
||||
updateTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void update() {
|
||||
|
||||
if (message != null) {
|
||||
messageLabel.setText(message);
|
||||
message = null;
|
||||
if (progressMessage != null) {
|
||||
messageLabel.setText(progressMessage);
|
||||
progressMessage = null;
|
||||
}
|
||||
|
||||
if (max != lastMax) {
|
||||
setMaxValueInProgressBar(max);
|
||||
lastMax = max;
|
||||
if (maxProgress != lastMaxProgress) {
|
||||
setMaxValueInProgressBar(maxProgress);
|
||||
lastMaxProgress = maxProgress;
|
||||
}
|
||||
|
||||
if (progress != lastProgress) {
|
||||
|
@ -379,10 +420,10 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
|||
|
||||
private synchronized void updateProgressPanel() {
|
||||
if (showingProgress) {
|
||||
progressPanel.add(progressBar, BorderLayout.NORTH);
|
||||
progressBarPanel.add(progressBar, BorderLayout.NORTH);
|
||||
}
|
||||
else {
|
||||
progressPanel.remove(progressBar);
|
||||
progressBarPanel.remove(progressBar);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -424,24 +465,24 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
|||
progressBar.setStringPainted(true);
|
||||
ToolTipManager.sharedInstance().registerComponent(progressBar);
|
||||
|
||||
createAnimatedIcon();
|
||||
progressPanel = new HourglassAnimationPanel();
|
||||
|
||||
progressPanel = new JPanel(new VerticalLayout(0));
|
||||
progressPanel.add(progressBar);
|
||||
progressBarPanel = new JPanel(new VerticalLayout(0));
|
||||
progressBarPanel.add(progressBar);
|
||||
if (includeTextField) {
|
||||
progressPanel.add(messageLabel);
|
||||
progressBarPanel.add(messageLabel);
|
||||
progressBar.setPreferredSize(new Dimension(180, 12));
|
||||
}
|
||||
else {
|
||||
progressBar.setBorderPainted(true);
|
||||
Dimension size = progressBar.getPreferredSize();
|
||||
progressPanel.setBorder(BorderFactory.createEmptyBorder(
|
||||
(imageLabel.getPreferredSize().height - size.height) / 2, 0, 0, 8));
|
||||
progressBarPanel.setBorder(BorderFactory.createEmptyBorder(
|
||||
(progressPanel.getPreferredSize().height - size.height) / 2, 0, 0, 8));
|
||||
}
|
||||
|
||||
activeProgressPanel = new JPanel(new BorderLayout());
|
||||
activeProgressPanel.add(progressPanel, BorderLayout.CENTER);
|
||||
activeProgressPanel.add(imageLabel, BorderLayout.EAST);
|
||||
mainContentPanel = new JPanel(new BorderLayout());
|
||||
mainContentPanel.add(progressBarPanel, BorderLayout.CENTER);
|
||||
mainContentPanel.add(progressPanel, BorderLayout.EAST);
|
||||
|
||||
ImageIcon icon = Icons.STOP_ICON;
|
||||
cancelButton = new EmptyBorderButton(icon);
|
||||
|
@ -452,86 +493,15 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
|||
cancelButton.setFocusable(false);
|
||||
cancelButton.setRolloverEnabled(true);
|
||||
|
||||
add(activeProgressPanel, BorderLayout.CENTER);
|
||||
add(mainContentPanel, BorderLayout.CENTER);
|
||||
|
||||
if (includeCancelButton) {
|
||||
eastButtonPanel = new JPanel();
|
||||
eastButtonPanel.setLayout(new BoxLayout(eastButtonPanel, BoxLayout.Y_AXIS));
|
||||
eastButtonPanel.add(Box.createVerticalGlue());
|
||||
eastButtonPanel.add(cancelButton);
|
||||
eastButtonPanel.add(Box.createVerticalGlue());
|
||||
add(eastButtonPanel, BorderLayout.EAST);
|
||||
}
|
||||
}
|
||||
|
||||
private void createAnimatedIcon() {
|
||||
String[] filenames = { "images/hourglass24_01.png", "images/hourglass24_02.png",
|
||||
"images/hourglass24_02.png", "images/hourglass24_03.png", "images/hourglass24_03.png",
|
||||
"images/hourglass24_04.png", "images/hourglass24_04.png", "images/hourglass24_05.png",
|
||||
"images/hourglass24_05.png", "images/hourglass24_06.png", "images/hourglass24_06.png",
|
||||
"images/hourglass24_07.png", "images/hourglass24_07.png", "images/hourglass24_08.png",
|
||||
"images/hourglass24_08.png", "images/hourglass24_09.png", "images/hourglass24_10.png",
|
||||
"images/hourglass24_11.png" };
|
||||
imageLabel =
|
||||
new GIconLabel(new AnimatedIcon(ResourceManager.loadImages(filenames), 150, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementProgress(long incrementAmount) {
|
||||
setProgress(progress + incrementAmount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
protected void notifyChangeListeners() {
|
||||
Runnable r = () -> {
|
||||
synchronized (listeners) {
|
||||
for (CancelledListener mcl : listeners) {
|
||||
mcl.cancelled();
|
||||
}
|
||||
}
|
||||
};
|
||||
SwingUtilities.invokeLater(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCancelledListener(CancelledListener mcl) {
|
||||
synchronized (listeners) {
|
||||
listeners.add(mcl);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCancelledListener(CancelledListener mcl) {
|
||||
synchronized (listeners) {
|
||||
listeners.remove(mcl);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIssueListener(IssueListener listener) {
|
||||
if (issueListeners == null) {
|
||||
issueListeners = WeakDataStructureFactory.createCopyOnWriteWeakSet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeIssueListener(IssueListener listener) {
|
||||
if (issueListeners != null) {
|
||||
issueListeners.remove(listener);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportIssue(Issue issue) {
|
||||
if (issueListeners != null) {
|
||||
for (IssueListener listener : issueListeners) {
|
||||
listener.issueReported(issue);
|
||||
}
|
||||
cancelPanel = new JPanel();
|
||||
cancelPanel.setLayout(new BoxLayout(cancelPanel, BoxLayout.Y_AXIS));
|
||||
cancelPanel.add(Box.createVerticalGlue());
|
||||
cancelPanel.add(cancelButton);
|
||||
cancelPanel.add(Box.createVerticalGlue());
|
||||
add(cancelPanel, BorderLayout.EAST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue