/*******************************************************************************
* Copyright (c) 2017 Rogue Wave Software Inc. 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:
* Rogue Wave Software Inc. - initial implementation
*******************************************************************************/
package org.eclipse.php.internal.ui.wizards.types;
import java.io.File;
import java.text.MessageFormat;
import java.util.*;
import java.util.List;
import java.util.regex.Pattern;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.preferences.DefaultScope;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.dltk.ast.Modifiers;
import org.eclipse.dltk.compiler.CharOperation;
import org.eclipse.dltk.core.*;
import org.eclipse.dltk.core.index2.search.ISearchEngine.MatchRule;
import org.eclipse.dltk.core.search.IDLTKSearchConstants;
import org.eclipse.dltk.core.search.IDLTKSearchScope;
import org.eclipse.dltk.core.search.SearchEngine;
import org.eclipse.dltk.internal.ui.wizards.TypedElementSelectionValidator;
import org.eclipse.dltk.ui.dialogs.FilteredTypesSelectionDialog;
import org.eclipse.dltk.ui.dialogs.ITypeInfoFilterExtension;
import org.eclipse.dltk.ui.dialogs.TypeSelectionExtension;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.Window;
import org.eclipse.php.core.PHPVersion;
import org.eclipse.php.core.compiler.PHPFlags;
import org.eclipse.php.core.project.ProjectOptions;
import org.eclipse.php.internal.core.PHPCorePlugin;
import org.eclipse.php.internal.core.PHPLanguageToolkit;
import org.eclipse.php.internal.core.documentModel.provisional.contenttype.ContentTypeIdForPHP;
import org.eclipse.php.internal.core.language.keywords.PHPKeywords;
import org.eclipse.php.internal.core.model.PHPModelAccess;
import org.eclipse.php.internal.ui.Logger;
import org.eclipse.php.internal.ui.PHPUiPlugin;
import org.eclipse.php.internal.ui.preferences.util.Key;
import org.eclipse.php.internal.ui.util.SWTUtil;
import org.eclipse.php.internal.ui.util.StatusInfo;
import org.eclipse.php.internal.ui.util.StatusUtil;
import org.eclipse.php.internal.ui.wizards.BasicPHPWizardPage;
import org.eclipse.php.internal.ui.wizards.fields.DialogField;
import org.eclipse.php.internal.ui.wizards.fields.IDialogFieldListener;
import org.eclipse.php.internal.ui.wizards.fields.IListAdapter;
import org.eclipse.php.internal.ui.wizards.fields.ListDialogField;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ContainerSelectionDialog;
import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.preferences.WorkingCopyManager;
import org.eclipse.ui.views.navigator.ResourceComparator;
import org.eclipse.wst.xml.core.internal.document.NodeImpl;
public abstract class NewPHPTypePage extends BasicPHPWizardPage implements IDialogFieldListener {
private static final String BIND_NAMESPACE_AND_LOCATION = "Bind namespace and location";//$NON-NLS-1$
public static final String REQUIRE_ONCE = "require_once";//$NON-NLS-1$
public static final String TODOS = "TODOs";//$NON-NLS-1$
public static final String PHP_DOC_BLOCKS = "PHPDoc Blocks";//$NON-NLS-1$
public static final String DESTRUCTOR = "Destructor";//$NON-NLS-1$
public static final String CONSTRUCTOR = "Constructor";//$NON-NLS-1$
public static final String INHERITED_ABSTRACT_METHODS = "Inherited abstract methods";//$NON-NLS-1$
private static final Pattern PHP_IDENTIFIER_PATTERN = Pattern
.compile("[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*"); //$NON-NLS-1$
protected PHPVersion phpVersion;
/**
* Constant to signal that the created type is a class.
*
*/
public static final int CLASS_TYPE = 1;
/**
* Constant to signal that the created type is a interface.
*
*/
public static final int INTERFACE_TYPE = 2;
/**
* Constant to signal that the created type is a trait.
*
*/
public static final int TRAIT_TYPE = 3;
// some validation IDs for validating specific sections within the UI
public static final int VALIDATE_SOURCE_FOLDER = 1;
protected StatusInfo sourceFolderStatus;
public static final int VALIDATE_NEW_FILE = 2;
protected StatusInfo newFileStatus;
public static final int VALIDATE_EXISTING_FILE = 3;
protected StatusInfo existingFileStatus;
public static final int VALIDATE_ELEMENT_NAME = 4;
protected StatusInfo elementNameStatus;
public static final int VALIDATE_NAMESPACE = 5;
protected StatusInfo namespaceStatus;
protected StatusInfo interfacesStatus;
protected StatusInfo traitsStatus;
private String sourceFolder = ""; //$NON-NLS-1$
protected Text sourceText;
protected Text newFileText;
protected Text existingFileText;
protected Text elementName;
protected Text namespaceText;
protected Composite modifiers;
protected ListDialogField<IType> fSuperInterfacesDialogField;
private ListDialogField<IType> fTraitsDialogField;
private Button existingFileBtn;
private Button firstBlockBtn;
private Button browseSourceBtn;
private Button browseExistingFile;
private Composite checkBoxesCreationComp;
protected int fTypeKind;
private boolean isInExistingPHPFile = false;
private Composite injectLocation;
private String existingFileName = ""; //$NON-NLS-1$
protected IType openByInterface = null;
protected IType openByTrait = null;
private Button addInterfacesBtn;
private Button addTraitsBtn;
private String initialElementName;
private IPreferenceStore preferenceStore;
private int removedSegmentNumber;
private IFile existingFile;
private Button namespaceCheckbox;
public NewPHPTypePage(String pageName) {
super(pageName);
updateStatus(new StatusInfo());
sourceFolderStatus = new StatusInfo();
newFileStatus = new StatusInfo();
existingFileStatus = new StatusInfo();
elementNameStatus = new StatusInfo();
namespaceStatus = new StatusInfo();
}
protected String getSuperInterfacesLabel() {
if (fTypeKind != INTERFACE_TYPE) {
return Messages.NewPHPTypePage_interfaces;
}
return Messages.NewPHPTypePage_extendedInterfaces;
}
// the location of where to inject the new element's code
protected void createLocationSection(Composite parent) {
final Composite container = new Composite(parent, SWT.NULL);
container.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
final GridLayout layout = new GridLayout();
layout.numColumns = 3;
layout.marginHeight = 0;
layout.marginWidth = 0;
container.setLayout(layout);
Label label = new Label(container, SWT.NULL);
label.setText(Messages.NewPHPTypePage_sourceFolder);
sourceText = new Text(container, SWT.BORDER | SWT.SINGLE);
sourceText.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
sourceText.setEditable(false);
// init PHPVersion
handlePHPVersion();
sourceText.setText(sourceFolder);
handlePHPVersion();
sourceText.addModifyListener(e -> {
Text textSource = (Text) e.getSource();
sourceFolder = textSource.getText();
handlePHPVersion();
validatePageValues(VALIDATE_SOURCE_FOLDER);
validatePageValues(VALIDATE_NEW_FILE);
updateDisabled();
});
browseSourceBtn = new Button(container, SWT.PUSH);
browseSourceBtn.setText(Messages.NewPHPTypePage_browse);
GridData gd = new GridData();
gd.verticalAlignment = GridData.BEGINNING;
gd.widthHint = SWTUtil.getButtonWidthHint(browseSourceBtn);
browseSourceBtn.setLayoutData(gd);
browseSourceBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
chooseNewSourceFolder();
String sourcePath = sourceText.getText();
if (sourcePath.length() > 0) {
handlePHPVersion();
}
validatePageValues(VALIDATE_SOURCE_FOLDER);
setDefaultNamespace();
}
});
final Button newFileBtn = new Button(container, SWT.RADIO);
newFileBtn.setText(Messages.NewPHPTypePage_createNewFile);
newFileBtn.setSelection(!isInExistingPHPFile);
newFileBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (isInExistingPHPFile) {
isInExistingPHPFile = false;
if (TypeWizardConstants.NEW_FILE_DEFAULT_NAME.equals(newFileText.getText())
|| newFileText.getText().trim().length() == 0) {
updateNewFilename();
}
updateDisabled();
setDefaultNamespace();
validatePageValues(VALIDATE_NEW_FILE);
// fix bug #14458 - Validate existing file
// In case of switch the radio buttons from 'Add existing
// file' to 'Create new file' erase the error message.
validatePageValues(VALIDATE_EXISTING_FILE);
}
}
});
newFileText = new Text(container, SWT.BORDER | SWT.SINGLE);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.widthHint = 300;
newFileText.setLayoutData(gd);
newFileText.addModifyListener(e -> validatePageValues(VALIDATE_NEW_FILE));
new Label(container, SWT.NULL);
existingFileBtn = new Button(container, SWT.RADIO);
existingFileBtn.setText(Messages.NewPHPTypePage_addInExistingFile);
existingFileBtn.setSelection(isInExistingPHPFile);
existingFileBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (!isInExistingPHPFile) {
isInExistingPHPFile = true;
if (existingFile != null) {
sourceFolder = existingFile.getParent().getFullPath().toOSString();
sourceText.setText(sourceFolder);
}
updateDisabled();
setDefaultNamespace();
validatePageValues(VALIDATE_NEW_FILE);
validatePageValues(VALIDATE_EXISTING_FILE);
validatePageValues(VALIDATE_SOURCE_FOLDER);
}
}
});
existingFileText = new Text(container, SWT.BORDER | SWT.SINGLE);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.widthHint = 300;
existingFileText.setLayoutData(gd);
existingFileText.setText(existingFileName);
existingFileText.addModifyListener(e -> {
validatePageValues(VALIDATE_EXISTING_FILE);
updateDisabled();
setDefaultNamespace();
});
gd = new GridData(GridData.FILL_HORIZONTAL);
browseExistingFile = new Button(container, SWT.PUSH);
browseExistingFile.setText(Messages.NewPHPTypePage_browse);
gd = new GridData();
gd.verticalAlignment = GridData.BEGINNING;
gd.widthHint = SWTUtil.getButtonWidthHint(browseExistingFile);
browseExistingFile.setLayoutData(gd);
browseExistingFile.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
openPHPFileDialog();
validatePageValues(VALIDATE_EXISTING_FILE);
validatePageValues(VALIDATE_SOURCE_FOLDER);
updateDisabled();
setDefaultNamespace();
}
});
// the radio buttons
new Label(container, SWT.NULL);
injectLocation = new Composite(container, SWT.NULL);
GridLayout injectLayout = new GridLayout(2, true);
injectLocation.setLayout(injectLayout);
injectLayout.marginHeight = 0;
injectLayout.marginWidth = 0;
firstBlockBtn = new Button(injectLocation, SWT.RADIO);
firstBlockBtn.setText(Messages.NewPHPTypePage_firstPHPBlock);
firstBlockBtn.setSelection(true);
Button newPHPBlockBtn = new Button(injectLocation, SWT.RADIO);
newPHPBlockBtn.setText(Messages.NewPHPTypePage_newPHPBlock);
new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL)
.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 3, 1));
}
protected void handlePHPVersion() {
String sourcePath = sourceText.getText();
if (sourcePath.length() > 0) {
if (isValidSourcePath(sourcePath)) {
IProject currentProject = getCurrentProject();
if (currentProject != null && !currentProject.isAccessible()) {
phpVersion = null;
} else {
phpVersion = ProjectOptions.getPHPVersion(currentProject);
}
} else {
phpVersion = null;
}
}
// use workspace default php version if it is null
if (phpVersion == null) {
phpVersion = ProjectOptions.getDefaultPHPVersion();
}
}
protected IScriptProject getProject() {
String sourcePath = sourceText.getText();
if (sourcePath.length() > 0 && isValidSourcePath(sourcePath)) {
IProject currProject = getCurrentProject();
if (currProject != null) {
return DLTKCore.create(currProject);
}
}
return null;
}
/**
* @return the project name the first section of the path
*/
protected String getProjectName(String sourcePath) {
IPath path = new Path(sourcePath);
if (path.segmentCount() > 1) {
sourcePath = path.segment(0);
}
return sourcePath;
}
/**
* Handles source path validation and when '\' is entered
*
* @param sourcePath
* @return
*/
protected boolean isValidSourcePath(String path) {
final IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IPath containerPath = new Path(path.replace('\\', IPath.SEPARATOR));
containerPath = new Path(containerPath.segment(0));
IResource resource = workspaceRoot.findMember(containerPath);
return resource != null;
}
/**
* Element name section
*
* @param container
* @param type
*/
protected void addElementNameText(Composite container, String type) {
GridData gd = new GridData();
Label elementNameLabel = new Label(container, SWT.NULL);
elementNameLabel.setText(type + Messages.NewPHPTypePage_name);
elementNameLabel.setLayoutData(gd);
elementName = new Text(container, SWT.BORDER | SWT.SINGLE);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
elementName.setLayoutData(gd);
elementName.setFocus();
elementName.addModifyListener(e -> {
validatePageValues(VALIDATE_ELEMENT_NAME);
updateNewFilename();
});
if (initialElementName != null) {
elementName.setText(initialElementName);
}
}
protected void addNamespaceText(Composite container) {
GridData gd = new GridData();
new Label(container, SWT.NULL);
namespaceCheckbox = new Button(container, SWT.CHECK);
namespaceCheckbox.setText(BIND_NAMESPACE_AND_LOCATION);
namespaceCheckbox.setSelection(true);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
namespaceCheckbox.setLayoutData(gd);
namespaceCheckbox.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
changeSourceFolder();
}
});
Label elementNameLabel = new Label(container, SWT.NULL);
elementNameLabel.setText(Messages.NewPHPTypePage_0);
elementNameLabel.setLayoutData(new GridData());
namespaceText = new Text(container, SWT.BORDER | SWT.SINGLE);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
namespaceText.setLayoutData(gd);
namespaceText.addModifyListener(e -> changeSourceFolder());
setDefaultNamespace();
}
private void changeSourceFolder() {
sourceText.setEditable(!namespaceCheckbox.getSelection());
if (!existingFileBtn.getSelection() && namespaceCheckbox.getSelection()) {
String sourceFolder = getSourceText();
IPath sourcePath = new Path(sourceFolder);
sourcePath = sourcePath.removeLastSegments(sourcePath.segmentCount() - removedSegmentNumber);
String[] segments = namespaceText.getText().split("\\\\");//$NON-NLS-1$
for (String segment : segments) {
sourcePath = sourcePath.append(segment);
}
sourceText.setText(sourcePath.toOSString());
}
validatePageValues(VALIDATE_NAMESPACE);
}
protected void setDefaultNamespace() {
if (namespaceText == null) {
return;
}
IFile existingFile = getExisitngFile();
String sourceFolder = getSourceText();
if (!sourceFolder.isEmpty()) {
IPath sourcePath = new Path(sourceFolder);
removedSegmentNumber = firstSegmentsToRemoveForNamespace(sourcePath);
}
if (existingFileBtn.getSelection()) {
if (existingFile != null) {
String defaultNamespace = getLastNamespace();
if (defaultNamespace != null) {
namespaceText.setText(defaultNamespace);
}
}
} else {
if (!sourceFolder.isEmpty()) {
IPath sourcePath = new Path(sourceFolder);
sourcePath = sourcePath.removeFirstSegments(removedSegmentNumber);
if (sourcePath.segmentCount() > 0) {
String defaultNamespace = sourcePath.toString().replace("/", //$NON-NLS-1$
"\\");//$NON-NLS-1$
if (defaultNamespace.endsWith("\\")) {//$NON-NLS-1$
defaultNamespace = defaultNamespace.substring(0, defaultNamespace.length() - 1);
}
namespaceText.setText(defaultNamespace);
} else {
namespaceText.setText("");//$NON-NLS-1$
}
}
}
}
private int firstSegmentsToRemoveForNamespace(IPath sourcePath) {
try {
for (IProjectFragment projectFragment : getProject().getProjectFragments()) {
int matching = projectFragment.getPath().matchingFirstSegments(sourcePath);
if (matching > 1) {
return matching;
}
}
} catch (ModelException e) {
PHPUiPlugin.log(e);
}
return 1;
}
/**
* Modifiers section
*
* @param container
* @param modifiersNames
*/
protected void addElementModifiers(Composite container, String[] modifiersNames) {
Label modifiersLabel = new Label(container, SWT.NULL);
modifiersLabel.setText(Messages.NewPHPTypePage_modifiers);
modifiers = new Composite(container, SWT.NONE);
int len = modifiersNames.length;
GridLayout layout = new GridLayout();
modifiers.setLayout(layout);
layout.numColumns = len;
layout.makeColumnsEqualWidth = true;
layout.marginHeight = 0;
layout.marginWidth = 0;
for (int i = 0; i < modifiersNames.length; i++) {
// fixed bug 14450 - change the modifier from checkboxes to radio
// buttons
Button check = new Button(modifiers, SWT.RADIO);
check.setText(modifiersNames[i]);
if (i == 0) {
check.setSelection(true);
}
}
new Label(container, SWT.NULL);
}
/**
* SuperInterfaces Control
*
* @param parent
*/
protected void createSuperInterfacesControls(Composite parent) {
final String INTERFACE = "interface"; //$NON-NLS-1$
Control[] controls = fSuperInterfacesDialogField.doFillIntoGrid(parent, 3);
GridData gd = new GridData(GridData.FILL_BOTH);
gd.grabExcessHorizontalSpace = true;
controls[1].setLayoutData(gd);
final TableViewer tableViewer = fSuperInterfacesDialogField.getTableViewer();
tableViewer.setColumnProperties(new String[] { INTERFACE });
tableViewer.getTable().addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent event) {
if (event.keyCode == SWT.F2 && event.stateMask == 0) {
ISelection selection = tableViewer.getSelection();
if (!(selection instanceof IStructuredSelection))
return;
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
tableViewer.editElement(structuredSelection.getFirstElement(), 0);
}
}
});
gd = (GridData) fSuperInterfacesDialogField.getListControl(null).getLayoutData();
if (fTypeKind == CLASS_TYPE) {
gd.heightHint = convertHeightInCharsToPixels(3);
} else {
gd.heightHint = convertHeightInCharsToPixels(6);
}
gd.grabExcessVerticalSpace = true;
gd.widthHint = getMaxFieldWidth();
addInterfacesBtn = (Button) fSuperInterfacesDialogField.getButtonBox(parent).getChildren()[0];
addInterfacesBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Object result = chooseInterfaces();
if (result != null && result instanceof IType) {
fSuperInterfacesDialogField.addElement((IType) result);
}
fSuperInterfacesDialogField.refresh();
validateInterfaces(getProject());
}
});
}
/**
* Traits Control
*
* @param parent
*/
protected void createTraitsControls(Composite parent) {
final String INTERFACE = "trait"; //$NON-NLS-1$
Control[] controls = fTraitsDialogField.doFillIntoGrid(parent, 3);
GridData gd = new GridData(GridData.FILL_BOTH);
gd.grabExcessHorizontalSpace = true;
controls[1].setLayoutData(gd);
final TableViewer tableViewer = fTraitsDialogField.getTableViewer();
tableViewer.setColumnProperties(new String[] { INTERFACE });
tableViewer.getTable().addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent event) {
if (event.keyCode == SWT.F2 && event.stateMask == 0) {
ISelection selection = tableViewer.getSelection();
if (!(selection instanceof IStructuredSelection))
return;
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
tableViewer.editElement(structuredSelection.getFirstElement(), 0);
}
}
});
gd = (GridData) fTraitsDialogField.getListControl(null).getLayoutData();
if (fTypeKind == CLASS_TYPE) {
gd.heightHint = convertHeightInCharsToPixels(3);
} else {
gd.heightHint = convertHeightInCharsToPixels(6);
}
gd.grabExcessVerticalSpace = true;
gd.widthHint = getMaxFieldWidth();
addTraitsBtn = (Button) fTraitsDialogField.getButtonBox(parent).getChildren()[0];
addTraitsBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Object result = chooseTraits();
if (result != null && result instanceof IType) {
fTraitsDialogField.addElement((IType) result);
}
fTraitsDialogField.refresh();
validateTraits(getProject());
}
});
}
protected int getMaxFieldWidth() {
return convertWidthInCharsToPixels(40);
}
/**
* Returns the name of the new PHP file to create. Note: Use this property
* carefully since it can contain a non EMPTY/NULL value even when the user
* request to create the PHP element in an EXISTING PHP file.
*/
public String getNewFileName() {
return newFileText.getText();
}
public String getNamespace() {
if (namespaceText == null) {
return "";//$NON-NLS-1$
}
if (isInFirstPHPBlock()) {
String lastNamespace = getLastNamespace();
if (lastNamespace != null) {
if (!lastNamespace.equals(namespaceText.getText())) {
return namespaceText.getText();
} else {
return ""; //$NON-NLS-1$
}
}
}
return namespaceText.getText();
}
public String getRealNamespace() {
if (namespaceText == null) {
return "";//$NON-NLS-1$
}
return namespaceText.getText();
}
public String getExistingFileName() {
return existingFileText.getText();
}
/**
* If the PHP element is about to be inserted in an existing file, this will
* return the IFile object of the existing file. Note: Use this property
* carefully since it can contain a non EMPTY/NULL value even when the user
* request to create the PHP element in a NEW PHP file.
*/
public IFile getExisitngFile() {
String sourceText = getSourceText();
String existingFileName = getExistingFileName();
if (existingFileName == null || existingFileName.isEmpty()) {
return null;
}
Path p = new Path(sourceText + File.separatorChar + existingFileName);
IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
return wsRoot.getFile(p);
}
/**
* Denotes whether the new PHP element is inserted in an existing PHP file
* (if true) or in a new php file (if false).
*/
public boolean isInExistingPHPFile() {
return existingFileBtn.getSelection();
}
/**
* Denotes whether the created element will be inserted in the 1st block of
* the existing PHP file , OR (if false) as a new PHP block
*/
public boolean isInFirstPHPBlock() {
return firstBlockBtn.getSelection();
}
/**
* The name of the PHP element
*/
public String getElementName() {
return elementName.getText();
}
/**
* Set the PHP element name
*/
public void setElementName(String elementName) {
this.initialElementName = elementName;
}
/**
* Returns a HashMap that represents the state of modifiers for the PHP
* element. Key - the string name of the modifier. Value - a Boolean object
* , whether the modifier is selected or not.
*/
public Map<String, Boolean> getModifiers() {
if (modifiers == null) {
return null;
}
HashMap<String, Boolean> result = new HashMap<>();
Button[] modBtns = (Button[]) modifiers.getChildren();
if (modBtns == null || modBtns.length == 0) {
return null;
}
for (Button element : modBtns) {
result.put(element.getText(), element.getSelection());
}
return result;
}
public List<IType> getInterfaces() {
return fSuperInterfacesDialogField.getElements();
}
public List<IType> getTraits() {
return fTraitsDialogField.getElements();
}
/**
* This will add a Checboxes composite with the given checkboxes names.
*
* @param elementSection
* @param checkBoxes
* @return
*/
protected Composite addCheckBoxesInElementSection(Composite elementSection, String[] checkBoxes) {
new Label(elementSection, SWT.NULL);
Composite checkBoxesContainer = new Composite(elementSection, SWT.NULL);
GridLayout layout = new GridLayout(1, true);
layout.marginHeight = 0;
layout.marginWidth = 0;
checkBoxesContainer.setLayout(layout);
for (String element : checkBoxes) {
Button button = new Button(checkBoxesContainer, SWT.CHECK);
button.setText(element);
}
return checkBoxesContainer;
}
/**
* This will add a Comment creation section with the given checkboxes names.
*
* @param elementSection
* @param checkBoxes
*/
protected void addCheckboxesCreation(Composite elementSection, String[] checkBoxes) {
GridData gd = new GridData();
gd.verticalAlignment = GridData.BEGINNING;
Label whichMethods = new Label(elementSection, SWT.NULL);
whichMethods.setText(Messages.NewPHPTypePage_checkboxesToCreate);
whichMethods.setLayoutData(gd);
checkBoxesCreationComp = new Composite(elementSection, SWT.NULL);
GridLayout layout = new GridLayout(3, true);
layout.marginHeight = 3;
layout.marginWidth = 0;
checkBoxesCreationComp.setLayout(layout);
for (String element : checkBoxes) {
if (element != null) {
Button button = new Button(checkBoxesCreationComp, SWT.CHECK);
button.setText(element);
} else {
new Label(checkBoxesCreationComp, SWT.NULL);
}
}
}
public boolean isCheckboxCreationChecked(String name) {
Control[] btns = checkBoxesCreationComp.getChildren();
for (Control control : btns) {
if (control instanceof Button) {
Button button = (Button) control;
if (button.getText().equals(name)) {
return button.getSelection();
}
}
}
return false;
}
/**
* Initializes the source folder field with a valid root. The root is
* computed from the given PHPlement.
*
* @param elem
* the PHP Element used to compute the initial root used as the
* source folder
*/
protected void initContainerPage(final IModelElement elem) {
IContainer initRoot = null;
if (elem != null) {
final IResource resource = elem.getResource();
if (resource != null) {
initRoot = resource.getParent();
} else {
IScriptProject sp = (IScriptProject) elem.getAncestor(IModelElement.SCRIPT_PROJECT);
if (sp != null) {
initRoot = sp.getProject();
}
}
}
setContainer(initRoot);
}
public void setContainer(final IContainer root) {
final String str = root == null ? "" : root.getFullPath().toOSString(); //$NON-NLS-1$
sourceFolder = str;
}
/**
* Initialized the page with the current selection
*
* @param selection
* The selection
*/
public Object init(final IStructuredSelection selection) {
final IModelElement element;
final IContainer container;
final Object result;
if ((element = getInitialPHPElement(selection)) != null) {
initContainerPage(element);
result = element;
} else if ((container = getInitialContainer(selection)) != null) {
setContainer(container);
result = container;
} else {
result = null;
}
return result;
}
protected void initValues() {
validatePageValues(VALIDATE_SOURCE_FOLDER);
if (!isInExistingPHPFile) {
existingFileText.setEnabled(false);
browseExistingFile.setEnabled(false);
Control[] buttons = injectLocation.getChildren();
for (Control element : buttons) {
element.setEnabled(false);
}
if (namespaceText != null) {
namespaceText.setEnabled(true);
}
} else {
newFileText.setEnabled(false);
sourceText.setEnabled(false);
browseSourceBtn.setEnabled(false);
if (namespaceText != null) {
namespaceText.setEnabled(isNamespaceEnabled());
}
}
if (!isInExistingPHPFile) {
validatePageValues(VALIDATE_NEW_FILE);
}
validatePageValues(VALIDATE_ELEMENT_NAME);
// add interface
if (openByInterface != null) {
fSuperInterfacesDialogField.addElement(openByInterface);
}
if (openByTrait != null) {
fTraitsDialogField.addElement(openByTrait);
}
initGeneratedGroupValues();
changeButtonEnableStatus();
}
protected void initGeneratedGroupValues() {
preferenceStore = PHPUiPlugin.getDefault().getPreferenceStore();
Button[] checkboxes = getGeneratedGroupCheckboxes();
for (Button button : checkboxes) {
initSelectionStatus(button);
}
initSelectionStatus(namespaceCheckbox);
}
private void initSelectionStatus(Button button) {
if (button == null) {
return;
}
String lastCheckboxValue = preferenceStore.getString(getPreferencePrefix() + button.getText());
if (lastCheckboxValue != null && lastCheckboxValue.trim().length() > 0) {
button.setSelection(lastCheckboxValue.equals("1"));//$NON-NLS-1$
} else if (button.getText().equals(INHERITED_ABSTRACT_METHODS)
|| button.getText().equals(BIND_NAMESPACE_AND_LOCATION)) {
preferenceStore.setValue(getPreferencePrefix() + button.getText(), "1");//$NON-NLS-1$
button.setSelection(true);
}
}
public void saveGeneratedGroupValues() {
Button[] checkboxes = getGeneratedGroupCheckboxes();
for (Button button : checkboxes) {
preferenceStore.setValue(getPreferencePrefix() + button.getText(), button.getSelection() ? "1" : "0");//$NON-NLS-1$ //$NON-NLS-2$
}
if (namespaceCheckbox != null) {
preferenceStore.setValue(getPreferencePrefix() + namespaceCheckbox.getText(),
namespaceCheckbox.getSelection() ? "1" : "0");//$NON-NLS-1$ //$NON-NLS-2$
}
}
protected Button[] getGeneratedGroupCheckboxes() {
List<Button> list = new ArrayList<>();
Control[] btns = null;
if (checkBoxesCreationComp != null) {
btns = checkBoxesCreationComp.getChildren();
for (Control control : btns) {
if (control instanceof Button) {
list.add((Button) control);
}
}
}
return list.toArray(new Button[list.size()]);
}
protected String getPreferencePrefix() {
return ""; //$NON-NLS-1$
}
protected void updateDisabled() {
// new file
if (!isInExistingPHPFile) {
existingFileText.setEnabled(false);
browseExistingFile.setEnabled(false);
Control[] buttons = injectLocation.getChildren();
for (Control element : buttons) {
element.setEnabled(false);
}
newFileText.setEnabled(true);
sourceText.setEnabled(true);
browseSourceBtn.setEnabled(true);
if (namespaceText != null) {
namespaceText.setEnabled(true);
}
}
// existing file
else {
newFileText.setEnabled(false);
sourceText.setEnabled(false);
browseSourceBtn.setEnabled(false);
existingFileText.setEnabled(true);
browseExistingFile.setEnabled(true);
Control[] buttons = injectLocation.getChildren();
for (Control element : buttons) {
element.setEnabled(true);
}
if (namespaceText != null) {
namespaceText.setEnabled(isNamespaceEnabled());
}
}
}
protected boolean isNamespaceEnabled() {
ISourceModule existingPHPFile = DLTKCore.createSourceModuleFrom(getExisitngFile());
if (existingPHPFile != null && existingPHPFile.exists()) {
try {
IModelElement[] rootElements = existingPHPFile.getChildren();
if (rootElements.length > 0 && rootElements[0] instanceof IType) {
IType firstElement = (IType) rootElements[0];
if (PHPFlags.isNamespace(firstElement.getFlags())) {
return true;
}
}
} catch (ModelException e) {
PHPUiPlugin.log(e);
}
}
return false;
}
protected String getLastNamespace() {
ISourceModule existingPHPFile = DLTKCore.createSourceModuleFrom(getExisitngFile());
if (existingPHPFile != null && existingPHPFile.exists()) {
try {
IModelElement[] rootElements = existingPHPFile.getChildren();
for (int i = rootElements.length - 1; i >= 0; i--) {
if (rootElements[i] instanceof IType) {
IType firstElement = (IType) rootElements[i];
if (PHPFlags.isNamespace(firstElement.getFlags())) {
return firstElement.getFullyQualifiedName();
}
}
}
return "";//$NON-NLS-1$
} catch (ModelException e) {
// means that there where a problem with getting a model
// do not log and just return null
return null;
}
} else {
return null;
}
}
protected void validatePageValues(int validationCode) {
switch (validationCode) {
case VALIDATE_ELEMENT_NAME:
elementNameStatus = new StatusInfo();
if (getElementName() == null || getElementName().length() == 0) {
String message = Messages.NewPHPTypePage_nameMustNotBeEmpty;
switch (fTypeKind) {
case CLASS_TYPE:
message = Messages.NewPHPTypePage_class + message;
break;
case INTERFACE_TYPE:
message = Messages.NewPHPTypePage_interface + message;
break;
case TRAIT_TYPE:
message = Messages.NewPHPTypePage_trait + message;
break;
}
elementNameStatus.setError(message);
} else if (isInExistingPHPFile()) {
Path p = new Path(getSourceText() + File.separatorChar + getExistingFileName());
IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
IFile file = wsRoot.getFile(p);
ISourceModule sourceModule = DLTKCore.createSourceModuleFrom(file);
if (sourceModule != null && sourceModule.exists()) {
IType[] types = null;
try {
types = sourceModule.getTypes();
} catch (ModelException e) {
Logger.logException(e);
}
if (types != null) {
// check if the new class/interface already exists in a
// current file
for (IType type : types) {
if (type.getElementName().equalsIgnoreCase(getElementName())) {
if (fTypeKind == CLASS_TYPE && !PHPFlags.isClass(type.getElementType())) {
elementNameStatus.setError(Messages.NewPHPTypePage_class + getElementName()
+ Messages.NewPHPTypePage_alreadyExistsInFile + existingFileName);
break;
} else if (fTypeKind == INTERFACE_TYPE && PHPFlags.isInterface(type.getElementType())) {
elementNameStatus.setError(Messages.NewPHPTypePage_interface + getElementName()
+ Messages.NewPHPTypePage_alreadyExistsInFile);
break;
} else if (fTypeKind == TRAIT_TYPE && PHPFlags.isInterface(type.getElementType())) {
elementNameStatus.setError(Messages.NewPHPTypePage_trait + getElementName()
+ Messages.NewPHPTypePage_alreadyExistsInFile);
break;
}
}
}
} // do nothing here, no elements exists in the file
}
}
// fix bug 14446 - add PHP identifier validation
if (getProject() != null && !isValidPHPIdentifier(getElementName())) {
String message = Messages.NewPHPTypePage_InvalidPhp;
String nameLabel = Messages.NewPHPTypePage_InvalidPhpName;
switch (fTypeKind) {
case CLASS_TYPE:
message = message + Messages.NewPHPTypePage_class + nameLabel;
break;
case INTERFACE_TYPE:
message = message + Messages.NewPHPTypePage_interface + nameLabel;
break;
case TRAIT_TYPE:
message = message + Messages.NewPHPTypePage_trait + nameLabel;
break;
}
elementNameStatus.setError(message);
}
updateStatus(findMostSevereStatus());
break;
case VALIDATE_SOURCE_FOLDER:
// since source folder is a critical location (PHP model)
// we should check how it affects the wizard pages
sourceFolderChanged();
break;
case VALIDATE_EXISTING_FILE:
existingFileStatus = new StatusInfo();
if (isInExistingPHPFile()) {
if (existingFileText.getText().length() == 0) {
existingFileStatus.setError(Messages.NewPHPTypePage_existingFileMustNotBeEmpty);
} else if (!isPathExist(sourceText.getText() + File.separatorChar + existingFileText.getText())) {
existingFileStatus.setError(Messages.NewPHPTypePage_targetPHPFile + existingFileText.getText()
+ Messages.NewPHPTypePage_doesNotExist);
} else if (!isPHPSuffix(existingFileText.getText())) {
existingFileStatus.setError(Messages.NewPHPTypePage_phpFile + existingFileText.getText()
+ Messages.NewPHPTypePage_notPhpExtention);
}
}
updateStatus(findMostSevereStatus());
break;
case VALIDATE_NEW_FILE:
newFileStatus = new StatusInfo();
if (!isInExistingPHPFile()) {
String fileName = newFileText.getText();
if (fileName.length() == 0) {
newFileStatus.setError(Messages.NewPHPTypePage_fileMustnotBeEmpty);
}
else if (isPathExist(sourceText.getText() + File.separatorChar + fileName)) {
newFileStatus.setError(
Messages.NewPHPTypePage_phpFile + fileName + Messages.NewPHPTypePage_alreadyExists);
} else if (!isPHPSuffix(fileName)) {
newFileStatus.setError(
Messages.NewPHPTypePage_phpFile + fileName + Messages.NewPHPTypePage_notPhpExtention);
} else if (!isValidFileName(fileName)) {
newFileStatus.setError(Messages.NewPHPTypePage_phpFile
+ MessageFormat.format(Messages.NewPHPTypePage_filename_not_valid, fileName));
}
}
updateStatus(findMostSevereStatus());
break;
case VALIDATE_NAMESPACE:
namespaceStatus = new StatusInfo();
String namespace = getNamespace();
if (namespace != null && !namespace.isEmpty()) {
int separator = namespace.indexOf('/', 0);
if (separator != -1) {
namespaceStatus.setError(Messages.NewPHPTypePage_invalidSeparator);
} else {
if (namespace.endsWith("\\")) {//$NON-NLS-1$
namespaceStatus.setError(Messages.NewPHPTypePage_emptySublevel);
} else {
String[] segments = namespace.split("\\\\");//$NON-NLS-1$
if (segments.length == 1 && !isValidPHPIdentifier(namespace.trim())) {
namespaceStatus.setError(Messages.NewPHPTypePage_invalidNamespaceName);
} else {
for (String segment : segments) {
if (segment.isEmpty()) {
namespaceStatus.setError(Messages.NewPHPTypePage_emptySublevel);
} else {
try {
Integer.parseInt(segment);
namespaceStatus.setError(Messages.NewPHPTypePage_invalidSublevel);
} catch (NumberFormatException e) {
// valid segment
}
}
}
}
}
}
}
updateStatus(findMostSevereStatus());
break;
}
String sourcePathStr = getProjectName(getSourceText());
if (sourcePathStr == null || sourcePathStr.length() == 0) {
return;
}
Path projPath = new Path(sourcePathStr);
if (projPath.segmentCount() == 1) {
IProject currentProject = getCurrentProject();
if (currentProject != null && currentProject.exists()) {
IScriptProject model = DLTKCore.create(currentProject);
if (getInterfaces().size() > 0) {
validateInterfaces(model);
}
if (getTraits().size() > 0) {
validateTraits(model);
}
}
}
}
private boolean isValidFileName(String fileName) {
IStatus status = ResourcesPlugin.getWorkspace().validateName(new String(fileName), IResource.FILE);
if (!status.isOK()) {
return false;
}
String trimedString = fileName.trim();
char[] scannedID = trimedString.toCharArray();
if (CharOperation.contains('$', scannedID)) {
return false;
}
if (CharOperation.startsWith(scannedID, new char[] { '.' })) {
return false;
}
return true;
}
// when changing the source folder, we also change the available PHP model.
// Therfore we must validate that all the interfaces that we already
// selected exist in
// the current project/source folder
protected void validateInterfaces(IScriptProject model) {
interfacesStatus = new StatusInfo();
Iterator<IType> iter = getInterfaces().iterator();
while (iter.hasNext()) {
interfacesStatus = new StatusInfo();
IType interfaceObj = (IType) iter.next();
String interfaceName = interfaceObj.getElementName();
IDLTKSearchScope scope = SearchEngine.createSearchScope(getProject());
IType[] classes = PHPModelAccess.getDefault().findTypes(interfaceName, MatchRule.EXACT,
Modifiers.AccInterface, 0, scope, new NullProgressMonitor());
// could be null coming from a non PHP project when the user
// changes source folder manually by typing a location to a Java
// project for example..
if (classes == null || classes.length == 0) {
interfacesStatus.setError(Messages.NewPHPTypePage_interface + interfaceName
+ Messages.NewPHPTypePage_doesnotExistInProject);
updateStatus(findMostSevereStatus());
return;
}
boolean foundSiblings = false;
for (IType element : classes) {
// check if php file name equals
if (element.getPath().toOSString().equals(interfaceObj.getPath().toOSString())) {
interfaceObj = element;
foundSiblings = true;
break;
}
}
// not found exact file but same interface name...
if (!foundSiblings) {
interfacesStatus.setWarning(Messages.NewPHPClassPage_interface + interfaceName);
updateStatus(findMostSevereStatus());
return;
}
// check if the interface comes from a PHP file with the same name
// as the injected one
ISourceModule sourceModel = interfaceObj.getSourceModule();
if (sourceModel != null) {
IPath superClassSrcPath = sourceModel.getPath();
String superClassSrcFileName = superClassSrcPath.toOSString();
String currentSrcFileName = null;
if (isInExistingPHPFile()) {
currentSrcFileName = getExistingFileName();
} else {
currentSrcFileName = getNewFileName();
}
// check if the file name are equals and path are different
if (!superClassSrcPath.removeLastSegments(1).equals(new Path(getSourceText()))
&& superClassSrcFileName.equals(currentSrcFileName)) {
interfacesStatus.setError(Messages.NewPHPTypePage_cannotImplementInterface + interfaceName);
updateStatus(findMostSevereStatus());
return;
}
}
}
updateStatus(findMostSevereStatus());
}
protected void validateTraits(IScriptProject model) {
traitsStatus = new StatusInfo();
Iterator<IType> iter = getTraits().iterator();
while (iter.hasNext()) {
traitsStatus = new StatusInfo();
IType interfaceObj = iter.next();
String interfaceName = interfaceObj.getElementName();
IDLTKSearchScope scope = SearchEngine.createSearchScope(getProject());
IType[] classes = PHPModelAccess.getDefault().findTypes(interfaceName, MatchRule.EXACT,
Modifiers.AccInterface, 0, scope, new NullProgressMonitor());
// could be null coming from a non PHP project when the user
// changes source folder manually by typing a location to a Java
// project for example..
if (classes == null || classes.length == 0) {
traitsStatus.setError(
Messages.NewPHPTypePage_trait + interfaceName + Messages.NewPHPTypePage_doesnotExistInProject);
updateStatus(findMostSevereStatus());
return;
}
boolean foundSiblings = false;
for (IType element : classes) {
// check if php file name equals
if (element.getPath().toOSString().equals(interfaceObj.getPath().toOSString())) {
interfaceObj = element;
foundSiblings = true;
break;
}
}
// not found exact file but same interface name...
if (!foundSiblings) {
traitsStatus.setWarning(Messages.NewPHPClassPage_trait + interfaceName);
updateStatus(findMostSevereStatus());
return;
}
// check if the interface comes from a PHP file with the same name
// as the injected one
ISourceModule sourceModel = interfaceObj.getSourceModule();
if (sourceModel != null) {
IPath superClassSrcPath = sourceModel.getPath();
String superClassSrcFileName = superClassSrcPath.toOSString();
String currentSrcFileName = null;
if (isInExistingPHPFile()) {
currentSrcFileName = getExistingFileName();
} else {
currentSrcFileName = getNewFileName();
}
// check if the file name are equals and path are different
if (!superClassSrcPath.removeLastSegments(1).equals(new Path(getSourceText()))
&& superClassSrcFileName.equals(currentSrcFileName)) {
traitsStatus.setError(Messages.NewPHPTypePage_cannotImplementTrait + interfaceName);
updateStatus(findMostSevereStatus());
return;
}
}
}
updateStatus(findMostSevereStatus());
}
/**
* @return true if the given name is valid PHP file name extension
*/
private boolean isPHPSuffix(String filename) {
IContentType type = Platform.getContentTypeManager().getContentType(ContentTypeIdForPHP.ContentTypeID_PHP);
return type.isAssociatedWith(filename);
}
/**
* @return true if the given name is valid PHP identifier
*/
private boolean isValidPHPIdentifier(String name) {
if (name != null && name.length() > 0) {
// Check if this is a valid PHP identifier:
if (!PHP_IDENTIFIER_PATTERN.matcher(name).matches()) {
return false;
}
// check if the identifier is keyword
if (isKeyword(name)) {
return false;
}
}
return true;
}
/**
* return true is case the given name is keyword, false otherwize
*/
private boolean isKeyword(String name) {
Collection<String> foundKeywords = PHPKeywords.getInstance(getProject().getProject()).findNamesByPrefix(name);
for (String keyword : foundKeywords) {
if (name.equalsIgnoreCase(keyword)) {
return true;
}
}
return false;
}
/**
* Since source folder changing affects the PHP model, it should be
* overriden by this class children.
*/
protected void sourceFolderChanged() {
sourceFolderStatus = new StatusInfo();
String sourcePath = sourceText.getText();
if (sourcePath.length() == 0) {
sourceFolderStatus.setError(Messages.NewPHPTypePage_sourceFolderMustNotBeEmpty);
} else if (!isValidSourcePath(sourcePath)) {
sourceFolderStatus
.setError(Messages.NewPHPTypePage_sourceFolder2 + sourcePath + Messages.NewPHPTypePage_isIllegal);
}
// check if project is closed
else {
IProject currentProject = getCurrentProject();
if (currentProject == null || !currentProject.isAccessible()) {
sourceFolderStatus.setError(
Messages.NewPHPTypePage_sourceFolder2 + sourcePath + Messages.NewPHPTypePage_isNotAccessible);
} else {
IScriptProject model = DLTKCore.create(currentProject);
if (model == null) {
sourceFolderStatus.setError(Messages.NewPHPTypePage_sourceFolder + sourcePath
+ Messages.NewPHPTypePage_doesNotPointToPhpProject);
}
}
}
updateStatus(findMostSevereStatus());
// disable Add button issue #15715
if (addInterfacesBtn != null) {
if (sourceFolderStatus.getCode() != IStatus.OK) {
addInterfacesBtn.setEnabled(false);
} else {
addInterfacesBtn.setEnabled(true);
}
}
if (addTraitsBtn != null) {
if (sourceFolderStatus.getCode() != IStatus.OK) {
addTraitsBtn.setEnabled(false);
} else {
addTraitsBtn.setEnabled(true);
}
}
}
protected boolean isPathExist(String path) {
final IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IPath containerPath = new Path(path);
IResource resource = workspaceRoot.findMember(containerPath);
return resource != null;
}
protected IModelElement getInitialPHPElement(final IStructuredSelection selection) {
if (selection != null && !selection.isEmpty()) {
Object obj = selection.getFirstElement();
IModelElement codeData = null;
if (obj instanceof NodeImpl) {
obj = ((IAdaptable) obj).getAdapter(IModelElement.class);
}
if (obj instanceof ISourceModule) {
codeData = (ISourceModule) obj;
while (codeData != null && !(codeData instanceof ISourceModule) && !(codeData instanceof IType)
&& !(codeData instanceof IMethod)) {
codeData = codeData.getParent();
}
// fixed bug 14462 - find the file element and get the name of
// the file
// in case of interface insert the interface to super interfaces
// list
if (codeData instanceof ISourceModule) {
try {
if (codeData.getCorrespondingResource() == null) {
isInExistingPHPFile = false;
return codeData;
}
} catch (ModelException e) {
Logger.logException(e);
}
isInExistingPHPFile = true;
String filename = null;
try {
filename = codeData.getCorrespondingResource().getFullPath().toOSString();
} catch (ModelException e) {
Logger.logException(e);
return null;
}
int idx = Math.max(filename.lastIndexOf('\\'), filename.lastIndexOf('/'));
if (idx != -1) {
existingFileName = filename.substring(idx + 1);
}
try {
existingFile = (IFile) codeData.getCorrespondingResource();
} catch (ModelException e) {
}
} else if (codeData instanceof IType) {
isInExistingPHPFile = false;
IType pClassData = (IType) codeData;
if (Flags.isInterface(pClassData.getElementType())) {
openByInterface = pClassData;
} else if (PHPFlags.isTrait(pClassData.getElementType())) {
openByTrait = pClassData;
}
} else {
isInExistingPHPFile = false;
}
return codeData;
} else if (obj instanceof IFile) {
isInExistingPHPFile = true;
existingFileName = ((IFile) obj).getName();
existingFile = (IFile) obj;
codeData = DLTKCore.create((IFile) obj);
}
if (codeData != null) {
return codeData;
}
}
return null;
}
protected IContainer getInitialContainer(final IStructuredSelection selection) {
if (selection != null && !selection.isEmpty()) {
final Object obj = selection.getFirstElement();
if (obj instanceof IModelElement) {
IResource resource = ((IModelElement) obj).getResource();
if (resource != null && !(resource instanceof IContainer)) {
resource = resource.getParent();
}
if (resource == null) {
IScriptProject sp = (IScriptProject) ((IModelElement) obj)
.getAncestor(IModelElement.SCRIPT_PROJECT);
if (sp != null) {
resource = sp.getProject();
}
}
return (IContainer) resource;
} else if (obj instanceof IResource) {
IResource resource = (IResource) obj;
if (resource != null && !(resource instanceof IContainer)) {
resource = resource.getParent();
}
return (IContainer) resource;
}
}
return null;
}
@Override
public void createControl(Composite parent) {
String[] addButtons = new String[] { Messages.NewPHPTypePage_add, null, Messages.NewPHPTypePage_remove };
IListAdapter<IType> listAdapter = new IListAdapter<IType>() {
@Override
public void customButtonPressed(ListDialogField<IType> field, int index) {
}
@Override
public void doubleClicked(ListDialogField<IType> field) {
}
@Override
public void selectionChanged(ListDialogField<IType> field) {
}
};
fSuperInterfacesDialogField = new ListDialogField<IType>(listAdapter, addButtons,
new PHPFullPathLabelProvider()) {
// override these methods to validate interfaces
@Override
public void removeElement(IType element) throws IllegalArgumentException {
super.removeElement(element);
validateInterfaces(getProject());
}
@Override
public void removeElements(List<IType> elements) {
super.removeElements(elements);
validateInterfaces(getProject());
}
@Override
public void removeAllElements() {
super.removeAllElements();
validateInterfaces(getProject());
}
};
fSuperInterfacesDialogField.setTableColumns(new ListDialogField.ColumnsDescription(1, false));
fSuperInterfacesDialogField.setLabelText(getSuperInterfacesLabel());
fSuperInterfacesDialogField.setRemoveButtonIndex(2);
fSuperInterfacesDialogField.setDialogFieldListener(this);
fTraitsDialogField = new ListDialogField<IType>(listAdapter, addButtons, new PHPFullPathLabelProvider()) {
// override these methods to validate interfaces
@Override
public void removeElement(IType element) throws IllegalArgumentException {
super.removeElement(element);
validateInterfaces(getProject());
}
@Override
public void removeElements(List<IType> elements) {
super.removeElements(elements);
validateInterfaces(getProject());
}
@Override
public void removeAllElements() {
super.removeAllElements();
validateInterfaces(getProject());
}
};
fTraitsDialogField.setTableColumns(new ListDialogField.ColumnsDescription(1, false));
fTraitsDialogField.setLabelText(Messages.NewPHPClassPage_traits);
fTraitsDialogField.setRemoveButtonIndex(2);
fTraitsDialogField.setDialogFieldListener(this);
}
/**
* Uses the standard container selection dialog to choose the new value for
* the Source Folder field.
*/
private void chooseNewSourceFolder() {
final ContainerSelectionDialog dialog = new ContainerSelectionDialog(getShell(),
ResourcesPlugin.getWorkspace().getRoot(), false, Messages.NewPHPTypePage_selectNewSourceFolder);
dialog.showClosedProjects(false);
if (dialog.open() == Window.OK) {
final Object[] result = dialog.getResult();
if (result.length == 1) {
sourceText.setText(((Path) result[0]).toOSString());
}
}
}
private void openPHPFileDialog() {
IFile[] selected = choosePHPEntries(null, new ArrayList<>());
if (selected == null || selected.length == 0) {
return;
}
existingFile = selected[0];
sourceText.setText(existingFile.getParent().getFullPath().toString());
existingFileText.setText(existingFile.getName());
}
// a UI component to select an existing file
private IFile[] choosePHPEntries(IPath initialSelection, List<Object> usedFiles) {
Class<?>[] acceptedClasses = new Class[] { IFile.class };
TypedElementSelectionValidator validator = new TypedElementSelectionValidator(acceptedClasses, true);
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IResource focus = initialSelection != null ? root.findMember(initialSelection) : null;
ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), new WorkbenchLabelProvider(),
new WorkbenchContentProvider());
dialog.setValidator(validator);
dialog.setTitle(Messages.NewPHPTypePage_phpFileSelection);
dialog.setMessage(Messages.NewPHPTypePage_selectExistingPHPFile);
dialog.addFilter(new NotUsedPHPFileFilter(usedFiles));
dialog.setInput(root);
dialog.setComparator(new ResourceComparator(ResourceComparator.NAME));
dialog.setInitialSelection(focus);
if (dialog.open() == Window.OK) {
Object[] elements = dialog.getResult();
IFile[] res = new IFile[elements.length];
for (int i = 0; i < res.length; i++) {
res[i] = (IFile) elements[i];
}
return res;
}
return null;
}
class NotUsedPHPFileFilter extends ViewerFilter {
private List<Object> fExcludes;
private final IContentType type = Platform.getContentTypeManager()
.getContentType(ContentTypeIdForPHP.ContentTypeID_PHP);
public NotUsedPHPFileFilter(List<Object> excludedFiles) {
fExcludes = excludedFiles;
}
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (element instanceof IFile) {
if (fExcludes != null && fExcludes.contains(element)) {
return false;
}
IFile file = (IFile) element;
return type.isAssociatedWith(file.getName());
}
return true;
}
}
// Interfaces Selection Control
protected Object chooseInterfaces() {
FilteredTypesSelectionDialog dialog = new FilteredTypesSelectionDialog(getShell(), false,
PlatformUI.getWorkbench().getProgressService(), SearchEngine.createSearchScope(getProject()),
IDLTKSearchConstants.TYPE, new TypeSelectionExtension() {
@Override
public ITypeInfoFilterExtension getFilterExtension() {
return typeInfoRequestor -> {
// is interface
if (Flags.isInterface(typeInfoRequestor.getModifiers())) {
List<IType> alreadySelectedInterfaces = fSuperInterfacesDialogField.getElements();
for (IType interfaceName : alreadySelectedInterfaces) {
if (interfaceName.getElementName()
.equalsIgnoreCase(typeInfoRequestor.getTypeName())) {
return false;
}
}
return true;
}
return false;
};
}
}, PHPLanguageToolkit.getDefault());
dialog.setListLabelProvider(new PHPFullPathLabelProvider());
dialog.setListSelectionLabelDecorator(new PHPFullPathLabelProvider());
dialog.setDetailsLabelProvider(new StatusLineLabelProvider());
dialog.setTitle(Messages.NewPHPTypePage_interfacesSelection);
dialog.setMessage(Messages.NewPHPTypePage_selectInterfaces);
dialog.setInitialPattern("", //$NON-NLS-1$
FilteredItemsSelectionDialog.FULL_SELECTION);
if (dialog.open() == Window.OK) {
Object[] resultArray = dialog.getResult();
if ((resultArray != null) && (resultArray.length > 0)) {
return resultArray[0];
}
}
return null;
}
// Interfaces Selection Control
protected Object chooseTraits() {
FilteredTypesSelectionDialog dialog = new FilteredTypesSelectionDialog(getShell(), false,
PlatformUI.getWorkbench().getProgressService(), SearchEngine.createSearchScope(getProject()),
IDLTKSearchConstants.TYPE, new TypeSelectionExtension() {
@Override
public ITypeInfoFilterExtension getFilterExtension() {
return typeInfoRequestor -> {
// is interface
if (PHPFlags.isTrait(typeInfoRequestor.getModifiers())) {
List<IType> alreadySelectedInterfaces = fTraitsDialogField.getElements();
for (IType interfaceName : alreadySelectedInterfaces) {
if (interfaceName.getElementName()
.equalsIgnoreCase(typeInfoRequestor.getTypeName())) {
return false;
}
}
return true;
}
return false;
};
}
}, PHPLanguageToolkit.getDefault());
dialog.setListLabelProvider(new PHPFullPathLabelProvider());
dialog.setListSelectionLabelDecorator(new PHPFullPathLabelProvider());
dialog.setDetailsLabelProvider(new StatusLineLabelProvider());
dialog.setTitle(Messages.NewPHPTypePage_traitsSelection);
dialog.setMessage(Messages.NewPHPTypePage_selectTraits);
dialog.setInitialPattern("", //$NON-NLS-1$
FilteredItemsSelectionDialog.FULL_SELECTION);
if (dialog.open() == Window.OK) {
Object[] resultArray = dialog.getResult();
if ((resultArray != null) && (resultArray.length > 0)) {
return resultArray[0];
}
}
return null;
}
public String getSourceText() {
return sourceText.getText().trim();
}
/**
* Finds the most severe error (if there is one)
*/
protected IStatus findMostSevereStatus() {
return StatusUtil.getMostSevere(new IStatus[] { sourceFolderStatus, elementNameStatus, newFileStatus,
existingFileStatus, interfacesStatus, namespaceStatus });
}
public PHPVersion getPHPVersion() {
return phpVersion;
}
protected void updateNewFilename() {
if (newFileText == null || newFileText.isDisposed()) {
return;
}
if (!elementNameStatus.matches(IStatus.ERROR) && !isInExistingPHPFile()) {
newFileText.setText(getElementName() + ".php"); //$NON-NLS-1$
}
}
protected IProject getCurrentProject() {
final IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
String projectPath = getSourceText();
if ((projectPath == null) || (projectPath.length() == 0)) {
return null;
}
if (!isValidSourcePath(projectPath)) {
return null;
}
return workspaceRoot.getProject(getProjectName(projectPath));
}
protected String getValue(Key key) {
IProject currProject = getCurrentProject();
IScopeContext[] fLookupOrder;
if (currProject != null) {
fLookupOrder = new IScopeContext[] { new ProjectScope(currProject), InstanceScope.INSTANCE,
DefaultScope.INSTANCE };
} else {
fLookupOrder = new IScopeContext[] { InstanceScope.INSTANCE, DefaultScope.INSTANCE };
}
WorkingCopyManager manager = new WorkingCopyManager();
return key.getStoredValue(fLookupOrder, false, manager);
}
protected final static Key getPHPCoreKey(String key) {
return getKey(PHPCorePlugin.ID, key);
}
protected static Key getKey(String plugin, String key) {
return new Key(plugin, key);
}
public Button getButton(String name) {
Button[] checkboxes = getGeneratedGroupCheckboxes();
for (Button button : checkboxes) {
if (button.getText().trim().equals(name)) {
return button;
}
}
return null;
}
@Override
public void dialogFieldChanged(DialogField field) {
changeButtonEnableStatus();
}
protected void changeButtonEnableStatus() {
Button button = getButton(REQUIRE_ONCE);
if (button != null) {
button.setEnabled(requireOnceShouldEnabled());
}
}
protected boolean requireOnceShouldEnabled() {
return !fSuperInterfacesDialogField.getElements().isEmpty() || !fTraitsDialogField.getElements().isEmpty();
}
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
if (visible) {
elementName.setFocus();
}
}
}