/******************************************************************************* * Copyright 2012 Geoscience Australia * * 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 au.gov.ga.earthsci.application.parts.retrieve; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.annotation.PreDestroy; import javax.inject.Inject; import org.eclipse.e4.ui.model.application.ui.basic.MPart; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.OwnerDrawLabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.TableItem; import au.gov.ga.earthsci.common.ui.util.SWTUtil; import au.gov.ga.earthsci.core.retrieve.IRetrieval; import au.gov.ga.earthsci.core.retrieve.IRetrievalListener; import au.gov.ga.earthsci.core.retrieve.IRetrievalService; import au.gov.ga.earthsci.core.retrieve.IRetrievalServiceListener; import au.gov.ga.earthsci.core.retrieve.RetrievalAdapter; /** * Part that displays progress of {@link IRetrieval}s running in the * {@link IRetrievalService}. * * @author Michael de Hoog (michael.dehoog@ga.gov.au) */ public class RetrievePart implements IRetrievalServiceListener { @Inject private IRetrievalService retrievalService; private TableViewer viewer; private final List<IRetrieval> retrievals = new ArrayList<IRetrieval>(); private final Set<Object> updatingElements = new HashSet<Object>(); private Color downloadBackgroundColor; @Inject public void init(Composite parent, MPart part) { Color listBackground = parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND); downloadBackgroundColor = SWTUtil.shouldDarken(listBackground) ? SWTUtil.darker(listBackground) : SWTUtil.lighter(listBackground); retrievalService.addListener(this); viewer = new TableViewer(parent, SWT.V_SCROLL); viewer.setContentProvider(ArrayContentProvider.getInstance()); viewer.setInput(retrievals); viewer.getTable().setLinesVisible(true); viewer.getTable().setHeaderVisible(true); /*viewer.setSorter(new ViewerSorter() { @Override public int category(Object element) { return ((JobInfo) element).job.getState(); } @Override public int compare(Viewer viewer, Object e1, Object e2) { return ((JobInfo) e1).job.getPriority() - ((JobInfo) e2).job.getPriority(); } }); viewer.addFilter(new ViewerFilter() { @Override public boolean select(Viewer viewer, Object parentElement, Object element) { return ((JobInfo) element).job.getState() != Job.SLEEPING; } });*/ createColumns(); } @PreDestroy public void packup() { retrievalService.removeListener(this); downloadBackgroundColor.dispose(); } private void createColumns() { TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE); column.getColumn().setText("URL"); column.getColumn().setWidth(300); column.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object element) { IRetrieval retrieval = (IRetrieval) element; return retrieval.getURL().toString(); } }); column = new TableViewerColumn(viewer, SWT.NONE); column.getColumn().setText("Caller(s)"); column.getColumn().setWidth(200); column.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object element) { IRetrieval retrieval = (IRetrieval) element; StringBuilder sb = new StringBuilder(); for (Object caller : retrieval.getCallers()) { sb.append(", " + caller.toString()); //$NON-NLS-1$ } if (sb.length() == 0) { return sb.toString(); } return sb.substring(2); } }); column = new TableViewerColumn(viewer, SWT.NONE); column.getColumn().setText("Progress"); column.getColumn().setWidth(150); column.setLabelProvider(new OwnerDrawLabelProvider() { @Override protected void paint(Event event, Object element) { GC gc = event.gc; Color foreground = gc.getForeground(); Color background = gc.getBackground(); IRetrieval retrieval = (IRetrieval) element; float percentage = Math.max(0, retrieval.getPercentage()); String text = positionString(retrieval); Rectangle bounds = ((TableItem) event.item).getBounds(event.index); int width = (int) ((bounds.width - 1) * percentage); gc.setBackground(downloadBackgroundColor); gc.fillRectangle(event.x, event.y, width, event.height); Point size = event.gc.textExtent(text); int offset = Math.max(0, (event.height - size.y) / 2); gc.setForeground(event.display.getSystemColor(SWT.COLOR_LIST_FOREGROUND)); gc.drawText(text, event.x + 2, event.y + offset, true); gc.setForeground(background); gc.setBackground(foreground); } @Override protected void measure(Event event, Object element) { } }); } private static String positionString(IRetrieval retrieval) { long position = retrieval.getPosition(); long length = retrieval.getLength(); float percentage = retrieval.getPercentage(); StringBuilder sb = new StringBuilder(); String unknown = "unknown"; long max = Math.max(position, length); if (max >= 0) { int unitNumber = max == 0 ? 0 : (int) (Math.log10(max) / Math.log10(1024)); String prefixes = "kMGTPEZY"; //$NON-NLS-1$ if (unitNumber > prefixes.length()) { unitNumber = 0; } String unit = (unitNumber <= 0 ? "" : prefixes.charAt(unitNumber - 1)) + "B"; //$NON-NLS-1$ //$NON-NLS-2$ long divisor = (long) Math.pow(1024, unitNumber); position /= divisor; length /= divisor; sb.append(position); sb.append(' '); sb.append(unit); sb.append(' '); sb.append("of"); sb.append(' '); if (length <= 0) { sb.append(unknown); } else { sb.append(length); sb.append(' '); sb.append(unit); } } else { sb.append(unknown); } if (percentage >= 0) { sb.append(" ("); //$NON-NLS-1$ sb.append((int) (percentage * 100)); sb.append("%)"); //$NON-NLS-1$ } return sb.toString(); } @Override public void retrievalAdded(final IRetrieval retrieval) { synchronized (retrievals) { retrievals.add(retrieval); } retrieval.addListener(retrievalListener); if (viewer != null && !viewer.getControl().isDisposed()) { viewer.getControl().getDisplay().asyncExec(new Runnable() { @Override public void run() { if (!viewer.getControl().isDisposed()) { viewer.add(retrieval); } } }); } } @Override public void retrievalRemoved(final IRetrieval retrieval) { synchronized (retrievals) { retrievals.remove(retrieval); } retrieval.removeListener(retrievalListener); if (viewer != null && !viewer.getControl().isDisposed()) { viewer.getControl().getDisplay().asyncExec(new Runnable() { @Override public void run() { if (!viewer.getControl().isDisposed()) { viewer.remove(retrieval); } } }); } } private void asyncUpdate(final Object element) { //don't queue multiple updates for each retrieval, so we don't flood the UI thread with asyncExec's if (updatingElements.contains(element)) { return; } if (viewer != null && !viewer.getControl().isDisposed()) { updatingElements.add(element); viewer.getControl().getDisplay().asyncExec(new Runnable() { @Override public void run() { if (!viewer.getControl().isDisposed()) { viewer.update(element, null); } updatingElements.remove(element); } }); } } private IRetrievalListener retrievalListener = new RetrievalAdapter() { @Override public void progress(IRetrieval retrieval) { asyncUpdate(retrieval); } @Override public void callersChanged(IRetrieval retrieval) { asyncUpdate(retrieval); } }; }