/** * */ package org.bundlemaker.core.ui.projecteditor; import java.util.Arrays; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.bundlemaker.core.project.BundleMakerProjectState; import org.bundlemaker.core.project.BundleMakerProjectDescriptionChangedEvent; import org.bundlemaker.core.project.IBundleMakerProjectChangedListener; import org.bundlemaker.core.project.IModifiableProjectDescription; import org.bundlemaker.core.project.IProjectContentProvider; import org.bundlemaker.core.project.BundleMakerProjectStateChangedEvent; import org.bundlemaker.core.resource.IModuleAwareBundleMakerProject; import org.bundlemaker.core.ui.BundleMakerImages; import org.bundlemaker.core.ui.VerticalFormButtonBar; import org.bundlemaker.core.ui.projecteditor.dnd.IProjectEditorDropProvider; import org.bundlemaker.core.ui.projecteditor.layout.FormLayoutUtils; import org.bundlemaker.core.ui.projecteditor.newwizard.ChooseContentProviderWizard; import org.bundlemaker.core.ui.projecteditor.provider.IProjectContentProviderEditor; import org.bundlemaker.core.ui.projecteditor.provider.IProjectContentProviderEditorElement; import org.bundlemaker.core.ui.projecteditor.provider.internal.ProjectEditorContributionRegistry; import org.bundlemaker.core.ui.utils.BundleMakerProjectOpener; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.layout.TreeColumnLayout; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.TreeViewerColumn; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.Transfer; 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.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Tree; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.IManagedForm; import org.eclipse.ui.forms.editor.FormPage; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.model.IWorkbenchAdapter; /** * <p> * Graphical editor for BundleMakers project contents * </p> * * @author Nils Hartmann (nils@nilshartmann.net) * */ public class ProjectEditorPage extends FormPage { /** * The project that is edited */ private final IModuleAwareBundleMakerProject _bundleMakerProject; /** * The form holding our controls */ private ScrolledForm _form; private boolean _needsReopening = true; private TreeViewer _treeViewer; private Button _editButton; private Button _removeButton; private Button _moveDownButton; private Button _moveUpButton; private Button _parseProjectButton; public ProjectEditorPage(ProjectEditor editor) { super(editor, "Content", "Content"); _bundleMakerProject = editor.getBundleMakerProject(); } @Override protected void createFormContent(IManagedForm mform) { super.createFormContent(mform); FormToolkit toolkit = mform.getToolkit(); _form = mform.getForm(); toolkit.decorateFormHeading(_form.getForm()); _form.setImage(BundleMakerImages.BUNDLEMAKER_ICON_SMALL.getImage()); _form.setText("Content"); _form.getBody().setLayout(FormLayoutUtils.createFormGridLayout(true, 1)); addBundleMakerProjectChangedListener(); // getEditor().addPropertyListener(new IPropertyListener() { // // @Override // public void propertyChanged(Object source, int propId) { // if (propId == IEditorPart.PROP_DIRTY) { // dirty = !dirty; // } // } // }); // HIER KOMMT DER EDITOR !!! createEditorControls(mform); // Add actions to toolbar updateToolBar(); refreshFormTitle(); } private void createEditorControls(final IManagedForm mform) { FormToolkit toolkit = mform.getToolkit(); final ScrolledForm form = mform.getForm(); Composite client = toolkit.createComposite(form.getBody()); client.setLayoutData(new GridData(GridData.FILL_BOTH)); client.setLayout(new GridLayout(2, false)); // Create the tree view and viewer that displays the IFileBasedContent entries Composite treeComposite = new Composite(client, SWT.NO); final Tree projectContentTree = toolkit.createTree(treeComposite, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION); GridData gd = new GridData(GridData.FILL_BOTH); gd.heightHint = 200; gd.widthHint = 100; treeComposite.setLayoutData(gd); projectContentTree.setLinesVisible(true); _treeViewer = new TreeViewer(projectContentTree); _treeViewer.setContentProvider(new ProjectEditorTreeViewerContentProvider(getProjectEditorContributionRegistry())); configureTreeDragAndDrop(); createTreeColumns(); createMenuManager(); final Shell shell = client.getShell(); // Set tree content _treeViewer.setInput(_bundleMakerProject); // add double click listener that edits the selected item _treeViewer.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(DoubleClickEvent event) { editContent(shell); } }); // Create the buttonbar final VerticalFormButtonBar buttonBar = new VerticalFormButtonBar(client, toolkit); // Create buttons buttonBar.newButton("Add...", new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { addContent(shell); } }); _editButton = buttonBar.newButton("Edit...", new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { editContent(shell); } }); _removeButton = buttonBar.newButton("Remove", new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { removeContent(shell); } }); _moveUpButton = buttonBar.newButton("Up", new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { moveProjectContentProviderUp(); } }); _moveDownButton = buttonBar.newButton("Down", new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { moveProjectContentProviderDown(); } }); _parseProjectButton = buttonBar.newButton("Open project", new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { parseProject(); } }); GridData layoutData = new GridData(GridData.FILL_HORIZONTAL); layoutData.grabExcessVerticalSpace = true; layoutData.verticalAlignment = SWT.BOTTOM; _parseProjectButton.setImage(BundleMakerImages.BUNDLEMAKER_PARSE_PROJECT.getImage()); _parseProjectButton.setLayoutData(layoutData); _treeViewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { refreshEnablement(); } }); // set initial enablement refreshEnablement(); // paint the borders toolkit.paintBordersFor(client); } /** * @return */ private ProjectEditorContributionRegistry getProjectEditorContributionRegistry() { return Activator.getDefault() .getProjectEditorContributionRegistry(); } /** * */ private void createMenuManager() { // Create menu manager MenuManager menuMgr = new MenuManager(); // Create menu for tree viewer Menu menu = menuMgr.createContextMenu(_treeViewer.getControl()); menuMgr.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager manager) { // (re-)populate context menu each time the menu is shown fillContextMenu(manager); } }); menuMgr.setRemoveAllWhenShown(true); _treeViewer.getControl().setMenu(menu); } protected void fillContextMenu(IMenuManager menuManager) { List<IProjectContentProviderEditorElement> selectedTreeViewerElements = getSelectedObjects(_treeViewer.getSelection(), IProjectContentProviderEditorElement.class); Set<IProjectContentProviderEditor> contentProviderEditors = getProjectEditorContributionRegistry() .getContentProviderEditors(); for (IProjectContentProviderEditor iProjectContentProviderEditor : contentProviderEditors) { List<IAction> contextMenuActions = iProjectContentProviderEditor.getContextMenuActions(_bundleMakerProject, selectedTreeViewerElements); if (contextMenuActions != null) { for (IAction iAction : contextMenuActions) { menuManager.add(iAction); } } } } protected Map<IProjectContentProviderEditor, List<Object>> getSelectedElementsByProvider() { Map<IProjectContentProviderEditor, List<Object>> result = new Hashtable<IProjectContentProviderEditor, List<Object>>(); List<ProjectEditorTreeViewerElement> selectedTreeViewerElements = getSelectedTreeViewerElements(); for (ProjectEditorTreeViewerElement selectedElement : selectedTreeViewerElements) { IProjectContentProviderEditor providingEditor = selectedElement.getProvidingEditor(); List<Object> objects = result.get(providingEditor); if (objects == null) { objects = new LinkedList<Object>(); result.put(providingEditor, objects); } objects.add(selectedElement.getElement()); } return result; } private void configureTreeDragAndDrop() { ProjectEditorContributionRegistry projectEditorDndProviderRegistry = getProjectEditorContributionRegistry(); Set<IProjectEditorDropProvider> registeredDndProviders = projectEditorDndProviderRegistry .getDropProviders(); ProjectEditorTreeViewerDropAdapter adapter = new ProjectEditorTreeViewerDropAdapter(_treeViewer, _bundleMakerProject, registeredDndProviders) { @Override protected void afterDrop(Object target) { // refresh the tree _treeViewer.refresh(null); // make the new object visible _treeViewer.expandToLevel(target, 1); // make sure tree viewer has focus _treeViewer.getControl().getParent().setFocus(); } }; // TODO: allow providers to specify supported operations int operations = DND.DROP_COPY | DND.DROP_MOVE; Set<Transfer> allSupportedTransferTypes = new HashSet<Transfer>(); for (IProjectEditorDropProvider provider : registeredDndProviders) { Transfer[] supportedTypes = provider.getSupportedDropTypes(); allSupportedTransferTypes.addAll(Arrays.asList(supportedTypes)); } _treeViewer.addDropSupport(operations, allSupportedTransferTypes.toArray(new Transfer[0]), adapter); } private void refreshEnablement() { List<ProjectEditorTreeViewerElement> selectedTreeViewerElements = getSelectedTreeViewerElements(); // Add... Button is always enabled as long as their is a "IProjectContentProviderFactory-Editor" available // Edit... is enabled only when there is exactly ONE selected object AND it's providing ProviderEditor returns true // on canEdit(Object) // Remove is enabled when at least one element is selected and either... // ...all of the elements are IProjectContentProviders (top level types) OR // ...all of the elements are children of the SAME TYPE of IProjectContentProviders // Up/Down are enabled when at least on IProjectContentProvider is selected (and no other element) boolean moveButtonsEnabled; boolean editButtonEnabled; boolean removeButtonEnabled; if (selectedTreeViewerElements.isEmpty()) { moveButtonsEnabled = false; editButtonEnabled = false; removeButtonEnabled = false; } else { moveButtonsEnabled = true; removeButtonEnabled = true; editButtonEnabled = selectedTreeViewerElements.size() == 1; for (ProjectEditorTreeViewerElement projectEditorTreeViewerElement : selectedTreeViewerElements) { final boolean isProjectContentProviderSelected = (projectEditorTreeViewerElement.getElement() instanceof IProjectContentProvider); if (!isProjectContentProviderSelected) { // move and remove buttons are only enable if only IProjectContentProvider elements are selected moveButtonsEnabled = false; if (removeButtonEnabled) { removeButtonEnabled = projectEditorTreeViewerElement.getProvidingEditor().canRemove( projectEditorTreeViewerElement.getElement()); } } if (editButtonEnabled) { editButtonEnabled = projectEditorTreeViewerElement.getProvidingEditor().canEdit( projectEditorTreeViewerElement.getElement()); } } } _moveDownButton.setEnabled(moveButtonsEnabled); _moveUpButton.setEnabled(moveButtonsEnabled); _removeButton.setEnabled(removeButtonEnabled); _editButton.setEnabled(editButtonEnabled); } /** * @param shell */ protected void addContent(Shell shell) { // Create the wizard presenting the available content provider wizards ProjectEditorContributionRegistry registry = getProjectEditorContributionRegistry(); ChooseContentProviderWizard wizard = new ChooseContentProviderWizard(_bundleMakerProject, registry); // create the WizardDialog WizardDialog dialog = new WizardDialog(shell, wizard); dialog.open(); // refresh Tree _treeViewer.refresh(null); } /** * @param shell */ protected void editContent(Shell shell) { IStructuredSelection treeViewerSelection = getTreeViewerSelection(); if (treeViewerSelection.isEmpty()) { return; } ProjectEditorTreeViewerElement element = (ProjectEditorTreeViewerElement) treeViewerSelection.getFirstElement(); boolean result = element.getProvidingEditor().edit(shell, _bundleMakerProject, element.getProjectContentProvider(), element.getElement()); if (!result) { return; } _treeViewer.refresh(null); } protected void moveProjectContentProviderUp() { moveProjectContentProvider(true); } protected void moveProjectContentProviderDown() { moveProjectContentProvider(false); } protected void moveProjectContentProvider(boolean up) { List<ProjectEditorTreeViewerElement> selectedTreeViewerElements = getSelectedTreeViewerElements(); List<IProjectContentProvider> contentProviders = new LinkedList<IProjectContentProvider>(); for (ProjectEditorTreeViewerElement projectEditorTreeViewerElement : selectedTreeViewerElements) { if (projectEditorTreeViewerElement.getElement() instanceof IProjectContentProvider) { IProjectContentProvider projectContentProvider = (IProjectContentProvider) projectEditorTreeViewerElement .getElement(); contentProviders.add(projectContentProvider); } } if (!contentProviders.isEmpty()) { IModifiableProjectDescription modifiableProjectDescription = getBundleMakerProject() .getModifiableProjectDescription(); if (up) { modifiableProjectDescription.moveUpContentProviders(contentProviders); } else { modifiableProjectDescription.moveDownContentProviders(contentProviders); } } _treeViewer.refresh(null); } /** * */ protected void removeContent(final Shell shell) { List<ProjectEditorTreeViewerElement> selectedObjects = getSelectedTreeViewerElements(); for (ProjectEditorTreeViewerElement projectEditorTreeViewerElement : selectedObjects) { if (projectEditorTreeViewerElement.getElement() instanceof IProjectContentProvider) { IProjectContentProvider provider = (IProjectContentProvider) projectEditorTreeViewerElement.getElement(); _bundleMakerProject.getModifiableProjectDescription().removeContentProvider(provider); } else { projectEditorTreeViewerElement.getProvidingEditor().remove(shell, _bundleMakerProject, projectEditorTreeViewerElement.getProjectContentProvider(), projectEditorTreeViewerElement.getElement()); } } _treeViewer.refresh(null); } protected List<ProjectEditorTreeViewerElement> getSelectedTreeViewerElements() { return getSelectedObjects(_treeViewer.getSelection(), ProjectEditorTreeViewerElement.class); } @SuppressWarnings({ "unchecked", "rawtypes" }) public static <T> List<T> getSelectedObjects(ISelection selection, Class<T> type) { final List<T> result = new LinkedList<T>(); if (selection instanceof IStructuredSelection) { IStructuredSelection structuredSelection = (IStructuredSelection) selection; Iterator iterator = structuredSelection.iterator(); while (iterator.hasNext()) { Object element = iterator.next(); if (type.isInstance(element)) { result.add((T) element); } } } return result; } protected IStructuredSelection getTreeViewerSelection() { return (IStructuredSelection) _treeViewer.getSelection(); } /** * */ private void createTreeColumns() { Tree tree = _treeViewer.getTree(); TreeColumnLayout layout = new TreeColumnLayout(); TreeViewerColumn column = new TreeViewerColumn(_treeViewer, SWT.NONE); column.setLabelProvider(new ProjectEditorTreeViewerResourceLabelProvider()); column.getColumn().setResizable(true); column.getColumn().setMoveable(true); column.getColumn().setText("Resource"); layout.setColumnData(column.getColumn(), new ColumnWeightData(80)); column = new TreeViewerColumn(_treeViewer, SWT.NONE); // column.setLabelProvider(new BundleMakerProjectDescriptionColumnLabelProvider(1)); // column.setEditingSupport(FileBasedContentEditingSupport.newEditingSupportForAnalyzeResource(this, _treeViewer)); column.setLabelProvider(new ProjectEditorTreeViewerAnalyzeLabelProvider(0)); column.setEditingSupport(new ProjectEditorTreeViewerEditingSupport(_treeViewer, true)); column.getColumn().setResizable(true); column.getColumn().setMoveable(true); column.getColumn().setText("Analyze"); column.getColumn().setAlignment(SWT.CENTER); layout.setColumnData(column.getColumn(), new ColumnWeightData(10)); column = new TreeViewerColumn(_treeViewer, SWT.NONE); // column.setLabelProvider(new BundleMakerProjectDescriptionColumnLabelProvider(2)); // column.setEditingSupport(FileBasedContentEditingSupport.newEditingSupportForAnalyzeSources(this, _treeViewer)); column.setLabelProvider(new ProjectEditorTreeViewerAnalyzeLabelProvider(1)); column.setEditingSupport(new ProjectEditorTreeViewerEditingSupport(_treeViewer, false)); column.getColumn().setResizable(true); column.getColumn().setMoveable(true); column.getColumn().setText("Analyze Sources"); column.getColumn().setAlignment(SWT.CENTER); layout.setColumnData(column.getColumn(), new ColumnWeightData(20)); tree.getParent().setLayout(layout); tree.setHeaderVisible(true); tree.layout(true); } private void updateToolBar() { // grab the form's toolbar IToolBarManager toolBarManager = _form.getToolBarManager(); // add actions toolBarManager.add(new ParseAction()); // update the toolbar _form.updateToolBar(); } private void refreshFormTitle() { if (!_form.isDisposed()) { _form.setText("Content"); if (_needsReopening) { _form.setMessage("Needs re-opening", IMessageProvider.INFORMATION); } else { _form.setMessage(null, IMessageProvider.NONE); } } } public void parseProject() { // Bug-Fix: Refresh the workspace to prevent eclipse from showing hidden projects try { ResourcesPlugin.getWorkspace().getRoot().refreshLocal(IResource.DEPTH_INFINITE, null); } catch (CoreException e) { // silently ignore... } // allow user to save the project if project is dirty IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); if (!page.saveEditor(getEditor(), true)) { // user canceled operation return; } // Parse the project BundleMakerProjectOpener.openProject(getBundleMakerProject()); } private void addBundleMakerProjectChangedListener() { getBundleMakerProject().addBundleMakerProjectChangedListener(new IBundleMakerProjectChangedListener.Adapter() { /** * {@inheritDoc} */ @Override public void projectStateChanged(BundleMakerProjectStateChangedEvent event) { handle(); } /** * {@inheritDoc} */ @Override public void projectDescriptionChanged(BundleMakerProjectDescriptionChangedEvent event) { if (event.getType() == BundleMakerProjectDescriptionChangedEvent.Type.PROJECT_DESCRIPTION_RECOMPUTED) { handle(); } } private void handle() { _needsReopening = getBundleMakerProject().getState() != BundleMakerProjectState.READY; Display.getDefault().syncExec(new Runnable() { @Override public void run() { refreshFormTitle(); } }); } }); } /** * @return */ private IModuleAwareBundleMakerProject getBundleMakerProject() { return _bundleMakerProject; } /** * An {@link Action} that (re-)parses the BundleMaker project */ class ParseAction extends Action { public ParseAction() { super("Open"); setImageDescriptor(BundleMakerImages.BUNDLEMAKER_PARSE_PROJECT.getImageDescriptor()); } @Override public void run() { parseProject(); } } class WorkbenchAdapterColumnLabelProvider extends ColumnLabelProvider { /* * (non-Javadoc) * * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object) */ @Override public String getText(Object element) { IWorkbenchAdapter adapter = (IWorkbenchAdapter) Platform.getAdapterManager().getAdapter(element, IWorkbenchAdapter.class); if (adapter != null) { return adapter.getLabel(element); } return super.getText(element); } /* * (non-Javadoc) * * @see org.eclipse.jface.viewers.ColumnLabelProvider#getImage(java.lang.Object) */ @Override public Image getImage(Object element) { IWorkbenchAdapter adapter = (IWorkbenchAdapter) Platform.getAdapterManager().getAdapter(element, IWorkbenchAdapter.class); if (adapter != null) { return adapter.getImageDescriptor(element).createImage(); } return super.getImage(element); } } }