blob: b084c828a04857fbb8678e241aff0cb6d8419068 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.e4.ui.progress.internal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.e4.ui.progress.IProgressService;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Widget;
/**
* The DetailedProgressViewer is a viewer that shows the details of all in
* progress job or jobs that are finished awaiting user input.
*
* @since 3.2
*
*/
public class DetailedProgressViewer extends AbstractProgressViewer {
//Maximum number of entries to display so that the view does not flood the UI with events
private static final int MAX_DISPLAYED = 20;
Composite control;
private ScrolledComposite scrolled;
private Composite noEntryArea;
private IProgressService progressService;
private FinishedJobs finishedJobs;
/**
* Create a new instance of the receiver with a control that is a child of
* parent with style style.
*
* @param parent
* @param style
*/
public DetailedProgressViewer(Composite parent, int style,
IProgressService progressService, FinishedJobs finishedJobs) {
this.progressService = progressService;
this.finishedJobs = finishedJobs;
scrolled = new ScrolledComposite(parent, SWT.V_SCROLL | style);
int height = JFaceResources.getDefaultFont().getFontData()[0]
.getHeight();
scrolled.getVerticalBar().setIncrement(height * 2);
scrolled.setExpandHorizontal(true);
scrolled.setExpandVertical(true);
control = new Composite(scrolled, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
control.setLayout(layout);
control.setBackground(parent.getDisplay().getSystemColor(
SWT.COLOR_LIST_BACKGROUND));
control.addFocusListener(new FocusAdapter() {
private boolean settingFocus = false;
@Override
public void focusGained(FocusEvent e) {
if (!settingFocus) {
// Prevent new focus events as a result this update
// occurring
settingFocus = true;
setFocus();
settingFocus = false;
}
}
});
control.addControlListener(new ControlListener() {
@Override
public void controlMoved(ControlEvent e) {
updateVisibleItems();
}
@Override
public void controlResized(ControlEvent e) {
updateVisibleItems();
}
});
// TODO E4 - missing e4 replacement
// PlatformUI.getWorkbench().getHelpSystem().setHelp(control,
// IWorkbenchHelpContextIds.RESPONSIVE_UI);
scrolled.setContent(control);
hookControl(control);
noEntryArea = new Composite(scrolled, SWT.NONE);
noEntryArea.setLayout(new GridLayout());
noEntryArea.setBackground(noEntryArea.getDisplay()
.getSystemColor(SWT.COLOR_LIST_BACKGROUND));
Label noEntryLabel = new Label(noEntryArea, SWT.NONE);
noEntryLabel.setText(ProgressMessages.ProgressView_NoOperations);
noEntryLabel.setBackground(noEntryArea.getDisplay().getSystemColor(
SWT.COLOR_LIST_BACKGROUND));
GridData textData = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
noEntryLabel.setLayoutData(textData);
// TODO E4 - missing e4 replacement
// PlatformUI.getWorkbench().getHelpSystem().setHelp(noEntryLabel,
// IWorkbenchHelpContextIds.RESPONSIVE_UI);
}
@Override
public void add(Object[] elements) {
ViewerComparator sorter = getComparator();
// Use a Set in case we are getting something added that exists
Set<Object> newItems = new HashSet<>(elements.length);
Control[] existingChildren = control.getChildren();
for (Control element : existingChildren) {
if (element.getData() != null)
newItems.add(element.getData());
}
for (Object element : elements) {
if (element != null)
newItems.add(element);
}
JobTreeElement[] infos = new JobTreeElement[newItems.size()];
newItems.toArray(infos);
if (sorter != null) {
sorter.sort(this, infos);
}
// Update with the new elements to prevent flash
for (Control element : existingChildren) {
((ProgressInfoItem) element).dispose();
}
int totalSize = Math.min(newItems.size(), MAX_DISPLAYED);
for (int i = 0; i < totalSize; i++) {
ProgressInfoItem item = createNewItem(infos[i]);
item.setColor(i);
}
control.layout(true);
updateForShowingProgress();
}
/**
* Update for the progress being displayed.
*/
private void updateForShowingProgress() {
if (control.getChildren().length > 0) {
scrolled.setContent(control);
} else {
scrolled.setContent(noEntryArea);
}
}
/**
* Create a new item for info.
*
* @param info
* @return ProgressInfoItem
*/
private ProgressInfoItem createNewItem(JobTreeElement info) {
final ProgressInfoItem item = new ProgressInfoItem(control, SWT.NONE,
info, progressService, finishedJobs);
item.addControlListener(new ControlListener() {
@Override
public void controlMoved(ControlEvent e) {
updateVisibleProgressItems(item);
}
@Override
public void controlResized(ControlEvent e) {
updateVisibleProgressItems(item);
}
});
item.setIndexListener(new ProgressInfoItem.IndexListener() {
@Override
public void selectNext() {
DetailedProgressViewer.this.selectNext(item);
}
@Override
public void selectPrevious() {
DetailedProgressViewer.this.selectPrevious(item);
}
@Override
public void select() {
Control[] children = control.getChildren();
for (Control element : children) {
ProgressInfoItem child = (ProgressInfoItem) element;
if (!item.equals(child)) {
child.selectWidgets(false);
}
}
item.selectWidgets(true);
}
});
// Refresh to populate with the current tasks
item.refresh();
return item;
}
/**
* Select the previous item in the receiver.
*
* @param item
*/
protected void selectPrevious(ProgressInfoItem item) {
Control[] children = control.getChildren();
for (int i = 0; i < children.length; i++) {
ProgressInfoItem child = (ProgressInfoItem) children[i];
if (item.equals(child)) {
ProgressInfoItem previous;
if (i == 0) {
previous = (ProgressInfoItem) children[children.length - 1];
} else {
previous = (ProgressInfoItem) children[i - 1];
}
item.selectWidgets(false);
previous.selectWidgets(true);
return;
}
}
}
/**
* Select the next item in the receiver.
*
* @param item
*/
protected void selectNext(ProgressInfoItem item) {
Control[] children = control.getChildren();
for (int i = 0; i < children.length; i++) {
ProgressInfoItem child = (ProgressInfoItem) children[i];
if (item.equals(child)) {
ProgressInfoItem next;
if (i == children.length - 1) {
next = (ProgressInfoItem) children[0];
} else {
next = (ProgressInfoItem) children[i + 1];
}
item.selectWidgets(false);
next.selectWidgets(true);
return;
}
}
}
@Override
protected Widget doFindInputItem(Object element) {
return null;
}
@Override
protected Widget doFindItem(Object element) {
Control[] existingChildren = control.getChildren();
for (Control controlElement : existingChildren) {
if (controlElement.isDisposed()
|| controlElement.getData() == null) {
continue;
}
if (controlElement.getData().equals(element)) {
return controlElement;
}
}
return null;
}
@Override
protected void doUpdateItem(Widget item, Object element, boolean fullMap) {
if (usingElementMap()) {
unmapElement(item);
}
item.dispose();
add(new Object[] { element });
}
@Override
public Control getControl() {
return scrolled;
}
@Override
protected List<Object> getSelectionFromWidget() {
return new ArrayList<>(0);
}
@Override
protected void inputChanged(Object input, Object oldInput) {
super.inputChanged(input, oldInput);
refreshAll();
updateForShowingProgress();
}
@Override
protected void internalRefresh(Object element) {
if (element == null) {
return;
}
if (element.equals(getRoot())) {
refreshAll();
return;
}
Widget widget = findItem(element);
if (widget == null) {
add(new Object[] { element });
return;
}
((ProgressInfoItem) widget).refresh();
// Update the minimum size
Point size = control.computeSize(SWT.DEFAULT, SWT.DEFAULT);
// no horizontal size because we do not want to scroll horizontal
size.x = 0;
size.y += IDialogConstants.VERTICAL_SPACING;
scrolled.setMinSize(size);
}
@Override
public void remove(Object[] elements) {
for (Object element : elements) {
JobTreeElement treeElement = (JobTreeElement) element;
// Make sure we are not keeping this one
if (finishedJobs.isKept(treeElement)) {
Widget item = doFindItem(element);
if (item != null) {
((ProgressInfoItem) item).refresh();
}
} else {
Widget item = doFindItem(treeElement);
if (item == null) {
// Is the parent showing?
Object parent = treeElement.getParent();
if (parent != null)
item = doFindItem(parent);
}
if (item != null) {
unmapElement(element);
item.dispose();
}
}
}
Control[] existingChildren = control.getChildren();
for (int i = 0; i < existingChildren.length; i++) {
ProgressInfoItem item = (ProgressInfoItem) existingChildren[i];
item.setColor(i);
}
control.layout(true);
updateForShowingProgress();
}
@Override
public void reveal(Object element) {
}
@Override
protected void setSelectionToWidget(@SuppressWarnings("rawtypes") List l, boolean reveal) {
}
/**
* Cancel the current selection
*
*/
public void cancelSelection() {
}
/**
* Set focus on the current selection.
*
*/
public void setFocus() {
Control[] children = control.getChildren();
if (children.length > 0) {
((ProgressInfoItem)children[0]).setButtonFocus();
} else {
noEntryArea.setFocus();
}
}
/**
* Refresh everything as the root is being refreshed.
*/
private void refreshAll() {
Object[] infos = getSortedChildren(getRoot());
Control[] existingChildren = control.getChildren();
for (Control element : existingChildren) {
element.dispose();
}
int maxLength = Math.min(infos.length,MAX_DISPLAYED);
// Create new ones if required
for (int i = 0; i < maxLength; i++) {
ProgressInfoItem item = createNewItem((JobTreeElement) infos[i]);
item.setColor(i);
}
control.layout(true);
updateForShowingProgress();
}
/**
* Set the virtual items to be visible or not depending on the displayed
* area.
*/
private void updateVisibleItems() {
updateVisibleProgressItems(control.getChildren());
}
private void updateVisibleProgressItems(Control... progressInfoItems) {
int top = scrolled.getOrigin().y;
int bottom = top + scrolled.getParent().getBounds().height;
for (Control element : progressInfoItems) {
ProgressInfoItem item = (ProgressInfoItem) element;
item.setDisplayed(top, bottom);
}
}
public ProgressInfoItem[] getProgressInfoItems() {
Control[] children = control.getChildren();
ProgressInfoItem[] progressInfoItems = new ProgressInfoItem[children.length];
System.arraycopy(children, 0, progressInfoItems, 0, children.length);
return progressInfoItems;
}
}