/******************************************************************************* * Copyright (c) 2007, 2015 Intel Corporation and others. * 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: * Intel Corporation - initial API and implementation * Markus Schorn (Wind River Systems) * Serge Beauchamp (Freescale Semiconductor) - Bug 406545 *******************************************************************************/ package org.eclipse.cdt.ui.newui; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; import org.eclipse.ui.dialogs.NewFolderDialog; import org.eclipse.ui.model.WorkbenchContentProvider; import org.eclipse.ui.model.WorkbenchLabelProvider; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICExclusionPatternPathEntry; import org.eclipse.cdt.core.settings.model.ICMultiItemsHolder; import org.eclipse.cdt.core.settings.model.ICResourceDescription; import org.eclipse.cdt.ui.CDTSharedImages; import org.eclipse.cdt.internal.ui.newui.Messages; /** * CLocationTab implements common features for "Source Location" and "Output Location" * tabs in project preferences. * */ public abstract class CLocationTab extends AbstractCPropertyTab { private final Image IMG_EN = CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_CFOLDER); private final Image IMG_FI = CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_EXCLUSION_FILTER_ATTRIB); Label label; TreeViewer tree; ArrayList<_Entry> src; ICResourceDescription cfgd; ICProject cprj; class _Filter { _Entry entry; _Filter(_Entry _entry) { entry = _entry; } public IPath[] getExtPaths() { IPath[] p = null; p = entry.ent.getExclusionPatterns(); return p; } public String[] getExts() { IPath[] p = getExtPaths(); if (p == null || p.length == 0) return new String[0]; String[] s = new String[p.length]; for (int i=0; i<p.length; i++) s[i] = p[i].toOSString(); return s; } @Override public String toString() { String[] s = getExts(); if (s.length == 0) return Messages.CLocationTab_0; String x = Messages.CLocationTab_1; for (String element : s) x = x + element + Messages.CLocationTab_2; x = x.substring(0, x.length() - 2) + Messages.CLocationTab_3; return x; } } class _Entry { ICExclusionPatternPathEntry ent; _Filter[] f = new _Filter[1]; _Entry(ICExclusionPatternPathEntry _ent) { ent = _ent; f[0] = new _Filter(this); } @Override public String toString() { return getPath() == null ? EMPTY_STR : getPath().toString(); } public IPath getPath() { return ent.isValueWorkspacePath() ? ent.getFullPath() : ent.getLocation(); } } @Override public void createControls(Composite parent) { super.createControls(parent); usercomp.setLayout(new GridLayout(1, false)); label = new Label(usercomp, SWT.NONE); label.setLayoutData(new GridData(GridData.BEGINNING)); tree = new TreeViewer(usercomp); tree.getTree().setLayoutData(new GridData(GridData.FILL_BOTH)); tree.getTree().addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateButtons(); }}); initButtons(new String[] {Messages.CLocationTab_4, Messages.CLocationTab_5, Messages.CLocationTab_6, Messages.CLocationTab_7}, 150); tree.setContentProvider(new ITreeContentProvider() { @Override public Object[] getChildren(Object parentElement) { if (parentElement instanceof _Entry) return ((_Entry)parentElement).f; return null; } @Override public Object getParent(Object element) { if (element instanceof _Filter) return ((_Filter)element).entry; return null; } @Override public boolean hasChildren(Object element) { return (element instanceof _Entry); } @Override public Object[] getElements(Object inputElement) { return src.toArray(new _Entry[src.size()]); } @Override public void dispose() {} @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { }}); tree.setLabelProvider(new LabelProvider() { @Override public Image getImage(Object element) { if (element instanceof _Entry) return IMG_EN; else if (element instanceof _Filter) return IMG_FI; else return null; } }); } /** * Add, Create/Link: always enabled * Edit: enabled if 1 element selected (entry or filter) * Delete: enabled if selected element is entry */ @Override protected void updateButtons() { TreeItem[] sel = tree.getTree().getSelection(); buttonSetEnabled(2, sel.length == 1); buttonSetEnabled(3, sel.length > 0 && sel[0].getData() instanceof _Entry); } @Override public void buttonPressed(int x) { Shell shell = usercomp.getShell(); TreeItem[] sel = tree.getTree().getSelection(); switch (x) { // add case 0: String[] ss = getProjectDialog(shell); if (ss != null) { for (String element : ss) src.add(new _Entry(newEntry(new Path(element), new IPath[0], true))); saveData(); } break; // create / link case 1: NewFolderDialog d = new NewFolderDialog(shell, page.getProject()) { @Override public void create() { super.create(); handleAdvancedButtonSelect(); } }; if (d.open() == Window.OK) { IFolder f = (IFolder)d.getFirstResult(); src.add(new _Entry(newEntry(f, new IPath[0], !f.isLinked()))); saveData(); } break; // edit filter case 2: if (sel.length == 0) return; Object data = sel[0].getData(); _Entry entry = null; if (data instanceof _Entry) entry = (_Entry)data; else if (data instanceof _Filter) entry = ((_Filter)data).entry; else return; ExPatternDialog dialog = new ExPatternDialog(usercomp.getShell(), entry.ent.getExclusionPatterns(), entry.getPath(), page.getProject()); if (dialog.open() == Window.OK) { IPath[] ps = dialog.getExclusionPattern(); IPath path = entry.getPath(); boolean isWsp = entry.ent.isValueWorkspacePath(); entry.ent = newEntry(path, ps, isWsp); saveData(); } break; case 3: if (sel.length == 0) return; for (TreeItem element : sel) { if (element.getData() instanceof _Entry) src.remove(element.getData()); } saveData(); break; default: break; } } private void saveData() { ICExclusionPatternPathEntry[] p = new ICExclusionPatternPathEntry[src.size()]; Iterator<_Entry> it = src.iterator(); int i=0; while(it.hasNext()) { p[i++] = (it.next()).ent; } setEntries(cfgd, p); tree.setInput(cfgd); updateData(cfgd); if (page instanceof AbstractPage) { ICConfigurationDescription cfgDescription = cfgd.getConfiguration(); ((AbstractPage)page).cfgChanged(cfgDescription); } } @Override public void updateData(ICResourceDescription _cfgd) { if (page.isMultiCfg()) { setAllVisible(false, ""); //$NON-NLS-1$ return; } cfgd = _cfgd; IAdaptable ad = page.getElement(); if (ad instanceof ICProject) { cprj = (ICProject)ad; } IResource rc = (IResource)ad; setAllVisible(true, null); src = new ArrayList<_Entry>(); _Entry selectedSourcePath = null; for (ICExclusionPatternPathEntry e : getEntries(cfgd)) { _Entry entry = new _Entry(e); if (entry.ent.isValueWorkspacePath() && entry.ent.getFullPath().equals(rc.getFullPath())) { selectedSourcePath = entry; } src.add(entry); } tree.setInput(src); if (selectedSourcePath!=null) { ISelection selection = new StructuredSelection(new Object[] {selectedSourcePath}); tree.setSelection(selection); } updateButtons(); } @Override public boolean canSupportMultiCfg() { return false; } protected abstract ICExclusionPatternPathEntry[] getEntries(ICResourceDescription cfgd); protected abstract void setEntries (ICResourceDescription cfgd, ICExclusionPatternPathEntry[] data); protected abstract ICExclusionPatternPathEntry newEntry(IPath p, IPath[] ex, boolean workspacePath); protected abstract ICExclusionPatternPathEntry newEntry(IFolder f, IPath[] ex, boolean workspacePath); @Override protected void performApply(ICResourceDescription src, ICResourceDescription dst) { setEntries(dst, getEntries(src)); } @Override protected void performDefaults() { setEntries(cfgd, null); updateData(cfgd); } // This page can be displayed either for project or for folder @Override public boolean canBeVisible() { if (page.getResDesc() instanceof ICMultiItemsHolder) return false; // cannot work with multi cfg return page.isForProject() || page.isForFolder(); } private String[] getProjectDialog(Shell shell) { Set<IPath> set = new HashSet<IPath>(src.size()); for (_Entry e : src) set.add(e.getPath()); LocDialog dialog = new LocDialog(shell, set); dialog.setInput(page.getProject()); dialog.setTitle(WORKSPACE_DIR_DIALOG_TITLE); dialog.setMessage(WORKSPACE_DIR_DIALOG_MSG); if (dialog.open() == Window.OK) { Object[] resources = dialog.getResult(); if (resources != null) { String[] ss = new String[resources.length]; for (int i=0; i<resources.length; i++) ss[i] = ((Holder)resources[i]).getPath().toString(); return ss; } } return null; } /** * This class should hold elements for source location tree */ class Holder implements IAdaptable { private IFolder f = null; private boolean isRoot = false; private IPath p = null; Holder(IProject _p) { f = _p.getFolder(_p.getName()); isRoot = true; p = _p.getFullPath(); } Holder(IFolder _f) { f = _f; isRoot = false; p = _f.getFullPath(); } @Override public <T> T getAdapter(Class<T> adapter) { return f.getAdapter(adapter); } public boolean isRoot() { return isRoot; } public IFolder getFolder() { return f; } public IPath getPath() { return p; } private CLocationTab getOuterType() { return CLocationTab.this; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + getOuterType().hashCode(); result = prime * result + ((p == null) ? 0 : p.hashCode()); result = prime * result + (isRoot ? 1231 : 1237); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Holder other = (Holder) obj; if (!getOuterType().equals(other.getOuterType())) return false; if (isRoot != other.isRoot) return false; if (p == null) { if (other.p != null) return false; } else if (!p.equals(other.p)) return false; return true; } /** * For debugging purpose only * @see java.lang.Object#toString() */ @SuppressWarnings("nls") @Override public String toString() { return "[Holder] " + p; } } class LocDialog extends ElementTreeSelectionDialog { Set <IPath> existing; public LocDialog(Shell parent, Set <IPath> ex) { super(parent, new WorkbenchLabelProvider() { @Override protected String decorateText(String input, Object element) { if (element instanceof Holder && ((Holder)element).isRoot()) return Messages.CLocationTab_8; return super.decorateText(input, element); } }, new WorkbenchContentProvider() { @Override public Object[] getChildren(Object element) { if (element instanceof IProject) { Object[] ob1 = super.getChildren(element); Object[] ob2 = new Object[ob1.length + 1]; int cnt = 0; ob2[cnt++] = new Holder((IProject)element); for (Object ob: ob1) { if (ob instanceof IFolder) ob2[cnt++] = new Holder((IFolder)ob); } ob1 = new Object[cnt]; System.arraycopy(ob2, 0, ob1, 0, cnt); return ob1; } else if (element instanceof Holder) { Holder h = (Holder)element; if (h.isRoot()) return new Object[0]; Object[] ob1 = super.getChildren(h.getFolder()); Object[] ob2 = new Object[ob1.length]; int cnt = 0; for (Object ob: ob1) { if (ob instanceof IFolder) ob2[cnt++] = new Holder((IFolder)ob); } ob1 = new Object[cnt]; System.arraycopy(ob2, 0, ob1, 0, cnt); return ob1; } else return super.getChildren(element); } }); addFilter(new ViewerFilter () { @Override public boolean select(Viewer viewer, Object parentElement, Object element) { if (! (element instanceof Holder)) return false; if (existing == null || existing.size() == 0) return true; Holder h = (Holder)element; return (! existing.contains(h.getPath())); }}); existing = ex; } @Override protected TreeViewer createTreeViewer(Composite parent) { TreeViewer treeViewer = super.createTreeViewer(parent); // Expand the tree and select current resource if (page.getElement() instanceof IFolder) { IFolder folder = (IFolder)page.getElement(); List<Holder> list = new ArrayList<Holder>(); list.add(new Holder(folder)); for (IContainer parentFolder = folder.getParent();parentFolder instanceof IFolder;parentFolder=parentFolder.getParent()) { list.add(0,new Holder((IFolder) parentFolder)); } treeViewer.expandToLevel(new TreePath(list.toArray()), 0); setInitialSelection(new Holder(folder)); } return treeViewer; } } }