blob: 0a47f577dc3e77e84abe96cd102626dfec61587a [file] [log] [blame]
/*
* Copyright (c) 2015 Eike Stepper (Berlin, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.oomph.jreinfo.ui;
import org.eclipse.oomph.internal.jreinfo.JREInfoPlugin;
import org.eclipse.oomph.jreinfo.JRE;
import org.eclipse.oomph.jreinfo.JREFilter;
import org.eclipse.oomph.jreinfo.JREManager;
import org.eclipse.oomph.ui.ErrorDialog;
import org.eclipse.oomph.ui.UIUtil;
import org.eclipse.oomph.util.IOUtil;
import org.eclipse.oomph.util.OS;
import org.eclipse.oomph.util.PropertiesUtil;
import org.eclipse.oomph.util.Request;
import org.eclipse.emf.edit.provider.IItemFontProvider;
import org.eclipse.emf.edit.ui.provider.ExtendedFontRegistry;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableFontProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author Eike Stepper
*/
public class JREComposite extends Composite
{
private static final Image IMAGE_GROUP = JREInfoUIPlugin.INSTANCE.getSWTImage("group");
private static final Image IMAGE_JRE = JREInfoUIPlugin.INSTANCE.getSWTImage("jre");
private static final Image IMAGE_JDK = JREInfoUIPlugin.INSTANCE.getSWTImage("jdk");
private static final int EXTRA_WIDTH = OS.INSTANCE.isLinux() ? 10 : 0;
private static final String[] GROUPS = { "System", "User" };
private static final Object[] EMPTY = new Object[0];
private final JREContentProvider contentProvider = new JREContentProvider();
private final Request.Handler downloadHandler;
private Object selectedElement;
private JREFilter filter;
private JRE[] extras = {};
private TreeViewer treeViewer;
private Button browseButton;
private Button downloadButton;
private Button removeButton;
private Button refreshButton;
public JREComposite(Composite parent, int style, Request.Handler downloadHandler, JREFilter filter, final Object selection)
{
super(parent, style);
this.downloadHandler = downloadHandler;
this.filter = filter;
selectedElement = selection;
UIUtil.setTransparentBackgroundColor(this);
setLayout(UIUtil.createGridLayout(2));
TreeColumnLayout treeLayout = new TreeColumnLayout();
Composite composite = new Composite(this, SWT.NONE);
composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
composite.setLayout(treeLayout);
treeViewer = new TreeViewer(composite, SWT.BORDER | SWT.MULTI);
treeViewer.setContentProvider(contentProvider);
treeViewer.setLabelProvider(new JRELabelProvider(treeViewer.getTree().getFont()));
treeViewer.addSelectionChangedListener(new ISelectionChangedListener()
{
public void selectionChanged(SelectionChangedEvent event)
{
IStructuredSelection selection = (IStructuredSelection)treeViewer.getSelection();
boolean removable = true;
int size = selection.size();
if (size == 0)
{
selectedElement = null;
removable = false;
}
else if (size == 1)
{
selectedElement = selection.getFirstElement();
removable = isExtraJRE(selectedElement);
}
else
{
selectedElement = null;
for (Object element : selection.toArray())
{
if (!isExtraJRE(element))
{
removable = false;
break;
}
}
}
removeButton.setEnabled(removable);
elementChanged(selectedElement);
}
});
treeViewer.addDoubleClickListener(new IDoubleClickListener()
{
public void doubleClick(DoubleClickEvent event)
{
if (selectedElement instanceof JRE)
{
doubleClicked((JRE)selectedElement);
}
}
});
Tree tree = treeViewer.getTree();
tree.setHeaderVisible(true);
tree.addKeyListener(new KeyAdapter()
{
@Override
public void keyPressed(KeyEvent e)
{
if (e.keyCode == SWT.DEL)
{
removePressed();
}
}
});
TreeColumn locationColumn = new TreeColumn(tree, SWT.LEFT);
locationColumn.setText("Location");
treeLayout.setColumnData(locationColumn, new ColumnWeightData(100));
TreeColumn versionColumn = new TreeColumn(tree, SWT.LEFT);
versionColumn.setText("Version");
treeLayout.setColumnData(versionColumn, new ColumnWeightData(1, 60 + EXTRA_WIDTH));
TreeColumn bitnessColumn = new TreeColumn(tree, SWT.LEFT);
bitnessColumn.setText("Bitness");
treeLayout.setColumnData(bitnessColumn, new ColumnWeightData(1, 60 + EXTRA_WIDTH));
TreeColumn typeColumn = new TreeColumn(tree, SWT.LEFT);
typeColumn.setText("Type");
treeLayout.setColumnData(typeColumn, new ColumnWeightData(1, 50 + EXTRA_WIDTH));
Composite buttonComposite = new Composite(this, SWT.NONE);
buttonComposite.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
buttonComposite.setLayout(UIUtil.createGridLayout(1));
browseButton = new Button(buttonComposite, SWT.NONE);
browseButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
browseButton.setText("&Browse...");
browseButton.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
browsePressed();
}
});
if (downloadHandler != null)
{
downloadButton = new Button(buttonComposite, SWT.NONE);
downloadButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
downloadButton.setText("&Download...");
downloadButton.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
downloadPressed();
}
});
}
removeButton = new Button(buttonComposite, SWT.NONE);
removeButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
removeButton.setText("&Remove");
removeButton.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
removePressed();
}
});
refreshButton = new Button(buttonComposite, SWT.NONE);
refreshButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
refreshButton.setText("Re&fresh");
refreshButton.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
refreshPressed();
}
});
UIUtil.asyncExec(new Runnable()
{
public void run()
{
BusyIndicator.showWhile(getShell().getDisplay(), new Runnable()
{
public void run()
{
treeViewer.setInput(JREManager.INSTANCE);
treeViewer.expandAll();
}
});
if (selectedElement == null)
{
removeButton.setEnabled(false);
}
else
{
treeViewer.setSelection(new StructuredSelection(selectedElement));
}
}
});
}
public JREFilter getJREFilter()
{
return filter;
}
public void setJREFilter(JREFilter filter)
{
this.filter = filter;
UIUtil.asyncExec(new Runnable()
{
public void run()
{
treeViewer.refresh();
}
});
}
public Object getSelectedElement()
{
return selectedElement;
}
public void setSelectedElement(final Object selectedElement)
{
this.selectedElement = selectedElement;
UIUtil.asyncExec(new Runnable()
{
public void run()
{
treeViewer.setSelection(new StructuredSelection(selectedElement));
elementChanged(selectedElement);
}
});
}
protected void elementChanged(Object element)
{
}
protected void browsePressed()
{
File rootFolder = null;
File file = new File(JREInfoPlugin.INSTANCE.getUserLocation().append("search.txt").toOSString());
List<String> lines = IOUtil.readLines(file, "UTF-8");
if (!lines.isEmpty())
{
rootFolder = new File(lines.get(0));
}
while (rootFolder != null && !rootFolder.isDirectory())
{
rootFolder = rootFolder.getParentFile();
}
String filterPath = rootFolder == null ? PropertiesUtil.getUserHome() : rootFolder.getAbsolutePath();
DirectoryDialog dialog = new DirectoryDialog(getShell());
dialog.setText(JREDialog.TITLE);
dialog.setMessage("Pick a root folder that will be recursively searched for Java virtual machines...");
dialog.setFilterPath(filterPath);
final String dir = dialog.open();
if (dir != null)
{
if (!dir.equals(filterPath))
{
IOUtil.writeLines(file, "UTF-8", Collections.singletonList(dir));
}
try
{
final AtomicReference<Set<JRE>> added = new AtomicReference<Set<JRE>>();
UIUtil.runInProgressDialog(getShell(), new IRunnableWithProgress()
{
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException
{
added.set(JREManager.INSTANCE.addExtraJavaHomes(dir, monitor));
}
});
Set<JRE> jres = added.get();
int size = jres == null ? 0 : jres.size();
if (size != 0)
{
treeViewer.refresh();
treeViewer.setExpandedState(GROUPS[1], true);
treeViewer.setSelection(new StructuredSelection(new ArrayList<JRE>(jres)));
}
MessageDialog.openInformation(getShell(), JREDialog.TITLE,
(size == 0 ? "No" : Integer.toString(size)) + " new VM" + (size == 1 ? "" : "s") + " found.");
}
catch (InvocationTargetException ex)
{
Throwable cause = ex.getCause();
if (cause == null)
{
cause = ex;
}
JREInfoPlugin.INSTANCE.log(cause);
ErrorDialog.open(cause);
}
catch (InterruptedException ex)
{
//$FALL-THROUGH$
}
}
}
protected void downloadPressed()
{
Request request = new Request("http://download.eclipse.org/oomph/jre/");
JREFilter filter = getJREFilter();
if (filter != null)
{
request.put("vm", filter.getQuery());
}
downloadHandler.handleRequest(request);
}
protected void removePressed()
{
Set<String> javaHomes = new HashSet<String>();
IStructuredSelection selection = (IStructuredSelection)treeViewer.getSelection();
for (Object element : selection.toArray())
{
if (isExtraJRE(element))
{
javaHomes.add(((JRE)element).getJavaHome().getAbsolutePath());
}
}
int size = javaHomes.size();
if (size != 0)
{
JREManager.INSTANCE.removeExtraJavaHomes(javaHomes.toArray(new String[size]));
treeViewer.refresh();
treeViewer.setSelection(StructuredSelection.EMPTY);
}
}
protected void refreshPressed()
{
JREManager.INSTANCE.refresh(true);
treeViewer.refresh();
}
protected void doubleClicked(JRE jre)
{
// Do nothing.
}
private boolean isExtraJRE(Object jre)
{
for (int i = 0; i < extras.length; i++)
{
if (extras[i] == jre)
{
return true;
}
}
return false;
}
/**
* @author Eike Stepper
*/
private final class JREContentProvider implements ITreeContentProvider
{
public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
{
}
public Object[] getChildren(Object element)
{
if (element == JREManager.INSTANCE)
{
return GROUPS;
}
if (element == GROUPS[0])
{
return JREManager.INSTANCE.getJREs(null, false);
}
if (element == GROUPS[1])
{
extras = JREManager.INSTANCE.getJREs(null, true);
return extras;
}
return EMPTY;
}
public boolean hasChildren(Object element)
{
return getChildren(element).length != 0;
}
public Object[] getElements(Object element)
{
return getChildren(element);
}
public Object getParent(Object element)
{
return null;
}
public void dispose()
{
}
}
/**
* @author Eike Stepper
*/
private final class JRELabelProvider extends LabelProvider implements ITableLabelProvider, IColorProvider, ITableFontProvider
{
private Font font;
public JRELabelProvider(Font font)
{
this.font = font;
}
public Image getColumnImage(Object element, int columnIndex)
{
if (columnIndex == 0)
{
if (element instanceof String)
{
return IMAGE_GROUP;
}
if (element instanceof JRE)
{
return ((JRE)element).isJDK() ? IMAGE_JDK : IMAGE_JRE;
}
}
return null;
}
public String getColumnText(Object element, int columnIndex)
{
if (element instanceof String)
{
if (columnIndex == 0)
{
return (String)element;
}
return null;
}
if (element instanceof JRE)
{
JRE jre = (JRE)element;
switch (columnIndex)
{
case 0:
return jre.toString();
case 1:
return jre.getMajor() + "." + jre.getMinor() + "." + jre.getMicro();
case 2:
return jre.getBitness() + " Bit";
case 3:
return jre.isJDK() ? "JDK" : "JRE";
}
}
return null;
}
public Color getForeground(Object element)
{
if (filter != null && element instanceof JRE)
{
JRE jre = (JRE)element;
if (!jre.isMatch(filter))
{
return getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY);
}
}
return null;
}
public Color getBackground(Object element)
{
return null;
}
public Font getFont(Object element, int columnIndex)
{
if (element instanceof JRE)
{
JRE jre = (JRE)element;
if (jre.isCurrent())
{
return ExtendedFontRegistry.INSTANCE.getFont(font, IItemFontProvider.BOLD_FONT);
}
}
return null;
}
}
}