/******************************************************************************* * Copyright (c) 2015 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.batch.ui.hyperlink; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.PopupDialog; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.Region; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.IOpenListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.OpenEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StyledCellLabelProvider; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.StyledString.Styler; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.graphics.TextStyle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.dialogs.PatternFilter; import org.jboss.tools.batch.core.BatchConstants; import org.jboss.tools.batch.core.IBatchProperty; import org.jboss.tools.batch.internal.core.impl.BatchUtil; import org.jboss.tools.batch.internal.core.impl.BatchUtil.NodePathTextSourceReference; import org.jboss.tools.batch.ui.JobImages; import org.jboss.tools.common.text.ITextSourceReference; import org.jboss.tools.common.text.ext.hyperlink.xpl.AbstractBaseHyperlink; import org.jboss.tools.common.text.ext.util.StructuredSelectionHelper; import org.jboss.tools.jst.web.kb.KbQuery.Tag; public class BatchPropertyDialog extends PopupDialog { private IBatchProperty batchProperty; private HashMap<IFile, List<NodePathTextSourceReference>> references = new HashMap<IFile, List<NodePathTextSourceReference>>(); private Composite composite; private Text fFilterText; private TreeViewer tree; private ReferencePatternFilter patternFilter; public BatchPropertyDialog(Shell parentShell, final IBatchProperty batchProperty) { super(parentShell, 0, true, true, false, false, false, "", null); this.batchProperty = batchProperty; BusyIndicator.showWhile(parentShell != null ? parentShell.getDisplay() : Display.getDefault(), new Runnable() { @Override public void run() { for (IFile file : batchProperty.getArtifact().getProject().getDeclaredBatchJobs()) { List<NodePathTextSourceReference> list = BatchUtil.getNodePathPropertyAttributeReferences(file, batchProperty.getArtifact().getName(), batchProperty.getPropertyName()); if(list.size() > 0){ references.put(file, list); } } } }); } /** * for test purpose * @return */ public HashMap<IFile, List<NodePathTextSourceReference>> getDisplayedReferences(){ return references; } private String computeTitle() { StringBuffer result = new StringBuffer(); result.append(NLS.bind(BatchHyperlinkMessages.SHOWING_REFERENCES_FOR_BATCH_PROPERTY, batchProperty.getPropertyName())); return result.toString(); } @Override protected Control getFocusControl() { return getFilterText(); } @Override protected Control createTitleMenuArea(Composite parent) { Composite fViewMenuButtonComposite= (Composite) super.createTitleMenuArea(parent); fFilterText = createFilterText(parent); return fViewMenuButtonComposite; } @Override protected void configureShell(Shell newShell) { super.configureShell(newShell); newShell.setText(BatchHyperlinkMessages.BATCH_PROPERTY_REFERENCES); } @Override protected Control createDialogArea(Composite parent) { composite = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(2, false); layout.marginHeight = 0; layout.marginWidth = 0; layout.verticalSpacing = 0; layout.horizontalSpacing = 0; composite.setLayout(layout); composite.setLayoutData(new GridData(GridData.FILL_BOTH)); composite.setFont(parent.getFont()); setTitleText(computeTitle()); createTreeView(composite); composite.addFocusListener(new FocusListener(){ @Override public void focusGained(FocusEvent e) { } @Override public void focusLost(FocusEvent e) { close(); } }); installFilter(); return composite; } void createTreeView(Composite parent) { tree = new TreeViewer(parent, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); tree.setAutoExpandLevel(TreeViewer.ALL_LEVELS); GridData g = new GridData(GridData.FILL_BOTH); tree.getControl().setLayoutData(g); tree.setContentProvider(new TreeContent()); tree.setLabelProvider(new LabelProvider()); tree.setInput(batchProperty); patternFilter = new ReferencePatternFilter(); tree.setFilters(new ViewerFilter[]{patternFilter}); tree.addOpenListener(new IOpenListener() { @Override public void open(OpenEvent event) { ISelection s = event.getSelection(); if(!s.isEmpty() && s instanceof IStructuredSelection) { Object o = ((IStructuredSelection)s).getFirstElement(); if(o instanceof NodePathTextSourceReference) { openElement((NodePathTextSourceReference) o); close(); } } } }); tree.getTree().addMouseMoveListener(new MouseMoveListener() { @Override public void mouseMove(MouseEvent e) { ViewerCell cell = tree.getCell(new Point(e.x, e.y)); if(cell != null) { Widget w = cell.getItem(); if(w != null && w.getData() != null) { tree.setSelection(new StructuredSelection(w.getData())); } } } }); tree.getTree().addMouseListener(new MouseAdapter() { @Override public void mouseUp(MouseEvent e) { gotoSelectedElement(); } }); tree.refresh(); } protected void gotoSelectedElement() { ISelection s = tree.getSelection(); if(!s.isEmpty() && s instanceof IStructuredSelection) { Object o = ((IStructuredSelection)s).getFirstElement(); if(o instanceof NodePathTextSourceReference) { openElement((NodePathTextSourceReference) o); close(); } } } protected Text getFilterText() { return fFilterText; } protected Text createFilterText(Composite parent) { fFilterText= new Text(parent, SWT.NONE); Dialog.applyDialogFont(fFilterText); GridData data= new GridData(GridData.FILL_HORIZONTAL); data.horizontalAlignment= GridData.FILL; data.verticalAlignment= GridData.CENTER; fFilterText.setLayoutData(data); fFilterText.addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) { if (e.keyCode == 0x0D) // return gotoSelectedElement(); if (e.keyCode == SWT.ARROW_DOWN) tree.getTree().setFocus(); if (e.keyCode == SWT.ARROW_UP) tree.getTree().setFocus(); if (e.character == 0x1B) // ESC close(); } @Override public void keyReleased(KeyEvent e) { // do nothing } }); return fFilterText; } private void installFilter() { fFilterText.setText(""); //$NON-NLS-1$ fFilterText.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { //textFilter.filter(); patternFilter.setPattern(fFilterText.getText()); tree.refresh(); tree.expandAll(); } }); } @Override protected Point getDefaultSize() { return new Point(700, 300); } @Override protected Point getDefaultLocation(Point size) { Display display = Display.getCurrent(); if(display == null) { display = Display.getDefault(); } if(display.getActiveShell() == null) { return super.getDefaultLocation(size); } Rectangle b = display.getActiveShell().getBounds(); int x = b.x + (b.width - size.x) / 2; int y = b.y + (b.height - size.y) / 2; return new Point(x, y); } class ReferencePatternFilter extends PatternFilter{ protected boolean isLeafMatch(Viewer viewer, Object element){ if(element instanceof NodePathTextSourceReference){ boolean parentMatch = super.isLeafMatch(viewer, ((NodePathTextSourceReference) element).getResource()); if(parentMatch){ return true; } } return super.isLeafMatch(viewer, element); } } class TreeContent implements ITreeContentProvider { @Override public void dispose() { } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public Object[] getElements(Object inputElement) { return getChildren(inputElement); } @Override public Object[] getChildren(Object parentElement) { if(parentElement instanceof IBatchProperty){ return references.keySet().toArray(); }else if(parentElement instanceof IFile){ return references.get((IFile)parentElement).toArray(); } return null; } @Override public Object getParent(Object element) { if(element instanceof NodePathTextSourceReference){ return ((ITextSourceReference) element).getResource(); } return null; } @Override public boolean hasChildren(Object element) { if(element instanceof IBatchProperty){ return references.keySet().size() > 0; }else if(element instanceof IFile){ return references.get((IFile)element).size() > 0; } return false; } } static Color gray = new Color(null, 128, 128, 128); static Color black = Display.getDefault().getSystemColor(SWT.COLOR_INFO_FOREGROUND); static Styler FILE_NAME_STYLER = new DefaultStyler(black, true, false); static Styler PATH_STYLER = new DefaultStyler(gray, true, false); static Styler PROPERTY_PATH_STYLER = new DefaultStyler(black, false, false); private static class DefaultStyler extends Styler { private Color foreground; private boolean bold; private boolean italic; public DefaultStyler(Color foreground, boolean bold, boolean italic) { this.foreground = foreground; this.italic = italic; this.bold = bold; } @Override public void applyStyles(TextStyle textStyle) { if (foreground != null) { textStyle.foreground = foreground; } if(italic) { textStyle.font = JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT); } if(bold) { textStyle.font = JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT); } } } class LabelProvider extends StyledCellLabelProvider implements DelegatingStyledCellLabelProvider.IStyledLabelProvider, ILabelProvider { @Override public void update(ViewerCell cell) { Object element = cell.getElement(); StyledString styledString = getStyledText(element); cell.setText(styledString.getString()); cell.setStyleRanges(styledString.getStyleRanges()); cell.setImage(getImage(element)); super.update(cell); } public String getText(Object element) { return getStyledText(element).getString(); } @Override public StyledString getStyledText(Object element) { if(element instanceof IFile){ StyledString sb = new StyledString(); sb.append(((IFile)element).getName(), FILE_NAME_STYLER).append(" - "); sb.append(((IFile)element).getParent().getFullPath().toString(), PATH_STYLER); return sb; }else if(element instanceof NodePathTextSourceReference){ return getNodePath((NodePathTextSourceReference)element); } return null; } @Override public Image getImage(Object element) { if(element instanceof IFile){ return JobImages.getImage(JobImages.JOB_IMAGE); }else if(element instanceof NodePathTextSourceReference){ return JobImages.getImage(JobImages.PROPERTY_IMAGE); } return null; } } private static StyledString getNodePath(NodePathTextSourceReference element){ StyledString ss = new StyledString(); List<Tag> tags = (List<Tag>) element.getNodePath(); for(int index = tags.size()-1; index >= 0; index--){ Tag tag = tags.get(index); if(BatchConstants.TAG_JOB.equalsIgnoreCase(tag.getName())){ continue; } Map<String, String> attributes = tag.getAttributes(); String attributeValue = null; String attributeName = BatchConstants.ATTR_ID; attributeValue = attributes.get(attributeName); if(attributeValue == null){ attributeName = BatchConstants.ATTR_REF; attributeValue = attributes.get(attributeName); } ss.append("/", PROPERTY_PATH_STYLER); ss.append(tag.getName(), PROPERTY_PATH_STYLER); if(attributeValue != null){ ss.append("(", PATH_STYLER ).append(attributeName, PATH_STYLER).append("=\"", PATH_STYLER).append(attributeValue, PATH_STYLER).append("\")", PATH_STYLER); } } return ss; } private void openElement(NodePathTextSourceReference reference){ AbstractBaseHyperlink.openFileInEditor((IFile)reference.getResource()); StructuredSelectionHelper.setSelectionAndRevealInActiveEditor(new Region(reference.getStartPosition(), reference.getLength())); } }