/******************************************************************************* * Copyright (c) 2017 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is 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: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.windup.ui.internal.rules; import java.io.File; import java.rmi.RemoteException; import java.util.List; import javax.inject.Inject; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.e4.core.contexts.ContextInjectionFactory; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.e4.core.di.annotations.Optional; import org.eclipse.e4.ui.di.UIEventTopic; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.util.LocalSelectionTransfer; import org.eclipse.jface.viewers.AbstractTreeViewer; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerDropAdapter; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.FileTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.dnd.TransferData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.part.ViewPart; import org.jboss.tools.windup.model.domain.ModelService; import org.jboss.tools.windup.model.domain.WindupConstants; import org.jboss.tools.windup.model.domain.WindupDomainListener.RulesetChange; import org.jboss.tools.windup.runtime.WindupRmiClient; import org.jboss.tools.windup.ui.WindupUIPlugin; import org.jboss.tools.windup.ui.internal.Messages; import org.jboss.tools.windup.ui.internal.rules.RulesNode.CustomRulesNode; import org.jboss.tools.windup.ui.internal.rules.RulesNode.RulesetFileNode; import org.jboss.tools.windup.ui.internal.rules.xml.XMLRulesetModelUtil; import org.jboss.tools.windup.windup.CustomRuleProvider; import org.jboss.windup.tooling.ExecutionBuilder; import org.jboss.windup.tooling.rules.RuleProviderRegistry; import org.w3c.dom.Node; import com.google.common.collect.Lists; import com.google.common.io.Files; /** * View for displaying Windup rule repositories. */ @SuppressWarnings("restriction") public class RuleRepositoryView extends ViewPart { public static final String VIEW_ID = "org.jboss.tools.windup.ui.rules.rulesView"; //$NON-NLS-1$ private TreeViewer treeViewer; private RuleRepositoryContentProvider contentProvider; @Inject private WindupRmiClient windupClient; @Inject private ModelService modelService; @Inject private IEclipseContext context; private MenuManager menuManager; @Override public void createPartControl(Composite parent) { GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(parent); GridDataFactory.fillDefaults().grab(true, true).applyTo(parent); try { createSystemRulesTreeViewer(parent); } catch (RemoteException e1) { WindupUIPlugin.log(e1); return; } treeViewer.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(DoubleClickEvent event) { if (event.getSelection().isEmpty()) { return; } ISelection selection = event.getSelection(); if (selection instanceof ITreeSelection) { Object element = ((ITreeSelection)selection).getFirstElement(); if (element instanceof RulesetFileNode) { RulesetFileNode node = (RulesetFileNode)element; IFileStore fileStore = EFS.getLocalFileSystem().getStore(new Path(node.getFile().getParent())); fileStore = fileStore.getChild(node.getName()); if (!fileStore.fetchInfo().isDirectory() && fileStore.fetchInfo().exists()) { IWorkbenchPage page= PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); try { IDE.openEditorOnFileStore(page, fileStore); } catch (PartInitException e) { WindupUIPlugin.log(e); MessageDialog.openError( Display.getDefault().getActiveShell(), Messages.openRuleset, Messages.errorOpeningRuleset); } } } else if (element instanceof Node) { Node node = (Node)element; Object provider = contentProvider.getProvider(node); if (provider != null) { XMLRulesetModelUtil.openRuleInEditor(provider, node); } } } } }); super.getSite().setSelectionProvider(treeViewer); menuManager = new MenuManager(); menuManager.setRemoveAllWhenShown(true); menuManager.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { RuleRepositoryView.this.fillContextMenu(manager); } }); Menu menu = menuManager.createContextMenu(treeViewer.getControl()); treeViewer.getControl().setMenu(menu); //getSite().registerContextMenu(menuManager, treeViewer); treeViewer.addDropSupport(DND.DROP_COPY| DND.DROP_MOVE, new Transfer[]{LocalSelectionTransfer.getTransfer(), FileTransfer.getInstance()}, new RulesetDropListener(treeViewer)); } private class RulesetDropListener extends ViewerDropAdapter { protected RulesetDropListener(Viewer viewer) { super(viewer); } private void addRulesets(String[] rulesetLocations, boolean isLocal) { List<CustomRuleProvider> providers = Lists.newArrayList(); WorkspaceModifyOperation operation = new WorkspaceModifyOperation() { @Override public void execute(IProgressMonitor monitor) { for (String rulesetLocation : rulesetLocations) { CustomRuleProvider provider = modelService.addRulesetRepository(rulesetLocation, true); //$NON-NLS-1$ providers.add(provider); } } }; try { new ProgressMonitorDialog(getSite().getShell()).run(false, false, operation); } catch (Exception e) { WindupUIPlugin.log(e); } } @Override public boolean performDrop(Object data) { Object target = getCurrentTarget(); if (target instanceof CustomRulesNode) { TransferData transferType = getCurrentEvent().currentDataType; if (LocalSelectionTransfer.getTransfer().isSupportedType(transferType)) { IStructuredSelection selection = (IStructuredSelection) data; List<String> locations = Lists.newArrayList(); for (Object selected : selection.toList()) { if (selected instanceof IAdaptable) { IFile file = ((IAdaptable)selected).getAdapter(IFile.class); if (file != null && file.getLocation() != null) { locations.add(file.getLocation().toString()); } } } if (!locations.isEmpty()) { addRulesets(locations.stream().toArray(String[]::new), true); } } else if (FileTransfer.getInstance().isSupportedType(transferType)) { List<String> locations = Lists.newArrayList(); String[] fileLocations = (String[]) data; if (fileLocations != null && fileLocations.length > 0) { for (String fileLocation : fileLocations) { File file = new File(fileLocation); if (file.exists() && !file.isDirectory()) { String extension = Files.getFileExtension(fileLocation); if (extension.equals(NewXMLFilePage.EXTENSION)) { locations.add(fileLocation); } } } if (!locations.isEmpty()) { addRulesets(locations.stream().toArray(String[]::new), false); return true; } } } } return false; } @Override public boolean validateDrop(Object target, int operation, TransferData transferType) { if (target instanceof CustomRulesNode) { switch (getCurrentLocation()) { case ViewerDropAdapter.LOCATION_AFTER: return false; case ViewerDropAdapter.LOCATION_ON: { overrideOperation(DND.DROP_COPY); return true; } case ViewerDropAdapter.LOCATION_BEFORE: return false; case ViewerDropAdapter.LOCATION_NONE: return false; } } return false; } } private void fillContextMenu(IMenuManager manager) { IStructuredSelection selection = (IStructuredSelection)treeViewer.getSelection(); List<CustomRuleProvider> providers = Lists.newArrayList(); for (Object selected : selection.toList()) { if (!(selected instanceof CustomRuleProvider)) { return; } providers.add((CustomRuleProvider)selected); } if (!providers.isEmpty()) { RemoveRulesetHandler action = ContextInjectionFactory.make(RemoveRulesetHandler.class, context); action.setProviders(providers); manager.add(action); } if (providers.size() == 1) { manager.add(new Separator()); NewXMLRuleHandler action = ContextInjectionFactory.make(NewXMLRuleHandler.class, context); action.setProvider(providers.get(0)); manager.add(action); } } @Inject @Optional private void rulesetAdded(@UIEventTopic(WindupConstants.CUSTOM_RULESET_CHANGED) RulesetChange change) throws RemoteException { if (treeViewer != null && !treeViewer.getTree().isDisposed()) { CustomRulesNode root = (CustomRulesNode)((RuleRepositoryInput)treeViewer.getInput()).getChildren()[1]; treeViewer.refresh(root); if (!change.isDelete()) { treeViewer.setSelection(new StructuredSelection(change.getProviders()), true); change.getProviders().forEach(provider -> treeViewer.expandToLevel(provider, AbstractTreeViewer.ALL_LEVELS)); } } } private void createSystemRulesTreeViewer(Composite parent) throws RemoteException { treeViewer = new TreeViewer(parent, SWT.FULL_SELECTION|SWT.MULTI|SWT.V_SCROLL|SWT.H_SCROLL); GridDataFactory.fillDefaults().grab(true, true).applyTo(treeViewer.getControl()); contentProvider = new RuleRepositoryContentProvider(treeViewer); treeViewer.setContentProvider(contentProvider); treeViewer.setLabelProvider(new DelegatingStyledCellLabelProvider(contentProvider)); refresh(); } @Inject @Optional private void updateServer(@UIEventTopic(WindupRmiClient.WINDUP_SERVER_STATUS) ExecutionBuilder executionBuilder) throws RemoteException { if (treeViewer != null && !treeViewer.getTree().isDisposed()) { refresh(); } } public void refresh() throws RemoteException { if (windupClient.isWindupServerRunning()) { Job fetchJob = new Job(Messages.refreshingRules) { //$NON-NLS-1$ @Override protected IStatus run(IProgressMonitor monitor) { RuleProviderRegistry systemRuleProviderRegistry = null; if (windupClient.isWindupServerRunning()) { try { systemRuleProviderRegistry = windupClient.getExecutionBuilder().getSystemRuleProviderRegistry(); } catch (RemoteException e) { WindupUIPlugin.log(e); Display.getDefault().asyncExec(() -> { MessageDialog.openError( Display.getDefault().getActiveShell(), Messages.refreshingRules, Messages.refreshingRulesError); }); } } refreshRulesTree(systemRuleProviderRegistry); return Status.OK_STATUS; } }; fetchJob.setSystem(true); fetchJob.schedule(); } else { refreshRulesTree(null); } } private void refreshRulesTree(RuleProviderRegistry systemRuleProviderRegistry) { Display.getDefault().asyncExec(() -> { treeViewer.setInput(RuleRepositoryInput.computeInput(systemRuleProviderRegistry, modelService)); }); } @Override public void setFocus() { treeViewer.getTree().setFocus(); } }