/******************************************************************************* * Copyright (c) 2009 IBM 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: * IBM Corporation - initial API and implementation * Zend Technologies *******************************************************************************/ package org.eclipse.php.internal.ui.preferences.includepath; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.*; import org.eclipse.dltk.core.IBuildpathEntry; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.internal.ui.util.CoreUtility; import org.eclipse.dltk.internal.ui.wizards.NewWizardMessages; import org.eclipse.dltk.internal.ui.wizards.buildpath.BPListElement; import org.eclipse.dltk.internal.ui.wizards.buildpath.BuildPathBasePage; import org.eclipse.dltk.internal.ui.wizards.dialogfields.ListDialogField; import org.eclipse.dltk.internal.ui.wizards.dialogfields.StringButtonDialogField; import org.eclipse.dltk.ui.DLTKPluginImages; import org.eclipse.dltk.ui.DLTKUIPlugin; import org.eclipse.dltk.ui.util.IStatusChangeListener; import org.eclipse.dltk.ui.viewsupport.ImageDisposer; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.php.internal.core.Logger; import org.eclipse.php.internal.core.PHPCorePlugin; import org.eclipse.php.internal.core.buildpath.BuildPathUtils; import org.eclipse.php.internal.core.includepath.IIncludepathListener; import org.eclipse.php.internal.core.includepath.IncludePath; import org.eclipse.php.internal.core.includepath.IncludePathManager; import org.eclipse.php.internal.ui.PHPUIMessages; import org.eclipse.php.internal.ui.PHPUiPlugin; 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.Control; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.internal.IChangeListener; import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer; /** * This class is responsible for the inner side of Include path property page. * Extends most of the dltk build path behavior with a few adaptations to the * include path needs * * @author Eden K., 2008 * */ public class PHPIncludePathsBlock extends AbstractIncludepathsBlock { /** * @author nir.c Wrapper composite, that un/register itself to any * includepath changes */ private final class IncludePathComposite extends Composite implements IIncludepathListener, IChangeListener { private IncludePathComposite(Composite parent, int style) { super(parent, style); IncludePathManager.getInstance().registerIncludepathListener(this); } @Override public void dispose() { if (fSourceContainerPage instanceof PHPIncludePathSourcePage) { PHPSourceContainerWorkbookPage page = (PHPSourceContainerWorkbookPage) fSourceContainerPage; page.unregisterAddedElementListener(this); } IncludePathManager.getInstance().unregisterIncludepathListener(this); super.dispose(); } @Override public void refresh(IProject project) { PHPIncludePathsBlock.this.updateUI(); } @Override public void update(boolean changed) { try { configureScriptProject(new NullProgressMonitor()); PHPIncludePathsBlock.this.updateUI(); } catch (OperationCanceledException e) { PHPCorePlugin.log(e); } catch (CoreException e) { PHPCorePlugin.log(e); } } } public PHPIncludePathsBlock(IRunnableContext runnableContext, IStatusChangeListener context, int pageToShow, boolean useNewPage, IWorkbenchPreferenceContainer pageContainer) { super(runnableContext, context, pageToShow, useNewPage, pageContainer); } @Override protected void initContainerElements() { BuildPathAdapter adapter = new BuildPathAdapter(); String[] buttonLabels = new String[] { NewWizardMessages.BuildPathsBlock_buildpath_up_button, NewWizardMessages.BuildPathsBlock_buildpath_down_button }; fBuildPathList = new ListDialogField(null, buttonLabels, new PHPIPListLabelProvider()); fBuildPathList.setDialogFieldListener(adapter); fBuildPathList.setLabelText(NewWizardMessages.BuildPathsBlock_buildpath_label); fBuildPathList.setUpButtonIndex(0); fBuildPathList.setDownButtonIndex(1); fBuildPathDialogField = new StringButtonDialogField(adapter); fBuildPathDialogField.setButtonLabel(NewWizardMessages.BuildPathsBlock_buildpath_button); fBuildPathDialogField.setDialogFieldListener(adapter); fBuildPathDialogField.setLabelText(NewWizardMessages.BuildPathsBlock_buildpath_label); } @Override protected IPreferenceStore getPreferenceStore() { return PHPUiPlugin.getDefault().getPreferenceStore(); } @Override protected boolean supportZips() { return true; } // -------- UI creation --------- @Override public Control createControl(Composite parent) { fSWTWidget = parent; Composite composite = new IncludePathComposite(parent, SWT.NONE); composite.setFont(parent.getFont()); GridLayout layout = new GridLayout(); layout.marginWidth = 0; layout.marginHeight = 0; layout.numColumns = 1; composite.setLayout(layout); TabFolder folder = new TabFolder(composite, SWT.NONE); folder.setLayoutData(new GridData(GridData.FILL_BOTH)); folder.setFont(composite.getFont()); TabItem item; item = new TabItem(folder, SWT.NONE); item.setText(NewWizardMessages.BuildPathsBlock_tab_source); item.setImage(DLTKPluginImages.get(DLTKPluginImages.IMG_OBJS_PACKFRAG_ROOT)); fSourceContainerPage = new PHPIncludePathSourcePage(fBuildPathList); ((PHPSourceContainerWorkbookPage) fSourceContainerPage) .registerAddedElementListener((IChangeListener) composite); item.setData(fSourceContainerPage); item.setControl(fSourceContainerPage.getControl(folder)); IWorkbench workbench = DLTKUIPlugin.getDefault().getWorkbench(); Image projectImage = workbench.getSharedImages().getImage(IDE.SharedImages.IMG_OBJ_PROJECT); fProjectsPage = new PHPProjectsWorkbookPage(fBuildPathList, fPageContainer); fProjectsPage.setTitle(PHPUIMessages.IncludePathProjectsPage_Folders_Label); item = new TabItem(folder, SWT.NONE); item.setText(NewWizardMessages.BuildPathsBlock_tab_projects); item.setImage(projectImage); item.setData(fProjectsPage); item.setControl(fProjectsPage.getControl(folder)); fLibrariesPage = new PHPLibrariesWorkbookPage(this.supportZips(), fBuildPathList, fPageContainer); fLibrariesPage.setTitle(PHPUIMessages.IncludePathLibrariesPage_Folders_Label); fLibrariesPage.setScriptProject(getScriptProject()); item = new TabItem(folder, SWT.NONE); item.setText(NewWizardMessages.BuildPathsBlock_tab_libraries); item.setImage(DLTKPluginImages.get(DLTKPluginImages.IMG_OBJS_LIBRARY)); item.setData(fLibrariesPage); item.setControl(fLibrariesPage.getControl(folder)); // a non shared image Image cpoImage = DLTKPluginImages.DESC_TOOL_BUILDPATH_ORDER.createImage(); composite.addDisposeListener(new ImageDisposer(cpoImage)); PHPBuildpathOrderingWorkbookPage ordpage = new PHPBuildpathOrderingWorkbookPage(fBuildPathList); setTitle(PHPUIMessages.IncludePathOrderPage_Folders_Label); item = new TabItem(folder, SWT.NONE); item.setText(PHPUIMessages.BuildPathsBlock_tab_order); item.setImage(cpoImage); item.setData(ordpage); item.setControl(ordpage.getControl(folder)); if (fCurrScriptProject != null) { fSourceContainerPage.init(fCurrScriptProject); fLibrariesPage.init(fCurrScriptProject); fProjectsPage.init(fCurrScriptProject); } folder.setSelection(fPageIndex); fCurrPage = (BuildPathBasePage) folder.getItem(fPageIndex).getData(); folder.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { tabChanged(e.item); } }); fTabFolder = folder; // TODO - add listener to include path manager changes // upon change call updateUI(); // and release listener on dispose Dialog.applyDialogFont(composite); return composite; } @Override protected void updateBuildPathStatus() { // disable checking for nested folders errors } @Override public void configureScriptProject(IProgressMonitor monitor) throws CoreException, OperationCanceledException { updateBuildPath(); flush(fBuildPathList.getElements(), getScriptProject(), monitor); initializeTimeStamps(); updateUI(); } /** * The purpose of this method is to adapt the build path according to the * entries added to the include path. If the user added to the include path * source folders that are not in (or contained in) the build path, he will * not get code completion and other functionality for this sources. THe * user is prompted and asked if he wants to add the relevant sources to the * build path as well see bug#255930 */ private void updateBuildPath() { PHPIncludePathSourcePage includePathSourcePage = (PHPIncludePathSourcePage) fSourceContainerPage; boolean shouldAddToBuildPath = includePathSourcePage.shouldAddToBuildPath(); if (!shouldAddToBuildPath) { return; } // get the source elements that the user added in the source tab List<BPListElement> addedElements = includePathSourcePage.getAddedElements(); List<IBuildpathEntry> buildPathEntries = new ArrayList<IBuildpathEntry>(); // in case there are any, the user is prompted with a question if (addedElements.size() > 0) { for (BPListElement listElement : addedElements) { if (!BuildPathUtils.isContainedInBuildpath(listElement.getPath(), fCurrScriptProject)) { buildPathEntries.add(listElement.getBuildpathEntry()); } } // if the user chose to, the relevant entries are added to the // buildpath try { BuildPathUtils.addEntriesToBuildPath(fCurrScriptProject, buildPathEntries); } catch (ModelException e) { Logger.logException("Failed adding entries to build path", e); //$NON-NLS-1$ } } } /* * Creates the script project and sets the configured build path and output * location. If the project already exists only build paths are updated. */ public static void flush(List buildpathEntries, IScriptProject javaProject, IProgressMonitor monitor) throws CoreException, OperationCanceledException { if (monitor == null) { monitor = new NullProgressMonitor(); } monitor.setTaskName(NewWizardMessages.BuildPathsBlock_operationdesc_Script); monitor.beginTask("", buildpathEntries.size() * 4 + 4); //$NON-NLS-1$ try { IProject project = javaProject.getProject(); monitor.worked(1); if (monitor.isCanceled()) { throw new OperationCanceledException(); } List<IBuildpathEntry> newBuildPathEntries = new ArrayList<IBuildpathEntry>(); List<IBuildpathEntry> newIncludePathEntries = new ArrayList<IBuildpathEntry>(); // go over the dialog entries. collect all of the source entries for // the include path array // and the rest for the build path array for (Iterator<IBuildpathEntry> iter = buildpathEntries.iterator(); iter.hasNext();) { BPListElement entry = (BPListElement) iter.next(); newIncludePathEntries.add(entry.getBuildpathEntry()); if (entry.getEntryKind() != IBuildpathEntry.BPE_SOURCE) { newBuildPathEntries.add(entry.getBuildpathEntry()); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=307982 // Add project in build path,press ok,then edit the // project's access rules will throw exception. BuildPathUtils.removeEntryFromBuildPath(javaProject, entry.getBuildpathEntry()); } IResource res = entry.getResource(); if (res instanceof IFolder && entry.getLinkTarget() == null && !res.exists()) { CoreUtility.createFolder((IFolder) res, true, true, new SubProgressMonitor(monitor, 1)); } else { monitor.worked(1); } } if (newBuildPathEntries.size() > 0) { // BuildPathUtils.removeEntryFromBuildPath(scriptProject, // buildpathEntry) BuildPathUtils.addEntriesToBuildPath(javaProject, newBuildPathEntries); } IncludePathManager.getInstance().addEntriesToIncludePath(project, newIncludePathEntries); } finally { monitor.done(); } } /** * Initializes the include path for the given project. Multiple calls to * init are allowed, but all existing settings will be cleared and replace * by the given or default paths. * * @param jproject * The java project to configure. Does not have to exist. * @param outputLocation * The output location to be set in the page. If * <code>null</code> is passed, jdt default settings are used, or * - if the project is an existing script project- the output * location of the existing project * @param buildpathEntries * The include path entries to be set in the page. If * <code>null</code> is passed, jdt default settings are used, or * - if the project is an existing script project - the buildpath * entries of the existing project */ @Override public void init(IScriptProject jproject, IBuildpathEntry[] buildpathEntries) { fCurrScriptProject = jproject; List<BPListElement> newBuildpath = new ArrayList<BPListElement>(); IProject project = fCurrScriptProject.getProject(); IncludePath[] includePathEntries = IncludePathManager.getInstance().getIncludePaths(project); for (IncludePath entry : includePathEntries) { Object includePathEntry = entry.getEntry(); if (includePathEntry instanceof IBuildpathEntry) { IBuildpathEntry bpEntry = (IBuildpathEntry) includePathEntry; newBuildpath.add(BPListElement.createFromExisting(bpEntry, fCurrScriptProject)); } else { IResource resource = (IResource) includePathEntry; newBuildpath.add(new BPListElement(fCurrScriptProject, IBuildpathEntry.BPE_SOURCE, resource.getFullPath(), resource, false)); } } // inits the dialog field fBuildPathDialogField.enableButton(project.exists()); fBuildPathList.setElements(newBuildpath); // fBuildPathList.setCheckedElements(newBuildpath); initializeTimeStamps(); updateUI(); } }