blob: 06556a4ed9bbbc2c7371d27fbeb2991a9fcf90a9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 Google, Inc and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Sergey Prigogin (Google) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.ui.preferences;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.internal.ui.dialogs.IStatusChangeListener;
import org.eclipse.cdt.internal.ui.dialogs.StatusInfo;
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle;
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle.IncludeKind;
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.ITreeListAdapter;
import org.eclipse.cdt.internal.ui.wizards.dialogfields.TreeListDialogField;
import org.eclipse.core.resources.IProject;
import org.eclipse.jface.layout.PixelConverter;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
/**
* The preference block for configuring styles of different categories of include statements.
*/
public class IncludeCategoriesBlock extends OptionsConfigurationBlock {
private final List<IncludeGroupStyle> styles;
private final Map<IncludeKind, Category> categories = new HashMap<>();
private TreeListDialogField<Category> categoryTree;
private PixelConverter pixelConverter;
private StackLayout editorAreaStack;
private Category selectedCategory;
public IncludeCategoriesBlock(IStatusChangeListener context, IProject project,
IWorkbenchPreferenceContainer container, List<IncludeGroupStyle> styles) {
super(context, project, new Key[0], container);
this.styles = styles;
createCategories();
}
private void createCategories() {
createCategory(IncludeKind.RELATED);
createCategory(IncludeKind.PARTNER);
createCategory(IncludeKind.IN_SAME_FOLDER);
createCategory(IncludeKind.IN_SUBFOLDER);
createCategory(IncludeKind.SYSTEM);
createCategory(IncludeKind.SYSTEM_WITH_EXTENSION);
createCategory(IncludeKind.SYSTEM_WITHOUT_EXTENSION);
createCategory(IncludeKind.OTHER);
createCategory(IncludeKind.IN_SAME_PROJECT);
createCategory(IncludeKind.IN_OTHER_PROJECT);
createCategory(IncludeKind.EXTERNAL);
}
private Category createCategory(IncludeKind includeKind) {
Category parentCategory = categories.get(includeKind.parent);
Category category = new Category(includeKind, parentCategory);
categories.put(category.getIncludeKind(), category);
return category;
}
public void postSetSelection(Object element) {
categoryTree.postSetSelection(new StructuredSelection(element));
}
@Override
protected Control createContents(Composite parent) {
pixelConverter = new PixelConverter(parent);
setShell(parent.getShell());
Composite composite = new Composite(parent, SWT.NONE);
composite.setFont(parent.getFont());
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
composite.setLayout(layout);
IncludeStyleAdapter adapter = new IncludeStyleAdapter();
categoryTree = new TreeListDialogField<>(adapter, null, new IncludeStyleLabelProvider());
categoryTree.setDialogFieldListener(adapter);
categoryTree.setLabelText(PreferencesMessages.IncludeCategoriesBlock_header_categories);
categoryTree.setViewerComparator(adapter);
for (Category category : categories.values()) {
if (category.parent == null)
categoryTree.addElement(category);
}
Label label = categoryTree.getLabelControl(composite);
label.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false));
Control tree = categoryTree.getTreeControl(composite);
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
gd.widthHint = pixelConverter.convertWidthInCharsToPixels(50);
gd.heightHint = pixelConverter.convertHeightInCharsToPixels(2);
tree.setLayoutData(gd);
createCategoryEditors(composite);
categoryTree.setTreeExpansionLevel(2);
categoryTree.selectFirstElement();
updateControls();
return composite;
}
private void createCategoryEditors(Composite parent) {
Composite editorArea = new Composite(parent, SWT.NONE);
editorArea.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
editorArea.setFont(parent.getFont());
editorAreaStack = new StackLayout();
editorArea.setLayout(editorAreaStack);
Map<IncludeKind, IncludeGroupStyle> stylesByKind = new HashMap<>();
for (IncludeGroupStyle style : styles) {
if (style.getIncludeKind() != IncludeKind.MATCHING_PATTERN)
stylesByKind.put(style.getIncludeKind(), style);
}
for (Category category : categories.values()) {
IncludeGroupStyleBlock block = new IncludeGroupStyleBlock(fContext, fProject, fContainer,
category.getDescription());
IncludeGroupStyle style = stylesByKind.get(category.getIncludeKind());
block.setStyle(style);
Control composite = block.createContents(editorArea);
category.setEditor(block, composite);
}
}
@Override
protected void updateControls() {
super.updateControls();
// Refresh
categoryTree.refresh();
updateConfigurationBlock(categoryTree.getSelectedElements());
for (Category category : categories.values()) {
category.getEditor().updateControls();
}
}
private void updateConfigurationBlock(List<Object> selection) {
if (selection.size() == 0)
return;
selectedCategory = (Category) selection.get(0);
editorAreaStack.topControl = selectedCategory.getEditorArea();
editorAreaStack.topControl.getParent().layout();
}
@Override
protected void validateSettings(Key changedKey, String oldValue, String newValue) {
fContext.statusChanged(new StatusInfo());
}
/**
* Represents a category of settings.
*/
private final static class Category {
public final Category parent;
public final int index; // Index in the siblings list
private final List<Category> children;
private final IncludeKind includeKind;
private Control editorArea;
private IncludeGroupStyleBlock editor;
Category(IncludeKind includeKind, Category parent) {
this.includeKind = includeKind;
this.parent = parent;
children = new ArrayList<>();
index = parent != null ? parent.addChild(this) : 0;
}
private int addChild(Category category) {
children.add(category);
return children.size() - 1;
}
Category[] getChildren() {
return children.toArray(new Category[children.size()]);
}
boolean hasChildren() {
return !children.isEmpty();
}
@Override
public String toString() {
return includeKind.name;
}
IncludeKind getIncludeKind() {
return includeKind;
}
IncludeGroupStyleBlock getEditor() {
return editor;
}
Control getEditorArea() {
return editorArea;
}
void setEditor(IncludeGroupStyleBlock editor, Control editorArea) {
this.editor = editor;
this.editorArea = editorArea;
}
String getName() {
return includeKind.name;
}
String getDescription() {
return includeKind.description;
}
}
private class IncludeStyleAdapter extends ViewerComparator
implements ITreeListAdapter<Category>, IDialogFieldListener {
@Override
public void selectionChanged(TreeListDialogField<Category> field) {
updateConfigurationBlock(field.getSelectedElements());
}
@Override
public void customButtonPressed(TreeListDialogField<Category> field, int index) {
}
@Override
public void doubleClicked(TreeListDialogField<Category> field) {
}
@Override
public Category[] getChildren(TreeListDialogField<Category> field, Object element) {
return ((Category) element).getChildren();
}
@Override
public Category getParent(TreeListDialogField<Category> field, Object element) {
return ((Category) element).parent;
}
@Override
public boolean hasChildren(TreeListDialogField<Category> field, Object element) {
return ((Category) element).hasChildren();
}
@Override
public void dialogFieldChanged(DialogField field) {
}
@Override
public void keyPressed(TreeListDialogField<Category> field, KeyEvent event) {
}
@Override
public int category(Object element) {
return ((Category) element).index;
}
}
private static class IncludeStyleLabelProvider extends LabelProvider {
@Override
public Image getImage(Object element) {
return null;
}
@Override
public String getText(Object element) {
return ((Category) element).getName();
}
}
}