/******************************************************************************* * Copyright (c) 2004, 2012 QNX Software Systems 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: * QNX Software Systems - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.ui.wizards.classwizard; import java.util.ArrayList; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Tree; import org.eclipse.ui.dialogs.SelectionStatusDialog; import org.eclipse.cdt.utils.PathUtil; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICContainer; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ICElementVisitor; import org.eclipse.cdt.core.model.ICModel; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.ui.CElementContentProvider; import org.eclipse.cdt.ui.CElementLabelProvider; import org.eclipse.cdt.ui.CElementSorter; import org.eclipse.cdt.internal.corext.util.CModelUtil; import org.eclipse.cdt.internal.ui.dialogs.StatusInfo; import org.eclipse.cdt.internal.ui.dialogs.StatusUtil; import org.eclipse.cdt.internal.ui.dialogs.TypedViewerFilter; import org.eclipse.cdt.internal.ui.wizards.dialogfields.DialogField; import org.eclipse.cdt.internal.ui.wizards.dialogfields.IDialogFieldListener; import org.eclipse.cdt.internal.ui.wizards.dialogfields.LayoutUtil; import org.eclipse.cdt.internal.ui.wizards.dialogfields.StringDialogField; public class SourceFileSelectionDialog extends SelectionStatusDialog { TreeViewer fViewer; private final ITreeContentProvider fContentProvider = new CElementContentProvider(); private final ILabelProvider fLabelProvider = new CElementLabelProvider(CElementLabelProvider.SHOW_DEFAULT); IStatus fCurrStatus = new StatusInfo(); IStatus fFolderNameStatus = new StatusInfo(); IStatus fFileNameStatus = new StatusInfo(); ICElement fInput; private int fWidth = 60; private int fHeight = 18; StringDialogField fFolderNameDialogField; StringDialogField fFileNameDialogField; private IWorkspaceRoot fWorkspaceRoot; private final FieldsAdapter fFieldsAdapter = new FieldsAdapter(); private ICElement fCurrentFolder = null; private String fCurrentFileString = null; String fInitialFolderName = null; String fInitialFileName = null; private final class FieldsAdapter extends SelectionAdapter implements ISelectionChangedListener, IDoubleClickListener, IDialogFieldListener { // -- SelectionAdapter -- @Override public void widgetDefaultSelected(SelectionEvent e) { doStatusUpdate(); if (fCurrStatus.isOK()) buttonPressed(IDialogConstants.OK_ID); } // -- ISelectionChangedListener -- @Override public void selectionChanged(SelectionChangedEvent event) { setResult(((IStructuredSelection) event.getSelection()).toList()); ISelection sel = event.getSelection(); if (sel instanceof IStructuredSelection) { Object obj = ((IStructuredSelection) sel).getFirstElement(); if (obj instanceof ICElement) { ICElement elem = (ICElement) obj; IPath path = elem.getPath(); String fileName = fFileNameDialogField.getText(); String folderName = fFolderNameDialogField.getText(); if (elem instanceof ICContainer || elem instanceof ICProject) { folderName = path.toString(); } else { folderName = path.removeLastSegments(1).toString(); fileName = path.lastSegment(); } setPathFields(folderName, fileName); } } doStatusUpdate(); } // -- IDoubleClickListener -- @Override public void doubleClick(DoubleClickEvent event) { doStatusUpdate(); ISelection selection = event.getSelection(); if (selection instanceof IStructuredSelection) { Object item = ((IStructuredSelection)selection).getFirstElement(); if (fCurrStatus.getSeverity() != IStatus.ERROR) { if (item instanceof ITranslationUnit) { setResult(((IStructuredSelection)selection).toList()); close(); return; } } if (fViewer.getExpandedState(item)) fViewer.collapseToLevel(item, 1); else fViewer.expandToLevel(item, 1); } } // -- IDialogFieldListener -- @Override public void dialogFieldChanged(DialogField field) { if (field == fFolderNameDialogField) { fFolderNameStatus = folderNameChanged(); fFileNameStatus = fileNameChanged(); } else if (field == fFileNameDialogField) { fFileNameStatus = fileNameChanged(); } doStatusUpdate(); } } static final Class<?>[] FILTER_TYPES = new Class[] { ICModel.class, ICProject.class, ICContainer.class, ITranslationUnit.class }; private final class Filter extends TypedViewerFilter { private Filter() { super(FILTER_TYPES); } @Override public boolean select(Viewer viewer, Object parent, Object obj) { if (obj instanceof ICElement) { ICElement elem = (ICElement)obj; if (!(fInput instanceof ICModel)) { return elem.getCProject().equals(fInput.getCProject()); } return true; } return super.select(viewer, parent, obj); } } /** * Constructs an instance of <code>ElementTreeSelectionDialog</code>. * * @param parent * The parent shell for the dialog */ public SourceFileSelectionDialog(Shell parent) { super(parent); fWorkspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); fInput = CoreModel.create(fWorkspaceRoot); fFolderNameDialogField = new StringDialogField(); fFolderNameDialogField.setDialogFieldListener(fFieldsAdapter); fFolderNameDialogField.setLabelText(NewClassWizardMessages.SourceFileSelectionDialog_folderName_label); fFileNameDialogField = new StringDialogField(); fFileNameDialogField.setDialogFieldListener(fFieldsAdapter); fFileNameDialogField.setLabelText(NewClassWizardMessages.SourceFileSelectionDialog_fileName_label); setResult(new ArrayList<Object>(0)); setStatusLineAboveButtons(true); int shellStyle = getShellStyle(); setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE); } /** * Sets the tree input. * * @param input * the tree input. */ public void setInput(ICElement input) { fInput = input; } protected void doStatusUpdate() { // status of all used components IStatus[] status = new IStatus[] { fFolderNameStatus, fFileNameStatus }; // the mode severe status will be displayed and the ok button enabled/disabled. updateStatus(status); } /** * Updates the status line and the ok button according to the given status * * @param status status to apply */ @Override protected void updateStatus(IStatus status) { fCurrStatus = status; super.updateStatus(status); } /** * Updates the status line and the ok button according to the status evaluate from * an array of status. The most severe error is taken. In case that two status with * the same severity exists, the status with lower index is taken. * * @param status the array of status */ protected void updateStatus(IStatus[] status) { updateStatus(StatusUtil.getMostSevere(status)); } IStatus folderNameChanged() { StatusInfo status = new StatusInfo(); fCurrentFolder = null; String str = fFolderNameDialogField.getText(); if (str.length() == 0) { status.setError(NewClassWizardMessages.SourceFileSelectionDialog_error_EnterFolderName); return status; } IPath path = new Path(str); IResource res = fWorkspaceRoot.findMember(path); if (res != null && res.exists()) { int resType = res.getType(); if (resType == IResource.PROJECT || resType == IResource.FOLDER) { IProject proj = res.getProject(); if (!proj.isOpen()) { status.setError(NLS.bind(NewClassWizardMessages.SourceFileSelectionDialog_error_NotAFolder, str)); return status; } ICElement e = CoreModel.getDefault().create(res.getFullPath()); fCurrentFolder = CModelUtil.getSourceFolder(e); if (fCurrentFolder == null) { status.setError(NLS.bind(NewClassWizardMessages.SourceFileSelectionDialog_error_NotASourceFolder, str)); return status; } if (!CoreModel.hasCCNature(proj) && !CoreModel.hasCNature(proj)) { if (resType == IResource.PROJECT) { status.setError(NewClassWizardMessages.SourceFileSelectionDialog_warning_NotACProject); return status; } status.setWarning(NewClassWizardMessages.SourceFileSelectionDialog_warning_NotInACProject); } } else { status.setError(NLS.bind(NewClassWizardMessages.SourceFileSelectionDialog_error_NotAFolder, str)); return status; } } else { status.setError(NLS.bind(NewClassWizardMessages.SourceFileSelectionDialog_error_FolderDoesNotExist, str)); return status; } return status; } IStatus fileNameChanged() { StatusInfo status = new StatusInfo(); fCurrentFileString = null; ICElement existingFile = null; String str = fFileNameDialogField.getText(); if (str.length() == 0) { status.setError(NewClassWizardMessages.SourceFileSelectionDialog_error_EnterFileName); return status; } if (fCurrentFolder != null) { IPath folderPath = fCurrentFolder.getPath(); IPath path = new Path(str); IResource res = fWorkspaceRoot.findMember(folderPath.append(path)); if (res == null) res = fWorkspaceRoot.findMember(path); if (res != null && res.exists()) { int resType = res.getType(); if (resType == IResource.FILE) { IProject proj = res.getProject(); if (!proj.isOpen()) { status.setError(NLS.bind(NewClassWizardMessages.SourceFileSelectionDialog_error_NotAFile, str)); return status; } ICElement e = CoreModel.getDefault().create(res.getFullPath()); if (e instanceof ITranslationUnit) { existingFile = e; } if (existingFile == null) { status.setError(NLS.bind(NewClassWizardMessages.SourceFileSelectionDialog_error_NotASourceFile, str)); return status; } if (!CoreModel.hasCCNature(proj) && !CoreModel.hasCNature(proj)) { status.setWarning(NewClassWizardMessages.SourceFileSelectionDialog_warning_NotInACProject); } } else { status.setError(NLS.bind(NewClassWizardMessages.SourceFileSelectionDialog_error_NotAFile, str)); return status; } } } if (existingFile != null) { status.setWarning(NLS.bind(NewClassWizardMessages.SourceFileSelectionDialog_warning_SourceFileExists, str)); } fCurrentFileString = str; return status; } /* * (non-Javadoc) * * @see org.eclipse.jface.window.Window#open() */ @Override public int open() { super.open(); return getReturnCode(); } /** * Handles cancel button pressed event. */ @Override protected void cancelPressed() { setResult(null); super.cancelPressed(); } /* * @see SelectionStatusDialog#computeResult() */ @Override protected void computeResult() { setResult(((IStructuredSelection) fViewer.getSelection()).toList()); } /* * (non-Javadoc) * * @see org.eclipse.jface.window.Window#create() */ @Override public void create() { BusyIndicator.showWhile(null, new Runnable() { @Override public void run() { superCreate(); fViewer.setSelection(new StructuredSelection(getInitialElementSelections()), true); setPathFields(fInitialFolderName, fInitialFileName); fFileNameDialogField.setFocus(); doStatusUpdate(); } }); } void superCreate() { super.create(); } /* * @see Dialog#createDialogArea(Composite) */ @Override protected Control createDialogArea(Composite parent) { Composite composite = (Composite) super.createDialogArea(parent); // Label messageLabel = createMessageArea(composite); int nColumns = 4; fFolderNameDialogField.doFillIntoGrid(composite, nColumns - 1); DialogField.createEmptySpace(composite); LayoutUtil.setWidthHint(fFolderNameDialogField.getTextControl(null), getMaxFieldWidth()); TreeViewer treeViewer = createTreeViewer(composite); GridData data = new GridData(GridData.FILL_BOTH); data.widthHint = convertWidthInCharsToPixels(fWidth); data.heightHint = convertHeightInCharsToPixels(fHeight); Tree treeWidget = treeViewer.getTree(); treeWidget.setLayoutData(data); treeWidget.setFont(parent.getFont()); fFileNameDialogField.doFillIntoGrid(composite, nColumns - 1); DialogField.createEmptySpace(composite); LayoutUtil.setWidthHint(fFileNameDialogField.getTextControl(null), getMaxFieldWidth()); return composite; } /** * Returns the recommended maximum width for text fields (in pixels). This * method requires that createContent has been called before this method is * call. Subclasses may override to change the maximum width for text * fields. * * @return the recommended maximum width for text fields. */ protected int getMaxFieldWidth() { return convertWidthInCharsToPixels(60); } /** * Creates the tree viewer. * * @param parent * the parent composite * @return the tree viewer */ protected TreeViewer createTreeViewer(Composite parent) { int style = (SWT.BORDER | SWT.SINGLE); fViewer = new TreeViewer(new Tree(parent, style)); fViewer.setContentProvider(fContentProvider); fViewer.setLabelProvider(fLabelProvider); fViewer.addSelectionChangedListener(fFieldsAdapter); fViewer.setSorter(new CElementSorter()); fViewer.addFilter(new Filter()); Tree tree = fViewer.getTree(); tree.addSelectionListener(fFieldsAdapter); fViewer.addDoubleClickListener(fFieldsAdapter); fViewer.setInput(fInput.getCModel()); return fViewer; } /** * Returns the tree viewer. * * @return the tree viewer */ protected TreeViewer getTreeViewer() { return fViewer; } /** * @see org.eclipse.jface.window.Window#handleShellCloseEvent() */ @Override protected void handleShellCloseEvent() { super.handleShellCloseEvent(); //Handle the closing of the shell by selecting the close icon if (getReturnCode() == CANCEL) setResult(null); } public String getFolderName() { if (fCurrentFolder != null) { return fCurrentFolder.getPath().toString(); } return null; } public String getFileName() { return fCurrentFileString; } public IPath getFilePath() { IPath path = null; if (fCurrentFolder != null) { path = fCurrentFolder.getPath(); if (fCurrentFileString != null) path = path.append(fCurrentFileString); } else if (fCurrentFileString != null) { path = new Path(fCurrentFileString); } return path; } void setPathFields(String folderName, String fileName) { fFolderNameDialogField.setTextWithoutUpdate(folderName != null ? folderName : ""); //$NON-NLS-1$ fFileNameDialogField.setTextWithoutUpdate(fileName != null ? fileName : ""); //$NON-NLS-1$ fFolderNameStatus = folderNameChanged(); fFileNameStatus = fileNameChanged(); } /** * Sets the initial selection. Convenience method. */ public void setInitialSelection(String folderName, String fileName) { fInitialFileName = (fileName != null && fileName.length() > 0) ? fileName : null; fInitialFolderName = null; if (folderName != null && folderName.length() > 0) { // find a folder that actually exists IPath initialFolderPath = new Path(folderName); final IPath folderPath = PathUtil.getValidEnclosingFolder(initialFolderPath); if (folderPath != null) { fInitialFolderName = folderPath.toString(); if (fInput != null) { final ICElement[] foundElem = {/*base_folder*/ null, /*exact_folder*/ null, /*exact_file*/ null}; try { fInput.accept(new ICElementVisitor() { @Override public boolean visit(ICElement elem) { IPath path = elem.getPath(); if (path.isPrefixOf(folderPath)) { if (foundElem[0] == null || path.segmentCount() > foundElem[0].getPath().segmentCount()) { foundElem[0] = elem; /*base_folder*/ } if (path.equals(folderPath)) { foundElem[1] = elem; /*exact_folder*/ if (fInitialFileName == null) return false; // no need to search children } else if (fInitialFileName != null && elem.getElementName().equals(fInitialFileName)) { foundElem[2] = elem; /*exact_file*/ return false; // no need to search children } return true; } return false; } }); ICElement selectedElement = foundElem[2]; /*exact_file*/ if (selectedElement == null) selectedElement = foundElem[1]; /*exact_folder*/ if (selectedElement == null) selectedElement = foundElem[0]; /*base_folder*/ if (selectedElement != null) { setInitialSelections(new Object[] { selectedElement }); } } catch (CoreException e) { } } } } } }