/*******************************************************************************
* Copyright (c) 2015 Pivotal Software, Inc.
* 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:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.dash.ngrok;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
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.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.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.springframework.ide.eclipse.boot.core.BootActivator;
import org.springframework.ide.eclipse.boot.util.SWTFactory;
/**
* @author Christian Dupuis
* @author Steffen Pingel
* @author Kris De Volder
*/
public class NGROKInstallBlock implements ISelectionProvider {
private static final int defaultColumnWidth = 350;
class NGROKContentProvider implements IStructuredContentProvider {
public void dispose() {
}
public Object[] getElements(Object input) {
return ngroks.toArray();
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
class NGROKLabelProvider extends LabelProvider implements ITableLabelProvider {
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
public String getColumnText(Object element, int columnIndex) {
return element.toString();
}
}
private Composite control;
private final List<String> ngroks = new ArrayList<String>();
private CheckboxTableViewer ngrokList;
private Button addButton;
private Button removeButton;
private Button editButton;
private final ListenerList selectionListeners = new ListenerList();
private ISelection prevSelection = new StructuredSelection();
private Table table;
private NGROKInstallManager installManager;
public NGROKInstallBlock(NGROKInstallManager installManager) {
this.installManager = installManager;
}
public void addSelectionChangedListener(ISelectionChangedListener listener) {
selectionListeners.add(listener);
}
public void createControl(Composite ancestor) {
Font font = ancestor.getFont();
Composite parent = SWTFactory.createComposite(ancestor, font, 2, 1, GridData.FILL_BOTH);
control = parent;
SWTFactory.createLabel(parent, "ngrok Installations:", 2);
table = new Table(parent, SWT.CHECK | SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
GridData gd = new GridData(GridData.FILL_BOTH);
gd.heightHint = 250;
gd.widthHint = 350;
table.setLayoutData(gd);
table.setFont(font);
table.setHeaderVisible(true);
table.setLinesVisible(true);
TableColumn column = new TableColumn(table, SWT.NULL);
column.setText("Location");
column.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
sortByLocation();
}
});
ngrokList = new CheckboxTableViewer(table);
ngrokList.setLabelProvider(new NGROKLabelProvider());
ngrokList.setContentProvider(new NGROKContentProvider());
// by default, sort by name
sortByLocation();
ngrokList.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent evt) {
enableButtons();
}
});
ngrokList.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
if (event.getChecked()) {
setCheckedNGROK((String) event.getElement());
}
else {
setCheckedNGROK(null);
}
}
});
ngrokList.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent e) {
if (!ngrokList.getSelection().isEmpty()) {
editNGROK();
}
}
});
table.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent event) {
if (event.character == SWT.DEL && event.stateMask == 0) {
if (removeButton.isEnabled()) {
removeNGROKs();
}
}
}
});
Composite buttons = SWTFactory.createComposite(parent, font, 1, 1, GridData.VERTICAL_ALIGN_BEGINNING, 0, 0);
addButton = SWTFactory.createPushButton(buttons, "Add...", null);
addButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event evt) {
addNGROK();
}
});
editButton = SWTFactory.createPushButton(buttons, "Edit...", null);
editButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event evt) {
editNGROK();
}
});
removeButton = SWTFactory.createPushButton(buttons, "Remove...", null);
removeButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event evt) {
removeNGROKs();
}
});
SWTFactory.createVerticalSpacer(parent, 1);
fillWithWorkspaceNGROKs();
enableButtons();
addButton.setEnabled(true);
}
public String getCheckedNGROK() {
Object[] objects = ngrokList.getCheckedElements();
if (objects.length == 0) {
return null;
}
return (String) objects[0];
}
public Control getControl() {
return control;
}
public String[] getNGROKs() {
return ngroks.toArray(new String[ngroks.size()]);
}
public ISelection getSelection() {
return new StructuredSelection(ngrokList.getCheckedElements());
}
public boolean isDuplicateName(String name) {
for (int i = 0; i < ngroks.size(); i++) {
String ngrok = ngroks.get(i);
if (ngrok.equals(name)) {
return true;
}
}
return false;
}
public void removeNGROKs(String[] ngroksToBeRemoved) {
IStructuredSelection prev = (IStructuredSelection) getSelection();
for (String ngrok : ngroksToBeRemoved) {
ngroks.remove(ngrok);
}
ngrokList.refresh();
IStructuredSelection curr = (IStructuredSelection) getSelection();
if (!curr.equals(prev)) {
String[] installs = getNGROKs();
if (curr.size() == 0 && installs.length == 1) {
setSelection(new StructuredSelection(installs[0]));
}
else {
fireSelectionChanged();
}
}
}
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
selectionListeners.remove(listener);
}
public void restoreColumnSettings(IDialogSettings settings, String qualifier) {
ngrokList.getTable().layout(true);
restoreColumnWidths(settings, qualifier);
}
public void saveColumnSettings(IDialogSettings settings, String qualifier) {
int columnCount = table.getColumnCount();
for (int i = 0; i < columnCount; i++) {
settings.put(qualifier + ".columnWidth" + i, table.getColumn(i).getWidth()); //$NON-NLS-1$
}
}
public void setCheckedNGROK(String vm) {
if (vm == null) {
setSelection(new StructuredSelection());
}
else {
setSelection(new StructuredSelection(vm));
}
}
public void setSelection(ISelection selection) {
if (selection instanceof IStructuredSelection) {
if (!selection.equals(prevSelection)) {
prevSelection = selection;
Object ngrok = ((IStructuredSelection) selection).getFirstElement();
if (ngrok == null) {
ngrokList.setCheckedElements(new Object[0]);
}
else {
ngrokList.setCheckedElements(new Object[] { ngrok });
ngrokList.reveal(ngrok);
}
fireSelectionChanged();
}
}
}
public void ngrokAdded(String ngrok) {
ngroks.add(ngrok);
ngrokList.refresh();
}
private void addNGROK() {
try {
FileDialog fileDialog = new FileDialog(control.getShell());
fileDialog.setText("select ngrok executable");
String result = fileDialog.open();
if (result != null) {
ngroks.add(result);
ngrokList.refresh();
ngrokList.setSelection(new StructuredSelection(result));
setSelection(new StructuredSelection(result));
}
} catch (Exception e) {
BootActivator.log(e);
}
}
private void editNGROK() {
IStructuredSelection selection = (IStructuredSelection) ngrokList.getSelection();
String ngrok = (String) selection.getFirstElement();
if (ngrok == null) {
return;
}
FileDialog fileDialog = new FileDialog(control.getShell());
fileDialog.setText("select ngrok executable");
fileDialog.setFileName(ngrok);
String result = fileDialog.open();
if (result != null) {
// replace with the edited VM
int index = ngroks.indexOf(ngrok);
ngroks.remove(index);
ngroks.add(index, result);
ngrokList.refresh();
ngrokList.setSelection(new StructuredSelection(result));
}
}
private void enableButtons() {
IStructuredSelection selection = (IStructuredSelection) ngrokList.getSelection();
int selectionCount = selection.size();
editButton.setEnabled(selectionCount == 1);
if (selectionCount > 0 && selectionCount < ngrokList.getTable().getItemCount()) {
removeButton.setEnabled(true);
}
else {
removeButton.setEnabled(false);
}
}
private void fireSelectionChanged() {
SelectionChangedEvent event = new SelectionChangedEvent(this, getSelection());
Object[] listeners = selectionListeners.getListeners();
for (Object listener2 : listeners) {
ISelectionChangedListener listener = (ISelectionChangedListener) listener2;
listener.selectionChanged(event);
}
}
private void removeNGROKs() {
IStructuredSelection selection = (IStructuredSelection) ngrokList.getSelection();
String[] ngroks = new String[selection.size()];
Iterator<String> iter = selection.iterator();
int i = 0;
while (iter.hasNext()) {
ngroks[i] = iter.next();
i++;
}
removeNGROKs(ngroks);
}
private void restoreColumnWidths(IDialogSettings settings, String qualifier) {
int columnCount = table.getColumnCount();
for (int i = 0; i < columnCount; i++) {
int width = -1;
try {
width = settings.getInt(qualifier + ".columnWidth" + i); //$NON-NLS-1$
}
catch (NumberFormatException e) {
}
if (width <= 0) {
table.getColumn(i).setWidth(defaultColumnWidth);
}
else {
table.getColumn(i).setWidth(width);
}
}
}
private void sortByLocation() {
ngrokList.setComparator(new ViewerComparator() {
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
if ((e1 instanceof String) && (e2 instanceof String)) {
String left = (String) e1;
String right = (String) e2;
return left.compareToIgnoreCase(right);
}
return super.compare(viewer, e1, e2);
}
@Override
public boolean isSorterProperty(Object element, String property) {
return true;
}
});
}
protected void fillWithWorkspaceNGROKs() {
Collection<String> installs = installManager.getInstalls();
String deflt = null;
try {
deflt = installManager.getDefaultInstall();
} catch (Exception e) {
BootActivator.log(e);
}
setNGROKs(installs.toArray(new String[installs.size()]), deflt);
}
protected Shell getShell() {
return getControl().getShell();
}
protected void setNGROKs(String[] newNgroks, String dflt) {
ngroks.clear();
for (String ngrok : newNgroks) {
ngroks.add(ngrok);
}
ngrokList.setInput(ngroks);
ngrokList.refresh();
for (String ngrok : newNgroks) {
if (ngrok.equals(dflt)) {
setCheckedNGROK(ngrok);
}
}
}
}