/******************************************************************************* * Copyright (c) 2007, 2009 Intel Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Intel Corporation - initial API and implementation * IBM Corporation * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.ui.newui; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IProject; import org.eclipse.swt.SWT; import org.eclipse.swt.accessibility.AccessibleAdapter; import org.eclipse.swt.accessibility.AccessibleEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.TreeEvent; import org.eclipse.swt.events.TreeListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICResourceDescription; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.internal.ui.newui.Messages; /** * @noextend This class is not intended to be subclassed by clients. */ public class RefsTab extends AbstractCPropertyTab { /** gray colour for 'disabled' items */ private final Color GRAY_COLOR = new Color(Display.getDefault(), 100, 100, 100); public Composite comp; private Tree tree; static private final String ACTIVE = "[" + Messages.RefsTab_Active + "]"; //$NON-NLS-1$ //$NON-NLS-2$ private static final int EXPAND_ALL_BUTTON = 0; private static final int COLLAPSE_ALL_BUTTON = 1; private static final int MOVEUP_BUTTON = 3; private static final int MOVEDOWN_BUTTON = 4; @Override public void createControls(Composite parent) { super.createControls(parent); initButtons(new String[] { Messages.RefsTab_ExpandAll, Messages.RefsTab_CollapseAll, null, MOVEUP_STR, MOVEDOWN_STR}, 120); usercomp.setLayout(new GridLayout(1, false)); tree = new Tree(usercomp, SWT.SINGLE | SWT.CHECK | SWT.BORDER); tree.setLayoutData(new GridData(GridData.FILL_BOTH)); tree.getAccessible().addAccessibleListener( new AccessibleAdapter() { @Override public void getName(AccessibleEvent e) { e.result = Messages.RefsTab_ProjectsList; } } ); // Populate the tree initData(); tree.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if ((e.detail & SWT.CHECK) == SWT.CHECK && e.item != null && (e.item instanceof TreeItem)) { TreeItem sel = (TreeItem)e.item; Object data = sel.getData(); // If data is not a configuration ID, then the user isn't allowed to select this... if (data == null) { sel.setChecked(false); return; } boolean checked = sel.getChecked(); TreeItem parent = sel.getParentItem(); if (parent == null) { // Project -- top-level item -- selected if (checked) sel.setExpanded(true); for (TreeItem child : sel.getItems()) { if (checked) { // Don't select a non-allowed configuration if (child.getData() != null) { child.setChecked(true); break; } } else child.setChecked(false); } } else { // Configuration selected (it has a parent) if (parent.getChecked()) { // Deselect other configs already selected for (TreeItem obj : parent.getItems()) obj.setChecked(false); sel.setChecked(checked); } parent.setChecked(checked); } // Save the checked configurations saveChecked(); } updateButtons(); } }); tree.addTreeListener(new TreeListener() { public void treeCollapsed(TreeEvent e) { updateExpandButtons(e, false, true); } public void treeExpanded(TreeEvent e) { updateExpandButtons(e, true, false); }}); } @Override public void buttonPressed(int n) { switch (n) { case COLLAPSE_ALL_BUTTON: case EXPAND_ALL_BUTTON: for (TreeItem item : tree.getItems()) item.setExpanded(n==EXPAND_ALL_BUTTON); updateButtons(); break; case MOVEUP_BUTTON: case MOVEDOWN_BUTTON: // TODO cache this... Map<String, String> oldMapping = getResDesc().getConfiguration().getReferenceInfo(); TreeItem ti = tree.getSelection()[0]; String projectName = ti.getText(); List<String> projNames = new ArrayList<String>(oldMapping.keySet()); int index = projNames.indexOf(projectName); if (n == MOVEUP_BUTTON) { if (index > 0) { projNames.set(index, projNames.get(index - 1)); projNames.set(index - 1, projectName); } } else { if (index < projNames.size() - 1) { projNames.set(index, projNames.get(index + 1)); projNames.set(index + 1, projectName); } } Map<String, String> newMapping = new LinkedHashMap<String, String>(oldMapping.size()); for (String name : projNames) newMapping.put(name, oldMapping.get(name)); getResDesc().getConfiguration().setReferenceInfo(newMapping); initData(); break; } } @Override protected void updateData(ICResourceDescription cfgd) { if (page.isMultiCfg()) { setAllVisible(false, null); } else { if (!usercomp.isVisible()) setAllVisible(true, null); initData(); } } /** * Persist the checked configurations */ private void saveChecked() { Map<String, String> refs = new LinkedHashMap<String, String>(); for (TreeItem project : tree.getItems()) { if (project.getChecked()) { if (project.getData() instanceof String) { assert(project.getData() != null); // Project is missing from the workspace, maintain references refs.put(project.getText(), (String)project.getData()); } else { for (TreeItem config : project.getItems()) { if (config.getChecked()) { assert(config.getData() != null); refs.put(project.getText(), (String)config.getData()); break; // only one configuration can be selected a time in a project } } } } } getResDesc().getConfiguration().setReferenceInfo(refs); } /** * Initialises the tree. * * TreeItems are either * TI: Text , Data * {IProject.getName()} , {IProject} * {cfgName} , {String cfgId} * {cfgName} , {null} // config is not allowed to be selected * * If the projects doesn't exist in the workspace: * {IProject.getName()} , {String cfgId} * */ private void initData() { // Persist the current select / expand state to restore... String currentSelection = tree.getSelectionCount() == 1 ? tree.getSelection()[0].getText() : null; Set<String> currentExpanded = new HashSet<String>(); for (TreeItem ti : tree.getItems()) if (ti.getExpanded()) currentExpanded.add(ti.getText()); tree.removeAll(); IProject p = page.getProject(); if (p == null) return; // Get all the CDT references Map<String,String> refs = getResDesc().getConfiguration().getReferenceInfo(); // Preserve project order. All linked to projects occur before others Set<String> projects = new LinkedHashSet<String>(refs.keySet()); for (IProject prj : p.getWorkspace().getRoot().getProjects()) projects.add(prj.getName()); for (String pname : projects) { // The referenced configuration ID String ref = refs.get(pname); IProject prj; ICConfigurationDescription[] cfgs; try { prj = p.getWorkspace().getRoot().getProject(pname); cfgs = page.getCfgsReadOnly(prj); } catch (Exception e) { CUIPlugin.log(Messages.RefsTab_ConfigurationsAccessError+pname, e); continue; } if (cfgs == null || cfgs.length == 0) { // If the project is referenced, then make sure the user knows about it! if (ref != null) { TreeItem ti = new TreeItem(tree, SWT.NONE); ti.setChecked(true); ti.setText(pname); ti.setData(refs.get(pname)); ti.setForeground(GRAY_COLOR); } continue; } // Only show the current project if it's got more than 1 configuration if (page.getProject().equals(prj) && cfgs.length < 2) continue; // Add the project TreeItem ti = new TreeItem(tree, SWT.NONE); ti.setText(pname); ti.setData(prj); if (ref != null) ti.setChecked(true); // Add the configurations TreeItem ti1; if (!prj.equals(p)) { // [ Active ] config in the tree ti1 = new TreeItem(ti, SWT.NONE); ti1.setText(ACTIVE); ti1.setData(EMPTY_STR); if (EMPTY_STR.equals(ref)) { ti1.setChecked(true); ti1.setData(ref); } } // Name configurations in the tree for (ICConfigurationDescription cfg : cfgs) { // Don't include self configuration ti1 = new TreeItem(ti, SWT.NONE); ti1.setText(cfg.getName()); if (prj.equals(p) && cfg.getId().equals(page.getResDesc().getConfiguration().getId())) { // users may *only* reference other configuration in the project // this data is deliberately null as it may not be selected... ti1.setForeground(GRAY_COLOR); continue; } else if (cfg.getId().equals(ref)) ti1.setChecked(true); ti1.setData(cfg.getId()); } } // Reselect / Re-expand previously selected & expanded items if (currentSelection != null) for (TreeItem ti : tree.getItems()) if (ti.getText().equals(currentSelection)) { tree.setSelection(ti); break; } for (TreeItem ti : tree.getItems()) if (currentExpanded.contains(ti.getText())) ti.setExpanded(true); updateButtons(); } @Override protected void performApply(ICResourceDescription src, ICResourceDescription dst) { dst.getConfiguration().setReferenceInfo(src.getConfiguration().getReferenceInfo()); } // This page can be displayed for project only @Override public boolean canBeVisible() { return page.isForProject(); } @Override protected void performDefaults() { if (!usercomp.isVisible()) return; getResDesc().getConfiguration().setReferenceInfo(new HashMap<String, String>()); initData(); } @Override protected void updateButtons() { updateExpandButtons(null, false, false); updateMoveButtons(); } @Override public void dispose() { super.dispose(); GRAY_COLOR.dispose(); } private void updateExpandButtons(TreeEvent e, boolean stateE, boolean stateC) { boolean cntE = stateE; boolean cntC = stateC; for (TreeItem item : tree.getItems()) { if (e != null && e.widget.equals(item)) continue; if (item.getExpanded()) cntE = true; else cntC = true; } buttonSetEnabled(EXPAND_ALL_BUTTON, cntC); // Expand All buttonSetEnabled(COLLAPSE_ALL_BUTTON, cntE); // Collapse all } /** * Make the move buttons enabled when a project is selected */ private void updateMoveButtons() { if (tree.getSelectionCount() == 1) { TreeItem ti = tree.getSelection()[0]; // Is a project selected? if (ti.getParentItem() == null && ti.getChecked()) { int index = tree.indexOf(ti); buttonSetEnabled(MOVEUP_BUTTON, index > 0); buttonSetEnabled(MOVEDOWN_BUTTON, index < tree.getItemCount() - 1); return; } } buttonSetEnabled(MOVEUP_BUTTON, false); buttonSetEnabled(MOVEDOWN_BUTTON, false); } }