/* * Copyright 2015 Nokia Solutions and Networks * Licensed under the Apache License, Version 2.0, * see license.txt file for details. */ package org.robotframework.ide.eclipse.main.plugin.project; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Optional; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.resource.FontDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StyledCellLabelProvider; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.StyledString.Styler; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; 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.graphics.Point; import org.eclipse.swt.graphics.TextStyle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PlatformUI; import org.rf.ide.core.dryrun.RobotDryRunLibraryImport; import org.rf.ide.core.dryrun.RobotDryRunLibraryImport.DryRunLibraryImportStatus; import org.robotframework.ide.eclipse.main.plugin.RedImages; import org.robotframework.ide.eclipse.main.plugin.project.library.SourceOpeningSupport; import org.robotframework.red.graphics.FontsManager; import org.robotframework.red.graphics.ImagesManager; import org.robotframework.red.viewers.TreeContentProvider; /** * @author mmarzec * @author bembenek */ public class LibrariesAutoDiscovererWindow extends Dialog { private static final String STATUS_ELEMENT_NAME = "Status"; private static final String SOURCE_ELEMENT_NAME = "Source"; private static final String IMPORTERS_ELEMENT_NAME = "Importers"; private static final String ADDITIONAL_INFO_ELEMENT_NAME = "Additional info"; private static final String ELEMENT_SEPARATOR = ":"; private static final Comparator<RobotDryRunLibraryImport> LIBRARY_IMPORT_COMPARATOR = (import1, import2) -> { if (import1.getStatus() == import2.getStatus()) { return import1.getName().compareToIgnoreCase(import2.getName()); } if (import1.getStatus() == DryRunLibraryImportStatus.ADDED && import2.getStatus() != DryRunLibraryImportStatus.ADDED) { return -1; } if (import1.getStatus() == DryRunLibraryImportStatus.NOT_ADDED && import2.getStatus() != DryRunLibraryImportStatus.NOT_ADDED) { return 1; } if (import1.getStatus() == DryRunLibraryImportStatus.ALREADY_EXISTING && import2.getStatus() == DryRunLibraryImportStatus.ADDED) { return 1; } if (import1.getStatus() == DryRunLibraryImportStatus.ALREADY_EXISTING && import2.getStatus() == DryRunLibraryImportStatus.NOT_ADDED) { return -1; } return 0; }; private TreeViewer discoveredLibrariesViewer; private StyledText detailsText; private final List<RobotDryRunLibraryImport> importedLibraries; public LibrariesAutoDiscovererWindow(final Shell parent, final List<RobotDryRunLibraryImport> importedLibraries) { super(parent); setShellStyle(SWT.CLOSE | SWT.MODELESS | SWT.BORDER | SWT.TITLE | SWT.RESIZE); setBlockOnOpen(false); this.importedLibraries = importedLibraries; } @Override protected Control createDialogArea(final Composite parent) { final Composite container = (Composite) super.createDialogArea(parent); createMainComposite(container); return container; } @Override protected void configureShell(final Shell newShell) { super.configureShell(newShell); newShell.setText("Discovering libraries summary"); } @Override protected Point getInitialSize() { return new Point(600, 550); } @Override protected void createButtonsForButtonBar(final Composite parent) { createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); } private Composite createMainComposite(final Composite parent) { final Composite mainComposite = new Composite(parent, SWT.NONE); GridLayoutFactory.fillDefaults().numColumns(1).margins(3, 3).applyTo(mainComposite); GridDataFactory.fillDefaults().grab(true, true).applyTo(mainComposite); final Label libsLabel = new Label(mainComposite, SWT.NONE); libsLabel.setText("Discovered libraries (" + importedLibraries.size() + "):"); createLibrariesViewer(mainComposite); createDetailsComposite(mainComposite); return mainComposite; } private void createLibrariesViewer(final Composite mainComposite) { discoveredLibrariesViewer = new TreeViewer(mainComposite); discoveredLibrariesViewer.getTree().setHeaderVisible(false); GridDataFactory.fillDefaults() .grab(true, true) .minSize(SWT.DEFAULT, 300) .applyTo(discoveredLibrariesViewer.getTree()); GridLayoutFactory.fillDefaults().numColumns(1).applyTo(discoveredLibrariesViewer.getTree()); discoveredLibrariesViewer.setContentProvider(new DiscoveredLibrariesViewerContentProvider()); discoveredLibrariesViewer.setLabelProvider(new DiscoveredLibrariesViewerLabelProvider()); Collections.sort(importedLibraries, LIBRARY_IMPORT_COMPARATOR); discoveredLibrariesViewer .setInput(importedLibraries.toArray(new RobotDryRunLibraryImport[importedLibraries.size()])); registerLibrariesViewerListeners(); } private void registerLibrariesViewerListeners() { discoveredLibrariesViewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(final SelectionChangedEvent event) { final Object selection = ((TreeSelection) event.getSelection()).getFirstElement(); if (selection != null) { if (selection instanceof DryRunLibraryImportChildElement) { detailsText.setText(selection.toString()); } else if (selection instanceof RobotDryRunLibraryImport) { detailsText.setText(convertDryRunLibraryImportToText((RobotDryRunLibraryImport) selection)); } else { detailsText.setText(""); } } } }); discoveredLibrariesViewer.getTree().addKeyListener(new KeyAdapter() { @Override public void keyReleased(final KeyEvent e) { if (e.keyCode == SWT.F3 && discoveredLibrariesViewer.getTree().getSelectionCount() == 1) { handleFileOpeningEvent(); } } }); final Menu menu = createContextMenu(); discoveredLibrariesViewer.getTree().addMouseListener(new MouseAdapter() { @Override public void mouseDown(final MouseEvent e) { if (e.button == 3 && discoveredLibrariesViewer.getTree().getSelectionCount() == 1 && getOpenableFilePath().isPresent()) { menu.setVisible(true); } } @Override public void mouseDoubleClick(final MouseEvent e) { if (e.button == 1 && discoveredLibrariesViewer.getTree().getSelectionCount() == 1) { handleFileOpeningEvent(); } } }); } private Menu createContextMenu() { final Menu menu = new Menu(discoveredLibrariesViewer.getTree()); final MenuItem gotoItem = new MenuItem(menu, SWT.PUSH); gotoItem.setText("Go to File"); gotoItem.setImage(ImagesManager.getImage(RedImages.getGoToImage())); gotoItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent event) { handleFileOpeningEvent(); } }); return menu; } private void handleFileOpeningEvent() { final Optional<String> filePath = getOpenableFilePath(); if (filePath.isPresent()) { final Optional<IFile> openableFile = getOpenableFile(filePath.get()); if (openableFile.isPresent()) { final IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); SourceOpeningSupport.tryToOpenInEditor(page, openableFile.get()); } } } private Optional<String> getOpenableFilePath() { final TreeSelection selection = (TreeSelection) discoveredLibrariesViewer.getSelection(); if (selection != null && selection.getFirstElement() instanceof DryRunLibraryImportChildElement) { final DryRunLibraryImportChildElement childElement = (DryRunLibraryImportChildElement) selection .getFirstElement(); if (childElement.isOpenableFilePath()) { return Optional.of(childElement.getValue()); } } return Optional.empty(); } private static Optional<IFile> getOpenableFile(final String filePath) { final IPath path = new Path(filePath); final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(path); if (file != null && file.exists()) { return Optional.of(file); } return Optional.empty(); } private void createDetailsComposite(final Composite mainComposite) { final Composite detailsComposite = new Composite(mainComposite, SWT.NONE); GridLayoutFactory.fillDefaults().numColumns(1).applyTo(detailsComposite); GridDataFactory.fillDefaults().hint(SWT.DEFAULT, 100).grab(true, false).applyTo(detailsComposite); detailsText = new StyledText(detailsComposite, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.WRAP); detailsText.setFont(JFaceResources.getTextFont()); GridDataFactory.fillDefaults().grab(true, true).applyTo(detailsText); GridLayoutFactory.fillDefaults().applyTo(detailsText); detailsText.setEditable(false); detailsText.setAlwaysShowScrollBars(false); } private String convertDryRunLibraryImportToText(final RobotDryRunLibraryImport libraryImport) { final StringBuilder libraryImportTxtBuilder = new StringBuilder(""); for (final Object child : extractDryRunLibraryImportChildren(libraryImport)) { if (child instanceof DryRunLibraryImportChildElement) { libraryImportTxtBuilder.append(child + "\n"); } else if (child instanceof DryRunLibraryImportListChildElement) { libraryImportTxtBuilder.append(((DryRunLibraryImportListChildElement) child).getName() + "\n"); for (final DryRunLibraryImportChildElement listChild : ((DryRunLibraryImportListChildElement) child) .getList()) { libraryImportTxtBuilder.append(listChild + "\n"); } } } return libraryImportTxtBuilder.toString(); } private List<Object> extractDryRunLibraryImportChildren(final RobotDryRunLibraryImport libraryImport) { final List<Object> children = new ArrayList<>(); if (libraryImport.getStatus() != null) { children.add( new DryRunLibraryImportChildElement(STATUS_ELEMENT_NAME, libraryImport.getStatus().getMessage())); } if (libraryImport.getSourcePath() != null && !libraryImport.getSourcePath().isEmpty()) { children.add(new DryRunLibraryImportChildElement(SOURCE_ELEMENT_NAME, libraryImport.getSourcePath(), true)); } else { children.add(new DryRunLibraryImportChildElement(SOURCE_ELEMENT_NAME, "Unknown")); } final List<String> importersPaths = libraryImport.getImportersPaths(); if (importersPaths.size() == 1) { children.add(new DryRunLibraryImportChildElement(IMPORTERS_ELEMENT_NAME, importersPaths.get(0), true)); } else { children.add(new DryRunLibraryImportListChildElement(IMPORTERS_ELEMENT_NAME, importersPaths)); } final String additionalInfo = libraryImport.getAdditionalInfo(); if (additionalInfo != null && !additionalInfo.isEmpty()) { children.add(new DryRunLibraryImportChildElement(ADDITIONAL_INFO_ELEMENT_NAME, additionalInfo)); } return children; } private class DiscoveredLibrariesViewerContentProvider extends TreeContentProvider { @Override public Object[] getElements(final Object inputElement) { return (RobotDryRunLibraryImport[]) inputElement; } @Override public Object[] getChildren(final Object parentElement) { if (parentElement instanceof RobotDryRunLibraryImport) { final List<Object> children = extractDryRunLibraryImportChildren( (RobotDryRunLibraryImport) parentElement); return children.toArray(new Object[children.size()]); } else if (parentElement instanceof DryRunLibraryImportListChildElement) { final List<DryRunLibraryImportChildElement> childElementList = ((DryRunLibraryImportListChildElement) parentElement) .getList(); return childElementList.toArray(new DryRunLibraryImportChildElement[childElementList.size()]); } return null; } @Override public Object getParent(final Object element) { return null; } @Override public boolean hasChildren(final Object element) { if (element instanceof DryRunLibraryImportChildElement) { return false; } return true; } } private class DiscoveredLibrariesViewerLabelProvider extends StyledCellLabelProvider { @Override public void update(final ViewerCell cell) { final StyledString label = getStyledString(cell.getElement()); cell.setText(label.getString()); cell.setStyleRanges(label.getStyleRanges()); cell.setImage(getImage(cell.getElement())); super.update(cell); } private StyledString getStyledString(final Object element) { StyledString label = new StyledString(""); if (element instanceof RobotDryRunLibraryImport) { final String name = ((RobotDryRunLibraryImport) element).getName().replaceAll("\\n", "/n"); label = new StyledString(name); } else if (element instanceof DryRunLibraryImportChildElement) { final DryRunLibraryImportChildElement libraryImportChildElement = (DryRunLibraryImportChildElement) element; final String childElementName = libraryImportChildElement.getName(); if (childElementName != null && !childElementName.isEmpty()) { label.append(new StyledString(childElementName, new Styler() { @Override public void applyStyles(final TextStyle textStyle) { textStyle.font = getFont(textStyle.font, SWT.BOLD); } })); label.append(" "); } final String childElementValue = libraryImportChildElement.getValue(); if (childElementValue != null && !childElementValue.isEmpty()) { if (libraryImportChildElement.isOpenableFilePath()) { label.append(new StyledString(childElementValue, new Styler() { @Override public void applyStyles(final TextStyle textStyle) { textStyle.underline = true; textStyle.foreground = Display.getCurrent().getSystemColor(SWT.COLOR_BLUE); } })); } else { label.append(childElementValue); } } } else if (element instanceof DryRunLibraryImportListChildElement) { label = new StyledString(((DryRunLibraryImportListChildElement) element).getName(), new Styler() { @Override public void applyStyles(final TextStyle textStyle) { textStyle.font = getFont(textStyle.font, SWT.BOLD); } }); } return label; } private Font getFont(final Font fontToReuse, final int style) { final Font currentFont = fontToReuse == null ? Display.getCurrent().getSystemFont() : fontToReuse; final FontDescriptor fontDescriptor = FontDescriptor.createFrom(currentFont).setStyle(style); return FontsManager.getFont(fontDescriptor); } private Image getImage(final Object element) { if (element instanceof RobotDryRunLibraryImport) { final RobotDryRunLibraryImport libraryImport = (RobotDryRunLibraryImport) element; if (libraryImport.getStatus() == DryRunLibraryImportStatus.NOT_ADDED) { return ImagesManager.getImage(RedImages.getFatalErrorImage()); } else if (libraryImport.getStatus() == DryRunLibraryImportStatus.ADDED) { return ImagesManager.getImage(RedImages.getBigSuccessImage()); } else if (libraryImport.getStatus() == DryRunLibraryImportStatus.ALREADY_EXISTING) { return ImagesManager.getImage(RedImages.getBigWarningImage()); } } else if (element instanceof DryRunLibraryImportChildElement || element instanceof DryRunLibraryImportListChildElement) { return ImagesManager.getImage(RedImages.getElementImage()); } return null; } } private static class DryRunLibraryImportChildElement { private String name; private final String value; private final boolean isOpenableFilePath; public DryRunLibraryImportChildElement(final String name, final String value) { this(name, value, false); } public DryRunLibraryImportChildElement(final String name, final String value, final boolean isFilePath) { if (name != null) { this.name = name + ELEMENT_SEPARATOR; } this.value = value; this.isOpenableFilePath = isFilePath && getOpenableFile(value).isPresent(); } public String getName() { return name; } public String getValue() { return value; } public boolean isOpenableFilePath() { return isOpenableFilePath; } @Override public String toString() { if (value == null && name != null) { return name; } if (value != null && name == null) { return value; } if (value == null && name == null) { return ""; } return name + " " + value; } } private static class DryRunLibraryImportListChildElement { private String name; private final List<DryRunLibraryImportChildElement> list = new ArrayList<>(); public DryRunLibraryImportListChildElement(final String name, final List<String> list) { if (name != null) { this.name = name + ELEMENT_SEPARATOR; } if (list != null) { for (final String listElement : list) { this.list.add(new DryRunLibraryImportChildElement(null, listElement, true)); } } } public List<DryRunLibraryImportChildElement> getList() { return list; } public String getName() { return name; } } }