/******************************************************************************* * Copyright (c) 2005, 2010 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 *******************************************************************************/ package org.eclipse.cdt.managedbuilder.ui.properties; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.cdtvariables.CdtVariableException; import org.eclipse.cdt.core.cdtvariables.ICdtVariable; import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager; import org.eclipse.cdt.core.cdtvariables.ICdtVariableStatus; import org.eclipse.cdt.core.cdtvariables.IStorableCdtVariables; import org.eclipse.cdt.core.cdtvariables.IUserVarSupplier; import org.eclipse.cdt.core.model.util.CDTListComparator; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICMultiItemsHolder; import org.eclipse.cdt.core.settings.model.ICResourceDescription; import org.eclipse.cdt.managedbuilder.internal.ui.Messages; import org.eclipse.cdt.ui.newui.AbstractCPropertyTab; import org.eclipse.cdt.ui.newui.AbstractPage; import org.eclipse.cdt.ui.newui.CDTPrefUtil; import org.eclipse.cdt.ui.newui.PrefPage_Abstract; import org.eclipse.cdt.ui.newui.StringListModeControl; import org.eclipse.cdt.utils.cdtvariables.CdtVariableResolver; import org.eclipse.cdt.utils.envvar.EnvVarOperationProcessor; import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.JFacePreferences; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.ColumnLayoutData; import org.eclipse.jface.viewers.ColumnPixelData; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IColorProvider; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.IFontProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITableFontProvider; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableLayout; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; 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.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; /** * displays the build macros for the given context * * @noextend This class is not intended to be subclassed by clients. * @noinstantiate This class is not intended to be instantiated by clients. */ public class CPropertyVarsTab extends AbstractCPropertyTab { private static final String VALUE_DELIMITER = " || "; //$NON-NLS-1$ private static final ICdtVariableManager vmgr = CCorePlugin.getDefault().getCdtVariableManager(); private static final IUserVarSupplier fUserSup = CCorePlugin.getUserVarSupplier(); private static final EnvCmp comparator = new EnvCmp(); private ICConfigurationDescription cfgd = null; private IStorableCdtVariables prefvars = null; //currently the "CWD" and "PWD" macros are not displayed in UI private static final String fHiddenMacros[] = new String[]{ "CWD", //$NON-NLS-1$ "PWD" //$NON-NLS-1$ }; private boolean fShowSysMacros = false; private Set<String> fIncorrectlyDefinedMacrosNames = new HashSet<String>(); private TableViewer tv; private Label fStatusLabel; private StringListModeControl stringListModeControl; private static final String[] fEditableTableColumnProps = new String[] { "editable name", //$NON-NLS-1$ "editable type", //$NON-NLS-1$ "editable value", //$NON-NLS-1$ }; private static final String[] fTableColumnNames = new String[] { Messages.MacrosBlock_label_header_name, Messages.MacrosBlock_label_header_type, Messages.MacrosBlock_label_header_value, }; private static final ColumnLayoutData[] fTableColumnLayouts = {new ColumnPixelData(100), new ColumnPixelData(100), new ColumnPixelData(250)}; private class MacroContentProvider implements IStructuredContentProvider{ public Object[] getElements(Object inputElement) { return (Object[])inputElement; } public void dispose() { } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {} } private class MacroLabelProvider extends LabelProvider implements ITableLabelProvider, IFontProvider , ITableFontProvider, IColorProvider{ @Override public Image getImage(Object element) { return null; } @Override public String getText(Object element) { return getColumnText(element, 0); } public Font getFont(Object element) { return getFont(element, 0); } public Image getColumnImage(Object element, int columnIndex) { return null; } public Color getBackground(Object element){ ICdtVariable var = (ICdtVariable)element; if(isUserVar(var)) return BACKGROUND_FOR_USER_VAR; return null; } public String getColumnText(Object element, int columnIndex) { ICdtVariable var = (ICdtVariable)element; switch(columnIndex){ case 0: return var.getName(); case 1: switch(var.getValueType()){ case ICdtVariable.VALUE_PATH_FILE: return Messages.MacrosBlock_label_type_path_file; case ICdtVariable.VALUE_PATH_FILE_LIST: return Messages.MacrosBlock_label_type_path_file_list; case ICdtVariable.VALUE_PATH_DIR: return Messages.MacrosBlock_label_type_path_dir; case ICdtVariable.VALUE_PATH_DIR_LIST: return Messages.MacrosBlock_label_type_path_dir_list; case ICdtVariable.VALUE_PATH_ANY: return Messages.MacrosBlock_label_type_path_any; case ICdtVariable.VALUE_PATH_ANY_LIST: return Messages.MacrosBlock_label_type_path_any_list; case ICdtVariable.VALUE_TEXT: return Messages.MacrosBlock_label_type_text; case ICdtVariable.VALUE_TEXT_LIST: return Messages.MacrosBlock_label_type_text_list; default: return "? " + var.getValueType(); //$NON-NLS-1$ } case 2: return getString(var); } return EMPTY_STR; } public Font getFont(Object element, int columnIndex) { ICdtVariable var = (ICdtVariable)element; if(columnIndex == 0 && isUserVar(var)) return JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT); return null; } public Color getForeground(Object element){ if(fIncorrectlyDefinedMacrosNames.contains(((ICdtVariable)element).getName())) return JFaceResources.getColorRegistry().get(JFacePreferences.ERROR_COLOR); return null; } } /* * called when the user macro selection was changed */ private void handleSelectionChanged(SelectionChangedEvent event){ updateButtons(); } @Override protected void updateButtons() { Object[] obs = ((IStructuredSelection)tv.getSelection()).toArray(); boolean canEdit = false; boolean canDel = false; if (obs != null && obs.length > 0) { canEdit = (obs.length == 1); for (int i=0; i<obs.length; i++) { if (obs[i] instanceof ICdtVariable && isUserVar((ICdtVariable)obs[i])) { canDel = true; break; } } } buttonSetEnabled(1, canEdit); buttonSetEnabled(2, canDel); } /* * called when a custom button was pressed */ @Override public void buttonPressed(int index){ switch(index){ case 0: handleAddButton(); break; case 1: handleEditButton(); break; case 2: handleDelButton(); break; } tv.getTable().setFocus(); } private void replaceMacros() { if (!page.isMultiCfg() || cfgd == null || CDTPrefUtil.getMultiCfgStringListWriteMode() != CDTPrefUtil.WMODE_REPLACE) return; ICdtVariable[] vars = getVariables(); for (int i=0; i<vars.length; i++) if (!isUserVar(vars[i])) vars[i] = null; for (ICConfigurationDescription c : getCfs()) { fUserSup.deleteAll(c); for (ICdtVariable macro : vars) if (macro != null) fUserSup.createMacro(macro, c); } } private ICConfigurationDescription[] getCfs() { if (cfgd instanceof ICMultiItemsHolder) return (ICConfigurationDescription[]) ((ICMultiItemsHolder)cfgd).getItems(); else return new ICConfigurationDescription[] {cfgd}; } private void addOrEdit(ICdtVariable macro, boolean forAll) { if( ! canCreate(macro)) return; if (cfgd != null) { if (forAll) { for (ICConfigurationDescription c : page.getCfgsEditable()) fUserSup.createMacro(macro, c); } else { if (page.isMultiCfg() && cfgd instanceof ICMultiItemsHolder) { for (ICConfigurationDescription c : getCfs()) fUserSup.createMacro(macro, c); replaceMacros(); } else fUserSup.createMacro(macro, cfgd); } } else if (chkVars()) prefvars.createMacro(macro); updateData(); } private void handleAddButton() { NewVarDialog dlg = new NewVarDialog(usercomp.getShell(), null, cfgd, getVariables()); if(dlg.open() == Dialog.OK) addOrEdit(dlg.getDefinedMacro(), dlg.isForAllCfgs); } private void handleEditButton() { ICdtVariable _vars[] = getSelectedUserMacros(); if(_vars != null && _vars.length == 1){ NewVarDialog dlg = new NewVarDialog(usercomp.getShell() ,_vars[0], cfgd, getVariables()); if(dlg.open() == Dialog.OK) addOrEdit(dlg.getDefinedMacro(), false); } } private void handleDelButton() { ICdtVariable macros[] = getSelectedUserMacros(); if(macros != null && macros.length > 0){ if(MessageDialog.openQuestion(usercomp.getShell(), Messages.MacrosBlock_label_delete_confirm_title, Messages.MacrosBlock_label_delete_confirm_message)){ for(int i = 0; i < macros.length; i++){ if (cfgd != null) { if (page.isMultiCfg() && cfgd instanceof ICMultiItemsHolder) { ICConfigurationDescription[] cfs = (ICConfigurationDescription[])((ICMultiItemsHolder)cfgd).getItems(); for (int k=0; k<cfs.length; k++) fUserSup.deleteMacro(macros[i].getName(), cfs[k]); replaceMacros(); } else fUserSup.deleteMacro(macros[i].getName(), cfgd); } else if (chkVars()) prefvars.deleteMacro(macros[i].getName()); } updateData(); } } } /* * returnes the selected user-defined macros */ @SuppressWarnings("unchecked") private ICdtVariable[] getSelectedUserMacros(){ if(tv == null) return null; List<ICdtVariable> list = ((IStructuredSelection)tv.getSelection()).toList(); return list.toArray(new ICdtVariable[list.size()]); } /* (non-Javadoc) * @see org.eclipse.cdt.ui.dialogs.ICOptionPage#performDefaults() */ @Override protected void performDefaults() { if(MessageDialog.openQuestion(usercomp.getShell(), Messages.MacrosBlock_label_delete_all_confirm_title, Messages.MacrosBlock_label_delete_all_confirm_message)){ if (cfgd != null) { if (page.isMultiCfg() && cfgd instanceof ICMultiItemsHolder) { ICConfigurationDescription[] cfs = (ICConfigurationDescription[])((ICMultiItemsHolder)cfgd).getItems(); for (int i=0; i<cfs.length; i++) fUserSup.deleteAll(cfs[i]); } else fUserSup.deleteAll(cfgd); } else if (chkVars()) prefvars.deleteAll(); updateData(); } } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite) */ @Override public void createControls(Composite parent) { super.createControls(parent); initButtons(new String[] {ADD_STR, EDIT_STR, DEL_STR}); usercomp.setLayout(new GridLayout(2, true)); createTableControl(); // Create a "show parent levels" button final Button b = new Button(usercomp, SWT.CHECK); b.setFont(usercomp.getFont()); b.setText(Messages.CPropertyVarsTab_0); b.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); b.setSelection(fShowSysMacros); b.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { fShowSysMacros = b.getSelection(); updateData(getResDesc()); } }); stringListModeControl = new StringListModeControl(page, usercomp, 1); stringListModeControl.addListener(SWT.Selection, new Listener() { public void handleEvent(Event event) { updateData(); } }); fStatusLabel = new Label(usercomp, SWT.LEFT); fStatusLabel.setFont(usercomp.getFont()); fStatusLabel.setText(EMPTY_STR); fStatusLabel.setLayoutData(new GridData(GridData.BEGINNING)); fStatusLabel.setForeground(JFaceResources.getColorRegistry().get(JFacePreferences.ERROR_COLOR)); } private void createTableControl(){ TableViewer tableViewer; tableViewer = new TableViewer(usercomp, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION); Table table = tableViewer.getTable(); TableLayout tableLayout = new TableLayout(); for (int i = 0; i < fTableColumnNames.length; i++) { tableLayout.addColumnData(fTableColumnLayouts[i]); TableColumn tc = new TableColumn(table, SWT.NONE, i); tc.setResizable(fTableColumnLayouts[i].resizable); tc.setText(fTableColumnNames[i]); } table.setLayout(tableLayout); table.setHeaderVisible(true); table.setLinesVisible(true); tableViewer.setContentProvider(new MacroContentProvider()); tableViewer.setLabelProvider(new MacroLabelProvider()); tableViewer.setSorter(new ViewerSorter()); tableViewer.setColumnProperties(fEditableTableColumnProps); tv = tableViewer; tableViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { handleSelectionChanged(event); } }); tableViewer.addDoubleClickListener(new IDoubleClickListener() { public void doubleClick(DoubleClickEvent event) { if (!tv.getSelection().isEmpty()) { buttonPressed(1); } } }); table.addKeyListener(new KeyListener(){ public void keyPressed(KeyEvent e){ if(e.keyCode == SWT.DEL) buttonPressed(2); } public void keyReleased(KeyEvent e){} }); GridData gd = new GridData(GridData.FILL_BOTH); gd.horizontalSpan = 2; table.setLayoutData(gd); } /* * answers whether the macro of a given name can be sreated */ private boolean canCreate(ICdtVariable v){ if (v == null) return false; String name = v.getName(); if(name == null || (name = name.trim()).length() == 0) return false; if(fHiddenMacros != null){ for(int i = 0; i < fHiddenMacros.length; i++){ if(fHiddenMacros[i].equals(EnvVarOperationProcessor.normalizeName(name))) return false; } } return true; } @Override public void updateData(ICResourceDescription _cfgd) { if (_cfgd == null) { cfgd = null; chkVars(); } else { cfgd = _cfgd.getConfiguration(); prefvars = null; } updateData(); } private boolean chkVars() { if (prefvars == null) prefvars = fUserSup.getWorkspaceVariablesCopy(); return (prefvars != null); } private void checkVariableIntegrity() { try{ if (page.isMultiCfg() && cfgd instanceof ICMultiItemsHolder) { ICConfigurationDescription[] cfs = (ICConfigurationDescription[])((ICMultiItemsHolder)cfgd).getItems(); for (int i=0; i<cfs.length; i++) vmgr.checkVariableIntegrity(cfs[i]); } else vmgr.checkVariableIntegrity(cfgd); updateState(null); } catch (CdtVariableException e){ updateState(e); } } private ICdtVariable[] getVariables() { if (page.isMultiCfg() && cfgd instanceof ICMultiItemsHolder) { ICMultiItemsHolder mih = (ICMultiItemsHolder)cfgd; ICConfigurationDescription[] cfs = (ICConfigurationDescription[])mih.getItems(); ICdtVariable[][] vs = new ICdtVariable[cfs.length][]; for (int i=0; i<cfs.length; i++) vs[i] = vmgr.getVariables(cfs[i]); Object[] obs = CDTPrefUtil.getListForDisplay(vs, comparator); ICdtVariable[] v = new ICdtVariable[obs.length]; System.arraycopy(obs, 0, v, 0, obs.length); return v; } else return vmgr.getVariables(cfgd); } private void updateData() { if(tv == null) return; checkVariableIntegrity(); // get variables ICdtVariable[] _vars = getVariables(); if (_vars == null) return; stringListModeControl.updateStringListModeControl(); if (cfgd == null) { chkVars(); if (fShowSysMacros) { List<ICdtVariable> lst = new ArrayList<ICdtVariable>(_vars.length); ICdtVariable[] uvars = prefvars.getMacros(); for (int i=0; i<uvars.length; i++) { lst.add(uvars[i]); for (int j=0; j<_vars.length; j++) { if (_vars[j] != null && _vars[j].getName().equals(uvars[i].getName())) { _vars[j] = null; break; } } } // add system vars not rewritten by user's for (int j=0; j<_vars.length; j++) { if (_vars[j] != null && !vmgr.isUserVariable(_vars[j], null)) lst.add(_vars[j]); } _vars = lst.toArray(new ICdtVariable[lst.size()]); } else { _vars = prefvars.getMacros(); } } ArrayList<ICdtVariable> list = new ArrayList<ICdtVariable>(_vars.length); for(int i = 0; i < _vars.length; i++){ if(_vars[i] != null && (fShowSysMacros || isUserVar(_vars[i]))) list.add(_vars[i]); } Collections.sort(list, CDTListComparator.getInstance()); tv.setInput(list.toArray(new ICdtVariable[list.size()])); updateButtons(); } private void updateState(CdtVariableException e){ fIncorrectlyDefinedMacrosNames.clear(); if(e != null){ fStatusLabel.setText(e.getMessage()); fStatusLabel.setVisible(true); ICdtVariableStatus statuses[] = e.getVariableStatuses(); for(int i = 0; i < statuses.length; i++){ String name = statuses[i].getVariableName(); if(name != null) fIncorrectlyDefinedMacrosNames.add(name); } } else fStatusLabel.setVisible(false); } /** * Checks whether variable is user's. * @param v - variable to check. * @return {@code true} if the variable is user's or {@code false} otherwise. */ private boolean isUserVar(ICdtVariable v) { if (cfgd == null) return chkVars() && prefvars.contains(v); if (page.isMultiCfg() && cfgd instanceof ICMultiItemsHolder) { ICConfigurationDescription[] cfs = (ICConfigurationDescription[])((ICMultiItemsHolder)cfgd).getItems(); for (int i=0; i<cfs.length; i++) if (vmgr.isUserVariable(v, cfs[i])) return true; return false; } else return vmgr.isUserVariable(v, cfgd); } private String getString(ICdtVariable v) { if (fUserSup.isDynamic(v)) return Messages.MacrosBlock_label_value_eclipse_dynamic; String value = EMPTY_STR; try { if (CdtVariableResolver.isStringListVariable(v.getValueType())) value = vmgr.convertStringListToString(v.getStringListValue(), VALUE_DELIMITER); else value = v.getStringValue(); } catch (CdtVariableException e1) {} return value; } @Override protected void performApply(ICResourceDescription src, ICResourceDescription dst) { if (cfgd != null) {// only for project, not for prefs if (page.isMultiCfg()) { if (src instanceof ICMultiItemsHolder && dst instanceof ICMultiItemsHolder) { ICMultiItemsHolder s = (ICMultiItemsHolder)src; ICMultiItemsHolder d = (ICMultiItemsHolder)dst; ICResourceDescription[] r0 = (ICResourceDescription[])s.getItems(); ICResourceDescription[] r1 = (ICResourceDescription[])d.getItems(); if (r0.length != r1.length) return; // unprobable for (int i=0; i<r0.length; i++) { ICdtVariable[] vs = fUserSup.getMacros(r0[i].getConfiguration()); fUserSup.setMacros(vs, r1[i].getConfiguration()); } } } else { ICdtVariable[] vs = fUserSup.getMacros(src.getConfiguration()); fUserSup.setMacros(vs, dst.getConfiguration()); } } else if (chkVars()) fUserSup.storeWorkspaceVariables(true); } /** * Unlike other pages, workspace variables * should be stored explicitly on "OK". */ @Override protected void performOK() { if (chkVars()) try { if (fUserSup.setWorkspaceVariables(prefvars)) if (page instanceof PrefPage_Abstract) PrefPage_Abstract.isChanged = true; } catch (CoreException e) {} prefvars = null; super.performOK(); } @Override protected void performCancel() { prefvars = null; super.performCancel(); } // This page can be displayed for project only @Override public boolean canBeVisible() { return page.isForProject() || page.isForPrefs(); } private static class EnvCmp implements Comparator<Object> { public int compare(Object a0, Object a1) { if (a0 == null || a1 == null) return 0; if (a0 instanceof ICdtVariable && a1 instanceof ICdtVariable) { ICdtVariable x0 = (ICdtVariable)a0; ICdtVariable x1 = (ICdtVariable)a1; String s0 = x0.getName(); if (s0 == null) s0 = AbstractPage.EMPTY_STR; String s1 = x1.getName(); if (s1 == null) s1 = AbstractPage.EMPTY_STR; return(s0.compareTo(s1)); } else return 0; } } }