package de.urszeidler.eclipse.solidity.compiler.support.preferences; import java.io.File; import java.io.FilenameFilter; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferencePage; import org.eclipse.jface.viewers.ISelectionChangedListener; 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.TableViewer; import org.eclipse.jface.viewers.Viewer; 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.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.DirectoryDialog; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; import de.urszeidler.eclipse.solidity.compiler.support.Activator; import de.urszeidler.eclipse.solidity.compiler.support.preferences.PreferenceConstants.SolC; import de.urszeidler.eclipse.solidity.compiler.support.util.StartCompiler; public class InstalledSolidityCompilerPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { private static final String SOLC_VERSION_PATTERN = "((.*)Version:[ ]*(.*)$)"; private static class ContentProvider implements IStructuredContentProvider { public Object[] getElements(Object inputElement) { return new Object[0]; } public void dispose() { } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } } private class TableLabelProvider extends LabelProvider implements ITableLabelProvider { public Image getColumnImage(Object element, int columnIndex) { return null; } public String getColumnText(Object element, int columnIndex) { return element.toString(); } } private Table fTable; private TableViewer fCompilerList; private Button fAddButton; private Button fRemoveButton; private Button fSearchButton; // private List<String> installedSolidityCompilers; private List<SolC> installedSolCs; /** * Create the preference page. */ public InstalledSolidityCompilerPreferencePage() { super(); setDescription("Add/remove or search solidity compilers useable with the solidity builder."); } /** * Create contents of the preference page. * * @param parent */ @Override protected Control createContents(Composite parent) { IPreferenceStore store = getPreferenceStore(); String isc = store.getString(PreferenceConstants.INSTALLED_SOL_COMPILERS); installedSolCs = PreferenceConstants.parsePreferences(isc); Composite container = new Composite(parent, SWT.NULL); container.setLayout(new GridLayout(3, false)); Font font = parent.getFont(); fTable = new Table(container, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION); GridData gd = new GridData(GridData.FILL_BOTH); gd.heightHint = 250; gd.widthHint = 350; fTable.setLayoutData(gd); fTable.setFont(font); fTable.setHeaderVisible(true); fTable.setLinesVisible(true); TableColumn column = new TableColumn(fTable, SWT.NULL); column.setText("Compiler"); column.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { fCompilerList.refresh(true); } }); int defaultwidth = 350 / 3 + 1; column.setWidth(defaultwidth); column = new TableColumn(fTable, SWT.NULL); column.setText("version"); column.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { fCompilerList.refresh(true); } }); column.setWidth(defaultwidth); column = new TableColumn(fTable, SWT.NULL); column.setText("path"); column.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { fCompilerList.refresh(true); } }); column.setWidth(defaultwidth); fCompilerList = new TableViewer(fTable); fCompilerList.setUseHashlookup(true); fCompilerList.setContentProvider(new ContentProvider() { @Override public Object[] getElements(Object inputElement) { return installedSolCs.toArray(); } }); fCompilerList.setLabelProvider(new TableLabelProvider() { @Override public String getColumnText(Object element, int columnIndex) { if (element instanceof SolC) { SolC solc = (SolC) element; switch (columnIndex) { case 0: return solc.name; case 1: return solc.version; case 2: return solc.path; } } return super.getColumnText(element, columnIndex); } }); Composite buttons = new Composite(container, SWT.NULL); buttons.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false, 1, 1)); buttons.setLayout(new GridLayout(1, false)); fAddButton = new Button(buttons, SWT.PUSH); fAddButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); fAddButton.setText("add"); fAddButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event evt) { addCompiler(); } }); fRemoveButton = new Button(buttons, SWT.PUSH); fRemoveButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); fRemoveButton.setText("remove"); fRemoveButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event evt) { removeCompilers(); } }); fSearchButton = new Button(buttons, SWT.PUSH); fSearchButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); fSearchButton.setText("search"); fSearchButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event evt) { search(); } }); fAddButton.setEnabled(installedSolCs.size() > 0); new Label(container, SWT.NONE); fCompilerList.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent evt) { enableButtons(); } }); fTable.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent event) { if (event.character == SWT.DEL && event.stateMask == 0) { if (fRemoveButton.isEnabled()) { removeCompilers(); } } } }); enableButtons(); fCompilerList.setInput(installedSolCs.toArray()); return container; } protected void enableButtons() { fAddButton.setEnabled(true); fRemoveButton.setEnabled(!fCompilerList.getSelection().isEmpty()); } protected void addCompiler() { FileDialog fileDialog = new FileDialog(getShell()); fileDialog.setFileName("solc"); fileDialog.setText("select solc "); String open = fileDialog.open(); File file = new File(open); SolC testSolCFile = testSolCFile(file); if (testSolCFile != null) { installedSolCs.add(testSolCFile); fCompilerList.setInput(installedSolCs); } } private SolC testSolCFile(File file) { final SolC solC = PreferenceConstants.solCof(file.getName(), file.getAbsolutePath(), null); if (file != null && file.canExecute() && file.getName().toLowerCase().equals("solc")) { List<String> options = new ArrayList<String>(); options.add(file.getAbsolutePath()); options.add("--version"); final Pattern compile2 = Pattern.compile(SOLC_VERSION_PATTERN, Pattern.MULTILINE | Pattern.DOTALL); StartCompiler.startCompiler(Collections.<String>emptyList(), new StartCompiler.CompilerCallback() { @Override public void compiled(String input, String error, Exception exception) { if (exception != null) Activator.logError(error, exception); System.out.println(input); if (input != null) { Matcher matcher = compile2.matcher(input); if (matcher.matches()) { solC.version = matcher.group(3).trim(); } } } }, options); if (solC.version != null) { solC.name = solC.name + "-" + solC.version; return solC; } } return null; } protected void removeCompilers() { IStructuredSelection structuredSelection = fCompilerList.getStructuredSelection(); if (installedSolCs.remove(structuredSelection.getFirstElement())) fCompilerList.setInput(installedSolCs.toArray()); } protected void search() { DirectoryDialog directoryDialog = new DirectoryDialog(getShell()); directoryDialog.setText("search solc "); String open = directoryDialog.open(); final File file = new File(open); final Set<SolC> list = new HashSet<SolC>(); IRunnableWithProgress withProgress = new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { monitor.beginTask("file:" + file.getAbsolutePath(), IProgressMonitor.UNKNOWN); searchAndAdd(file, list, monitor); monitor.done(); } }; try { new ProgressMonitorDialog(getShell()).run(true, true, withProgress); installedSolCs.addAll(list); fCompilerList.setInput(installedSolCs.toArray()); } catch (InvocationTargetException | InterruptedException e) { Activator.logError("", e); } } /** * @param file * @param list * @param monitor */ private void searchAndAdd(File file, Set<SolC> list, IProgressMonitor monitor) { if(file==null || monitor.isCanceled()) return; testAndAdd(list, file); monitor.setTaskName("Searching: found("+list.size()+") "+ file.getAbsolutePath()); File[] listFiles = file.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return dir.isDirectory(); } }); if (listFiles != null) for (File file2 : listFiles) { searchAndAdd(file2, list, monitor); } } /** * @param list * @param file2 */ private void testAndAdd(Set<SolC> list, File file2) { if (file2 == null) return; File[] listFiles2 = file2.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return "solc".equals(name); } }); if (listFiles2 != null && listFiles2.length == 1) { SolC testSolCFile = testSolCFile(listFiles2[0]); if (testSolCFile != null) list.add(testSolCFile); } } /** * Initialize the preference page. */ public void init(IWorkbench workbench) { setPreferenceStore(Activator.getDefault().getPreferenceStore()); } @Override protected void performApply() { StringBuffer buffer = new StringBuffer(); for (Iterator<SolC> iterator = installedSolCs.iterator(); iterator.hasNext();) { SolC solC = (SolC) iterator.next(); buffer.append(solC.name).append(",").append(solC.path).append(",").append(solC.version); if (iterator.hasNext()) buffer.append("::"); } getPreferenceStore().setValue(PreferenceConstants.INSTALLED_SOL_COMPILERS, buffer.toString()); super.performApply(); } }