/******************************************************************************* * Copyright (c) 2010, 2013 Andrew Gvozdev 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: * Andrew Gvozdev - Initial API and implementation * Tom Hochstein (Freescale) - Bug 412601 - Preprocessor Entries properties tab should list languages * Serge Beauchamp (Freescale Semiconductor) - Bug 406545 *******************************************************************************/ package org.eclipse.cdt.internal.ui.language.settings.providers; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.viewers.IDecoration; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; 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.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsBroadcastingProvider; import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsEditableProvider; import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider; import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvidersKeeper; import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsBaseProvider; import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager; import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport; import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.LanguageManager; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; import org.eclipse.cdt.core.settings.model.ICResourceDescription; import org.eclipse.cdt.core.settings.model.ICSettingEntry; import org.eclipse.cdt.core.settings.model.util.CDataUtil; import org.eclipse.cdt.ui.CDTSharedImages; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.newui.AbstractCPropertyTab; import org.eclipse.cdt.internal.ui.newui.Messages; import org.eclipse.cdt.internal.ui.newui.StatusMessageLine; /** * This tab presents language settings entries categorized by language * settings providers. * * @noinstantiate This class is not intended to be instantiated by clients. * @noextend This class is not intended to be subclassed by clients. */ public class LanguageSettingsEntriesTab extends AbstractCPropertyTab { private static final String EXPORT_STR = Messages.AbstractLangsListTab_Export; private static final String UNEXPORT_STR = Messages.AbstractLangsListTab_Unexport; private static final int[] DEFAULT_ENTRIES_SASH_WEIGHTS = new int[] { 10, 30 }; private SashForm sashFormEntries; private Tree treeLanguages; private Tree treeEntries; private TreeViewer treeEntriesViewer; private String currentLanguageId = null; private static String currentLanguageIdGlobal = null; private Button builtInCheckBox; private StatusMessageLine fStatusLine; private LanguageSettingsProvidersPage masterPropertyPage = null; private static final int BUTTON_ADD = 0; private static final int BUTTON_EDIT = 1; private static final int BUTTON_DELETE = 2; private static final int BUTTON_EXPORT = 3; // there is a separator instead of button #4 private static final int BUTTON_MOVE_UP = 5; private static final int BUTTON_MOVE_DOWN = 6; private static final String[] BUTTON_LABELS = new String[7]; { BUTTON_LABELS[BUTTON_ADD] = ADD_STR; BUTTON_LABELS[BUTTON_EDIT] = EDIT_STR; BUTTON_LABELS[BUTTON_DELETE] = DEL_STR; BUTTON_LABELS[BUTTON_EXPORT] = EXPORT_STR; BUTTON_LABELS[BUTTON_MOVE_UP] = MOVEUP_STR; BUTTON_LABELS[BUTTON_MOVE_DOWN] = MOVEDOWN_STR; } private static final String CLEAR_STR = Messages.LanguageSettingsProviderTab_Clear; private Map<String, List<ILanguageSettingsProvider>> initialProvidersMap = new HashMap<String, List<ILanguageSettingsProvider>>(); /** * Label provider for language settings providers displayed by this tab. */ private class EntriesTreeLabelProvider extends LanguageSettingsProvidersLabelProvider { @Override protected String[] getOverlayKeys(ILanguageSettingsProvider provider) { String[] overlayKeys = super.getOverlayKeys(provider); if (provider.getName() == null) { return overlayKeys; } IResource rc = getResource(); List<ICLanguageSettingEntry> entries = getSettingEntries(provider); if (entries == null && !(rc instanceof IProject)) { List<ICLanguageSettingEntry> entriesParent = getSettingEntriesUpResourceTree(provider); if (entriesParent != null) { overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_PARENT; } } else if (provider instanceof ILanguageSettingsBroadcastingProvider && (page.isForFile() || page.isForFolder())) { // Assuming that the default entries for a resource are always null. // Using that for performance reasons. See note in performDefaults(). List<ICLanguageSettingEntry> entriesParent = provider.getSettingEntries(null, null, currentLanguageId); if (entries != null && !entries.equals(entriesParent)) { overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_SETTING; } } ICConfigurationDescription cfgDescription = getConfigurationDescription(); List<ILanguageSettingsProvider> initialProviders = initialProvidersMap.get(cfgDescription.getId()); if (initialProviders != null && !initialProviders.contains(provider)) { overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_EDITED; } return overlayKeys; } @Override public Image getImage(Object element) { if (element instanceof ICLanguageSettingEntry) { ICConfigurationDescription cfgDescription = getConfigurationDescription(); return LanguageSettingsImages.getImage((ICLanguageSettingEntry) element, cfgDescription); } return super.getImage(element); } @Override public String getText(Object element) { if (element instanceof ICLanguageSettingEntry) { ICLanguageSettingEntry entry = (ICLanguageSettingEntry) element; String text = entry.getName(); if (entry.getKind() == ICSettingEntry.MACRO) { if ((entry.getFlags() & ICSettingEntry.UNDEFINED) == 0) { text = text + '=' + entry.getValue(); } } else if (LanguageSettingsImages.isProjectRelative(entry)) { text = LanguageSettingsImages.toProjectRelative(text); } return text; } return super.getText(element); } } /** * Content provider for setting entries tree. */ private class EntriesTreeContentProvider implements ITreeContentProvider { @Override public Object[] getElements(Object inputElement) { return getChildren(inputElement); } @Override public Object[] getChildren(Object parentElement) { if (parentElement instanceof Object[]) return (Object[]) parentElement; if (parentElement instanceof ILanguageSettingsProvider) { ILanguageSettingsProvider lsProvider = (ILanguageSettingsProvider)parentElement; List<ICLanguageSettingEntry> entriesList = getSettingEntriesUpResourceTree(lsProvider); if (entriesList == null) { return null; } // convert to modifiable list entriesList = new ArrayList<ICLanguageSettingEntry>(entriesList); if (builtInCheckBox.getSelection() == false) { for (Iterator<ICLanguageSettingEntry> iter = entriesList.iterator(); iter.hasNext();) { ICLanguageSettingEntry entry = iter.next(); if (entry.isBuiltIn()) { iter.remove(); } } } return entriesList.toArray(); } return null; } @Override public Object getParent(Object element) { return null; } @Override public boolean hasChildren(Object element) { Object[] children = getChildren(element); return children!=null && children.length>0; } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public void dispose() { } } /** * Shortcut for getting the current resource for the property page. */ private IResource getResource() { return (IResource)page.getElement(); } /** * Shortcut for getting the current configuration description. */ private ICConfigurationDescription getConfigurationDescription() { return getResDesc().getConfiguration(); } /** * Shortcut for getting the currently selected provider. */ private ILanguageSettingsProvider getSelectedProvider() { ILanguageSettingsProvider provider = null; TreeItem[] items = treeEntries.getSelection(); if (items.length == 1) { TreeItem item = items[0]; Object itemData = item.getData(); if (itemData instanceof ICLanguageSettingEntry) { item = item.getParentItem(); if (item != null) { itemData = item.getData(); } } if (itemData instanceof ILanguageSettingsProvider) { provider = (ILanguageSettingsProvider)itemData; } } return provider; } /** * Shortcut for getting the currently selected setting entry. */ private ICLanguageSettingEntry getSelectedEntry() { ICLanguageSettingEntry entry = null; TreeItem[] items = treeEntries.getSelection(); if (items.length == 1) { TreeItem item = items[0]; Object itemData = item.getData(); if (itemData instanceof ICLanguageSettingEntry) { entry = (ICLanguageSettingEntry)itemData; } } return entry; } /** * Shortcut for getting setting entries for current context. {@link LanguageSettingsManager} * will be checking parent resources if no settings defined for current resource. * * @return list of setting entries for the current context. */ private List<ICLanguageSettingEntry> getSettingEntriesUpResourceTree(ILanguageSettingsProvider provider) { ICConfigurationDescription cfgDescription = getConfigurationDescription(); IResource rc = getResource(); List<ICLanguageSettingEntry> entries = LanguageSettingsManager.getSettingEntriesUpResourceTree(provider, cfgDescription, rc, currentLanguageId); return entries; } /** * Shortcut for getting setting entries for current context without checking the parent resource. * @return list of setting entries for the current context. */ private List<ICLanguageSettingEntry> getSettingEntries(ILanguageSettingsProvider provider) { ICConfigurationDescription cfgDescription = getConfigurationDescription(); IResource rc = getResource(); return provider.getSettingEntries(cfgDescription, rc, currentLanguageId); } /** * Store original providers to be able to tell whether they were changed by user. */ private void trackInitialSettings() { if (!page.isForPrefs()) { ICConfigurationDescription[] cfgDescriptions = page.getCfgsEditable(); for (ICConfigurationDescription cfgDescription : cfgDescriptions) { if (cfgDescription instanceof ILanguageSettingsProvidersKeeper) { String cfgId = cfgDescription.getId(); List<ILanguageSettingsProvider> initialProviders = ((ILanguageSettingsProvidersKeeper) cfgDescription).getLanguageSettingProviders(); initialProvidersMap.put(cfgId, initialProviders); } } } } /** * Create UI control for languages. */ private void createTreeForLanguages(Composite parent) { treeLanguages = new Tree(parent, SWT.BORDER | SWT.SINGLE | SWT.H_SCROLL); treeLanguages.setLayoutData(new GridData(GridData.FILL_VERTICAL)); treeLanguages.setHeaderVisible(true); treeLanguages.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { TreeItem[] items = treeLanguages.getSelection(); if (items.length > 0) { currentLanguageId = (String) items[0].getData(); currentLanguageIdGlobal = currentLanguageId; updateTreeForEntries(null, null); } } }); final TreeColumn columnLanguages = new TreeColumn(treeLanguages, SWT.NONE); columnLanguages.setText(Messages.AbstractLangsListTab_Languages); columnLanguages.setWidth(200); columnLanguages.setResizable(false); columnLanguages.setToolTipText(Messages.AbstractLangsListTab_Languages); treeLanguages.addPaintListener(new PaintListener() { @Override public void paintControl(PaintEvent e) { int x = treeLanguages.getBounds().width - 5; if (columnLanguages.getWidth() != x) { columnLanguages.setWidth(x); } } }); } /** * Create tree for providers and their entries. */ private void createTreeForEntries(Composite parent) { treeEntries = new Tree(parent, SWT.BORDER | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL); treeEntries.setLayoutData(new GridData(GridData.FILL_VERTICAL)); treeEntries.setHeaderVisible(true); treeEntries.setLinesVisible(true); final TreeColumn treeCol = new TreeColumn(treeEntries, SWT.NONE); treeEntries.addPaintListener(new PaintListener() { @Override public void paintControl(PaintEvent e) { int x = treeEntries.getClientArea().width; if (treeCol.getWidth() != x) treeCol.setWidth(x); } }); treeCol.setText(Messages.LanguageSettingsProviderTab_SettingEntries); treeCol.setWidth(200); treeCol.setResizable(false); treeCol.setToolTipText(Messages.LanguageSettingsProviderTab_SettingEntriesTooltip); treeEntriesViewer = new TreeViewer(treeEntries); treeEntriesViewer.setContentProvider(new EntriesTreeContentProvider()); treeEntriesViewer.setLabelProvider(new EntriesTreeLabelProvider()); treeEntriesViewer.setUseHashlookup(true); treeEntries.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (treeLanguages.getSelectionCount() == 0) { selectLanguage(currentLanguageId); } updateStatusLine(); updateButtons(); } @Override public void widgetDefaultSelected(SelectionEvent e) { if (buttonIsEnabled(BUTTON_EDIT) && treeEntries.getSelection().length>0) buttonPressed(BUTTON_EDIT); } }); } /** * Create sash form. */ private void createSashForm() { sashFormEntries = new SashForm(usercomp,SWT.HORIZONTAL); GridData gd = new GridData(GridData.FILL_BOTH); gd.horizontalSpan = 2; gd.grabExcessVerticalSpace = true; sashFormEntries.setLayoutData(gd); GridLayout layout = new GridLayout(); sashFormEntries.setLayout(layout); createTreeForLanguages(sashFormEntries); createTreeForEntries(sashFormEntries); sashFormEntries.setWeights(DEFAULT_ENTRIES_SASH_WEIGHTS); } /** * Create check-box to control whether to show built-in entries or not. */ private void createBuiltInsCheckBox() { builtInCheckBox = setupCheck(usercomp, Messages.AbstractLangsListTab_ShowBuiltin, 1, GridData.FILL_HORIZONTAL); builtInCheckBox.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateTreeForEntries(null, null); } }); builtInCheckBox.setSelection(true); builtInCheckBox.setEnabled(true); } @Override public void createControls(Composite parent) { super.createControls(parent); currentLanguageId = null; usercomp.setLayout(new GridLayout()); GridData gd = (GridData) usercomp.getLayoutData(); // Discourage settings entry table from trying to show all its items at once, see bug 264330 gd.heightHint =1; if (page instanceof LanguageSettingsProvidersPage) { masterPropertyPage = (LanguageSettingsProvidersPage) page; } trackInitialSettings(); createSashForm(); fStatusLine = new StatusMessageLine(usercomp, SWT.LEFT, 2); createBuiltInsCheckBox(); enableTabControls(masterPropertyPage.isLanguageSettingsProvidersEnabled()); initButtons(BUTTON_LABELS); updateData(getResDesc()); } /** * Gray out or restore all controls except enabling check-box. */ private void enableTabControls(boolean enable) { sashFormEntries.setEnabled(enable); treeLanguages.setEnabled(enable); treeEntries.setEnabled(enable); builtInCheckBox.setEnabled(enable); buttoncomp.setEnabled(enable); if (enable) { updateTreeForEntries(null, null); } else { buttonSetEnabled(BUTTON_ADD, false); buttonSetEnabled(BUTTON_EDIT, false); buttonSetEnabled(BUTTON_DELETE, false); buttonSetEnabled(BUTTON_EXPORT, false); buttonSetEnabled(BUTTON_MOVE_UP, false); buttonSetEnabled(BUTTON_MOVE_DOWN, false); } } /** * Check if "Export" button is in "Export" mode or "Unexport" mode. */ private boolean isExportMode(ILanguageSettingsProvider provider, ICLanguageSettingEntry entry) { List<ICLanguageSettingEntry> entries = getSettingEntriesUpResourceTree(provider); boolean isAllowedToEdit = provider instanceof ILanguageSettingsEditableProvider && LanguageSettingsProviderAssociationManager.isAllowedToEditEntries(provider); boolean canExport = isAllowedToEdit && entries != null && entries.size() > 0; boolean isExported = false; if (canExport) { if (entry != null) { isExported = (entry.getFlags() & ICSettingEntry.EXPORTED) == ICSettingEntry.EXPORTED; } else if (entries != null) { for (ICLanguageSettingEntry ent : entries) { isExported = (ent.getFlags() & ICSettingEntry.EXPORTED) == ICSettingEntry.EXPORTED; // in case of mixed exports suggest to "Export" if (!isExported) { break; } } } } return !isExported; } /** * Updates state for all buttons. Called when table selection changes. */ @Override protected void updateButtons() { ILanguageSettingsProvider provider = getSelectedProvider(); ICLanguageSettingEntry entry = getSelectedEntry(); List<ICLanguageSettingEntry> entries = getSettingEntriesUpResourceTree(provider); boolean isEntrySelected = (entry != null); boolean isProviderSelected = !isEntrySelected && (provider != null); boolean isAllowedToEdit = provider instanceof ILanguageSettingsEditableProvider && LanguageSettingsProviderAssociationManager.isAllowedToEditEntries(provider); boolean isAllowedToClear = provider instanceof ILanguageSettingsEditableProvider && LanguageSettingsProviderAssociationManager.isAllowedToClear(provider); boolean canAdd = isAllowedToEdit; boolean canEdit = isAllowedToEdit && isEntrySelected; boolean canDelete = isAllowedToEdit && isEntrySelected; boolean canClear = isAllowedToClear && isProviderSelected && entries != null && entries.size() > 0; boolean canExport = isAllowedToEdit && entries != null && entries.size() > 0; boolean suggestExport = isExportMode(provider, entry); boolean canMoveUp = false; boolean canMoveDown = false; if (isAllowedToEdit && isEntrySelected && entries != null) { int last = entries.size() - 1; int pos = getExactIndex(entries, entry); if (pos >= 0 && pos <= last) { canMoveUp = (pos != 0); canMoveDown = (pos != last); } } buttonSetText(BUTTON_DELETE, isProviderSelected ? CLEAR_STR : DEL_STR); buttonSetText(BUTTON_EXPORT, suggestExport ? EXPORT_STR : UNEXPORT_STR); buttonSetEnabled(BUTTON_ADD, canAdd); buttonSetEnabled(BUTTON_EDIT, canEdit); buttonSetEnabled(BUTTON_DELETE, canDelete || canClear); buttonSetEnabled(BUTTON_EXPORT, canExport); buttonSetEnabled(BUTTON_MOVE_UP, canMoveUp); buttonSetEnabled(BUTTON_MOVE_DOWN, canMoveDown); } /** * Displays warning message - if any - for selected language settings entry. */ private void updateStatusLine() { IStatus status=null; if (masterPropertyPage.isLanguageSettingsProvidersEnabled()) { ICConfigurationDescription cfgDescription = getConfigurationDescription(); status = LanguageSettingsImages.getStatus(getSelectedEntry(), cfgDescription); } if (status == null || status == Status.OK_STATUS) { ILanguageSettingsProvider provider = getSelectedProvider(); boolean isAllowedEditing = provider instanceof ILanguageSettingsEditableProvider && LanguageSettingsProviderAssociationManager.isAllowedToEditEntries(provider); if (provider != null && !isAllowedEditing) { status = new Status(IStatus.INFO, CUIPlugin.PLUGIN_ID, Messages.LanguageSettingsEntriesTab_Entries_Not_Editable); } } if (status == null || status == Status.OK_STATUS) { if (treeLanguages.getItemCount() <= 0) { status = new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, Messages.LanguageSettingsEntriesTab_Cannot_Determine_Languages); } } fStatusLine.setErrorStatus(status); } /** * Handle buttons */ @Override public void buttonPressed(int buttonIndex) { ILanguageSettingsProvider selectedProvider = getSelectedProvider(); ICLanguageSettingEntry selectedEntry = getSelectedEntry(); switch (buttonIndex) { case BUTTON_ADD: performAdd(selectedProvider); break; case BUTTON_EDIT: performEdit(selectedProvider, selectedEntry); break; case BUTTON_DELETE: performDelete(selectedProvider, selectedEntry); break; case BUTTON_EXPORT: performExport(selectedProvider, selectedEntry); break; case BUTTON_MOVE_UP: performMoveUp(selectedProvider, selectedEntry); break; case BUTTON_MOVE_DOWN: performMoveDown(selectedProvider, selectedEntry); break; default: } treeEntries.setFocus(); } /** * That method returns exact position of an element in the list. * Note that {@link List#indexOf(Object)} returns position of the first element * equals to the given one, not exact element. * * @param entries * @param entry * @return exact position of the element or -1 of not found. */ private int getExactIndex(List<ICLanguageSettingEntry> entries, ICLanguageSettingEntry entry) { if (entries != null) { for (int i = 0; i < entries.size(); i++) { if (entries.get(i) == entry) return i; } } return -1; } /** * Find TreeItem associated with a provider. */ private TreeItem findProviderItem(String id) { TreeItem[] providerItems = treeEntries.getItems(); for (TreeItem providerItem : providerItems) { Object providerItemData = providerItem.getData(); if (providerItemData instanceof ILanguageSettingsProvider) { ILanguageSettingsProvider provider = (ILanguageSettingsProvider)providerItemData; if (provider.getId().equals(id)) { return providerItem; } } } return null; } /** * Find TreeItem associated with a provider's entry. */ private TreeItem findEntryItem(String providerId, ICLanguageSettingEntry entry) { TreeItem[] providerItems = treeEntries.getItems(); for (TreeItem providerItem : providerItems) { Object providerItemData = providerItem.getData(); if (providerItemData instanceof ILanguageSettingsProvider) { ILanguageSettingsProvider provider = (ILanguageSettingsProvider)providerItemData; if (provider.getId().equals(providerId)) { TreeItem[] entryItems = providerItem.getItems(); for (TreeItem entryItem : entryItems) { Object entryItemData = entryItem.getData(); if (entryItemData==entry) return entryItem; } } } } return null; } /** * Select language settings entry item in the tree. */ private void selectItem(String providerId, ICLanguageSettingEntry entry) { TreeItem providerItem = findProviderItem(providerId); if (providerItem != null) { treeEntries.select(providerItem); if (providerItem.getItems().length > 0) { treeEntries.showItem(providerItem.getItems()[0]); } TreeItem entryItem = findEntryItem(providerId, entry); if (entryItem != null) { treeEntries.showItem(entryItem); treeEntries.select(entryItem); } updateStatusLine(); } } /** * Add language settings entry. */ private void addEntry(ILanguageSettingsProvider provider, ICLanguageSettingEntry entry) { if (provider != null && entry != null) { String providerId = provider.getId(); List<ICLanguageSettingEntry> entries = getEntriesShownToUser(provider); ICLanguageSettingEntry selectedEntry = getSelectedEntry(); int pos = getExactIndex(entries, selectedEntry); entries.add(pos+1, entry); saveEntries(provider, entries); updateTreeForEntries(providerId, entry); } } /** * Save entries into provider considering resource parent. */ private void saveEntries(ILanguageSettingsProvider provider, List<ICLanguageSettingEntry> entries) { if (provider instanceof ILanguageSettingsEditableProvider) { ICConfigurationDescription cfgDescription = getConfigurationDescription(); IResource rc = getResource(); if (entries != null && rc != null) { IContainer parent = rc instanceof IProject ? null : rc.getParent(); List<ICLanguageSettingEntry> parentEntries = LanguageSettingsManager.getSettingEntriesUpResourceTree(provider, cfgDescription, parent, currentLanguageId); if (entries.equals(parentEntries)) { // to use parent entries instead entries = null; } } ((ILanguageSettingsEditableProvider)provider).setSettingEntries(cfgDescription, rc, currentLanguageId, entries); } } /** * Get list of setting entries shown to user. If current resource has no entries assigned the parent * resource is inspected. */ private List<ICLanguageSettingEntry> getEntriesShownToUser(ILanguageSettingsProvider provider) { ICConfigurationDescription cfgDescription = getConfigurationDescription(); IResource rc = getResource(); List<ICLanguageSettingEntry> entries = provider.getSettingEntries(cfgDescription, rc, currentLanguageId); if (entries == null) { entries = getSettingEntriesUpResourceTree(provider); } entries = new ArrayList<ICLanguageSettingEntry>(entries); return entries; } /** * Call dialog to add settings entry. */ private void performAdd(ILanguageSettingsProvider selectedProvider) { if (selectedProvider instanceof ILanguageSettingsEditableProvider) { ICConfigurationDescription cfgDescription = getConfigurationDescription(); ICLanguageSettingEntry selectedEntry = getSelectedEntry(); LanguageSettingEntryDialog addDialog = new LanguageSettingEntryDialog(usercomp.getShell(), cfgDescription, selectedEntry, true); if (addDialog.open()) { ICLanguageSettingEntry settingEntry = addDialog.getEntries()[0]; if (settingEntry != null) { selectedProvider = getWorkingCopy((ILanguageSettingsEditableProvider)selectedProvider); addEntry(selectedProvider, settingEntry); } } } } /** * Return working copy of the provider to edit in current session. If the supplied provider is already * the working copy return it. If not, create a copy to be edited. */ private ILanguageSettingsEditableProvider getWorkingCopy(ILanguageSettingsEditableProvider provider) { ICConfigurationDescription cfgDescription = getConfigurationDescription(); List<ILanguageSettingsProvider> initialProviders = initialProvidersMap.get(cfgDescription.getId()); if (initialProviders.contains(provider)) { List<ILanguageSettingsProvider> providers = new ArrayList<ILanguageSettingsProvider>(((ILanguageSettingsProvidersKeeper) cfgDescription).getLanguageSettingProviders()); int pos = providers.indexOf(provider); if (pos >= 0) { try { provider = provider.clone(); providers.set(pos, provider); ((ILanguageSettingsProvidersKeeper) cfgDescription).setLanguageSettingProviders(providers); } catch (CloneNotSupportedException e) { CUIPlugin.log("Internal Error: cannot clone provider "+provider.getId(), e); //$NON-NLS-1$ } } else { CUIPlugin.log("Internal Error: cannot find provider "+provider.getId(), new Exception()); //$NON-NLS-1$ } } return provider; } /** * Call dialog to edit settings entry. */ private void performEdit(ILanguageSettingsProvider selectedProvider, ICLanguageSettingEntry selectedEntry) { if (selectedProvider instanceof ILanguageSettingsEditableProvider && selectedEntry != null) { ICConfigurationDescription cfgDecsription = getConfigurationDescription(); LanguageSettingEntryDialog editDialog = new LanguageSettingEntryDialog(usercomp.getShell(), cfgDecsription, selectedEntry); if (editDialog.open()) { ICLanguageSettingEntry newEntry = editDialog.getEntries()[0]; if (newEntry != null) { selectedProvider = getWorkingCopy((ILanguageSettingsEditableProvider)selectedProvider); replaceEntry(selectedProvider, selectedEntry, newEntry); } } } } /** * Delete provider's entry and update UI. */ private void deleteEntry(ILanguageSettingsProvider provider, ICLanguageSettingEntry entry) { if (provider != null && entry != null) { String providerId = provider.getId(); List<ICLanguageSettingEntry> entries = getEntriesShownToUser(provider); int pos = getExactIndex(entries, entry); entries.remove(entry); saveEntries(provider, entries); if (pos >= entries.size()) { pos = entries.size() - 1; } ICLanguageSettingEntry entryToSelect = (pos >= 0) ? entries.get(pos) : null; updateTreeForEntries(providerId, entryToSelect); } } /** * Replace provider's entry and update UI. */ private void replaceEntry(ILanguageSettingsProvider provider, ICLanguageSettingEntry oldEntry, ICLanguageSettingEntry newEntry) { if (provider != null && oldEntry != null && newEntry != null) { String providerId = provider.getId(); List<ICLanguageSettingEntry> entries = getEntriesShownToUser(provider); int pos = getExactIndex(entries, oldEntry); entries.set(pos, newEntry); saveEntries(provider, entries); updateTreeForEntries(providerId, newEntry); } } /** * Clear all provider's entries for the given resource and update UI. */ private void clearProvider(ILanguageSettingsProvider provider) { if (provider != null) { String providerId = provider.getId(); List<ICLanguageSettingEntry> empty = new ArrayList<ICLanguageSettingEntry>(); saveEntries(provider, empty); updateTreeForEntries(providerId, null); } } /** * Clear provider's entries for the given resource or remove one entry depending on selection. */ private void performDelete(ILanguageSettingsProvider selectedProvider, ICLanguageSettingEntry selectedEntry) { if (selectedProvider instanceof ILanguageSettingsEditableProvider) { selectedProvider = getWorkingCopy((ILanguageSettingsEditableProvider)selectedProvider); if (selectedEntry != null) { deleteEntry(selectedProvider, selectedEntry); } else { clearProvider(selectedProvider); } } } /** * Change "Export" flag of provider's entry and update UI. */ private void exportEntry(ILanguageSettingsProvider provider, ICLanguageSettingEntry entry, boolean isExport) { if (provider instanceof ILanguageSettingsEditableProvider && entry != null) { int flags = entry.getFlags(); if (isExport) { flags |= ICSettingEntry.EXPORTED; } else { flags &= ~ICSettingEntry.EXPORTED; } ICLanguageSettingEntry newEntry = CDataUtil.createEntry(entry, flags); if (newEntry != null) { provider = getWorkingCopy((ILanguageSettingsEditableProvider)provider); replaceEntry(provider, entry, newEntry); } } } /** * Change "Export" flag of all provider's entries and update UI. */ private void exportAllEntries(ILanguageSettingsProvider provider, boolean isExport) { if (provider instanceof ILanguageSettingsEditableProvider) { List<ICLanguageSettingEntry> entries = getEntriesShownToUser(provider); if (entries.size() > 0) { provider = getWorkingCopy((ILanguageSettingsEditableProvider)provider); for (int i = 0; i < entries.size() ; i++) { ICLanguageSettingEntry entry = entries.get(i); int flags = entry.getFlags(); if (isExport) { flags |= ICSettingEntry.EXPORTED; } else { flags &= ~ICSettingEntry.EXPORTED; } ICLanguageSettingEntry newEntry = CDataUtil.createEntry(entry, flags); entries.set(i, newEntry); } saveEntries(provider, entries); updateTreeForEntries(provider.getId(), null); } } } /** * Export or un-export provider's entry or entries. */ private void performExport(ILanguageSettingsProvider selectedProvider, ICLanguageSettingEntry selectedEntry) { if (selectedProvider instanceof ILanguageSettingsEditableProvider) { boolean isExport = isExportMode(selectedProvider, selectedEntry); if (selectedEntry != null) { exportEntry(selectedProvider, selectedEntry, isExport); } else { exportAllEntries(selectedProvider, isExport); } } } /** * Move provider's entry up or down. */ private void moveEntry(ILanguageSettingsProvider provider, ICLanguageSettingEntry entry, boolean up) { if (provider != null && entry != null) { String providerId = provider.getId(); List<ICLanguageSettingEntry> entries = getEntriesShownToUser(provider); int pos = getExactIndex(entries, entry); int newPos = up ? pos-1 : pos+1; Collections.swap(entries, pos, newPos); saveEntries(provider, entries); updateTreeForEntries(providerId, entry); } } /** * Move provider's entry up. */ private void performMoveUp(ILanguageSettingsProvider selectedProvider, ICLanguageSettingEntry selectedEntry) { if (selectedEntry != null && (selectedProvider instanceof ILanguageSettingsEditableProvider)) { selectedProvider = getWorkingCopy((ILanguageSettingsEditableProvider)selectedProvider); moveEntry(selectedProvider, selectedEntry, true); } } /** * Move provider's entry down. */ private void performMoveDown(ILanguageSettingsProvider selectedProvider, ICLanguageSettingEntry selectedEntry) { if (selectedEntry != null && (selectedProvider instanceof ILanguageSettingsEditableProvider)) { selectedProvider = getWorkingCopy((ILanguageSettingsEditableProvider)selectedProvider); moveEntry(selectedProvider, selectedEntry, false); } } /** * Get list of providers to display in the settings entry tree. */ private List<ILanguageSettingsProvider> getProviders(String languageSettingId) { List<ILanguageSettingsProvider> itemsList = new LinkedList<ILanguageSettingsProvider>(); IResource rc = getResource(); ICConfigurationDescription cfgDescription = getConfigurationDescription(); if (rc != null && cfgDescription instanceof ILanguageSettingsProvidersKeeper) { List<ILanguageSettingsProvider> cfgProviders = ((ILanguageSettingsProvidersKeeper) cfgDescription).getLanguageSettingProviders(); for (ILanguageSettingsProvider cfgProvider : cfgProviders) { ILanguageSettingsProvider rawProvider = LanguageSettingsManager.getRawProvider(cfgProvider); if (rawProvider instanceof LanguageSettingsBaseProvider) { // filter out providers incapable of providing entries for this language List<String> languageIds = ((LanguageSettingsBaseProvider)rawProvider).getLanguageScope(); if (languageIds != null && !languageIds.contains(currentLanguageId)) { continue; } } itemsList.add(cfgProvider); } } return itemsList; } /** * Re-reads and refreshes the entries tree. * * @param selectedProviderId - provider of the entry to select after update. * If the entry is {@code null} the provider itself will be selected. * @param selectedEntry - entry to select in the tree after update. */ private void updateTreeForEntries(String selectedProviderId, ICLanguageSettingEntry selectedEntry) { Object[] expandedElements = treeEntriesViewer.getExpandedElements(); List<ILanguageSettingsProvider> tableItems = getProviders(currentLanguageId); treeEntriesViewer.getControl().setRedraw(false); treeEntriesViewer.setInput(tableItems.toArray(new Object[tableItems.size()])); // set selection and restore expansion states if (selectedProviderId != null) { selectItem(selectedProviderId, selectedEntry); // find the provider that will replace selected one and replace it in expandedElements[] for (ILanguageSettingsProvider provider : tableItems) { if (provider.getId().equals(selectedProviderId)) { for (int i = 0; i < expandedElements.length; i++) { if (expandedElements[i] instanceof ILanguageSettingsProvider) { if (((ILanguageSettingsProvider) expandedElements[i]).getId().equals(selectedProviderId)) { expandedElements[i] = provider; break; } } } break; } } } treeEntriesViewer.setExpandedElements(expandedElements); treeEntriesViewer.getControl().setRedraw(true); treeEntriesViewer.getControl().redraw(); updateStatusLine(); updateButtons(); } /** * Re-reads and refreshes the languages tree. */ private void updateTreeForLanguages(ICResourceDescription rcDes) { treeLanguages.removeAll(); currentLanguageId = null; List<String> languageIds = LanguageSettingsManager.getLanguages(rcDes); if (languageIds.size() > 1) { // remove null language when some real ones are defined languageIds.remove(null); } else if (languageIds.isEmpty()) { // if no languages are defined keep null language as "Unspecified language" languageIds.add(null); } // Use a TreeMap to sort the languages by name. // For each name we keep a list of ids in case of name overlap. Map<String, List<String>> map = new TreeMap<String, List<String>>(); for (String langId : languageIds) { ILanguage language = LanguageManager.getInstance().getLanguage(langId); String langName = language != null ? language.getName() : Messages.LanguageSettingsEntriesTab_UnspecifiedLanguage; if (langName == null || langName.length() == 0) continue; List<String> langIds = map.get(langName); if (langIds == null) { langIds = new ArrayList<String>(); map.put(langName, langIds); } langIds.add(langId); } for (String langName : map.keySet()) { List<String> langIds = map.get(langName); for (String langId : langIds) { TreeItem t = new TreeItem(treeLanguages, SWT.NONE); if (langIds.size() == 1) { t.setText(0, langName); } else { StringBuilder uniqueLangName = new StringBuilder(); uniqueLangName.append(langName).append(" [id=") //$NON-NLS-1$ .append(langId).append("]"); //$NON-NLS-1$ t.setText(0, uniqueLangName.toString()); } t.setData(langId); if (currentLanguageIdGlobal != null && currentLanguageIdGlobal.equals(langId)) { currentLanguageId = currentLanguageIdGlobal; treeLanguages.setSelection(t); } else if (currentLanguageId == null) { // this selects first language on first round // do not select the tree item and global language selection here, only on actual click currentLanguageId = langId; } } } } /** * Change selection of language. */ private void selectLanguage(String langId) { currentLanguageId = langId; currentLanguageIdGlobal = currentLanguageId; for (TreeItem t : treeLanguages.getItems()) { if ((t.getData() == null && langId == null) || t.getData().equals(langId)) { treeLanguages.setSelection(t); break; } } } /** * Update the tab. Called when configuration changes. */ @Override public void updateData(ICResourceDescription rcDes) { if (!canBeVisible()) return; if (rcDes != null) { if (page.isMultiCfg()) { setAllVisible(false, null); return; } else { setAllVisible(true, null); } updateTreeForLanguages(rcDes); updateTreeForEntries(null, null); if (masterPropertyPage != null) { boolean enabled = masterPropertyPage.isLanguageSettingsProvidersEnabled(); enableTabControls(enabled); } } updateButtons(); } @Override public boolean canSupportMultiCfg() { return false; } @Override protected void performDefaults() { // This page restores defaults for file/folder only. // Project and Preferences page are restored by LanguageSettingsProviderTab. if (page.isForFile() || page.isForFolder()) { // The logic below is not exactly correct as the default for a resource could be different than null. // It is supposed to match the one taken from extension for the same resource which in theory can be non-null. // However for the performance reasons for resource decorators where the same logic is used // we use null for resetting file/folder resource which should be correct in most cases. // Count that as a feature. ICConfigurationDescription cfgDescription = getConfigurationDescription(); if (!(cfgDescription instanceof ILanguageSettingsProvidersKeeper)) { return; } boolean changed = false; IResource rc = getResource(); List<ILanguageSettingsProvider> oldProviders = ((ILanguageSettingsProvidersKeeper) cfgDescription).getLanguageSettingProviders(); List<ILanguageSettingsProvider> newProviders = new ArrayList<ILanguageSettingsProvider>(oldProviders.size()); // clear entries for a given resource for all languages where applicable providers: for (ILanguageSettingsProvider provider : oldProviders) { ILanguageSettingsEditableProvider providerCopy = null; if (provider instanceof ILanguageSettingsEditableProvider) { for (TreeItem langItems : treeLanguages.getItems()) { String langId = (String)langItems.getData(); if (provider.getSettingEntries(cfgDescription, rc, langId) != null) { if (providerCopy == null) { // copy providers to be able to "Cancel" in UI providerCopy = LanguageSettingsManager.getProviderCopy((ILanguageSettingsEditableProvider) provider, true); if (providerCopy == null) { continue providers; } } providerCopy.setSettingEntries(cfgDescription, rc, langId, null); changed = true; } } } if (providerCopy != null) { newProviders.add(providerCopy); } else { newProviders.add(provider); } } if (changed) { ((ILanguageSettingsProvidersKeeper) cfgDescription).setLanguageSettingProviders(newProviders); updateTreeForEntries(null, null); } } } @Override protected void performApply(ICResourceDescription srcRcDescription, ICResourceDescription destRcDescription) { if (!page.isForPrefs()) { ICConfigurationDescription sd = srcRcDescription.getConfiguration(); ICConfigurationDescription dd = destRcDescription.getConfiguration(); if (sd instanceof ILanguageSettingsProvidersKeeper && dd instanceof ILanguageSettingsProvidersKeeper) { List<ILanguageSettingsProvider> newProviders = ((ILanguageSettingsProvidersKeeper) sd).getLanguageSettingProviders(); ((ILanguageSettingsProvidersKeeper) dd).setLanguageSettingProviders(newProviders); } } performOK(); trackInitialSettings(); updateData(getResDesc()); } @Override protected void performOK() { if (masterPropertyPage != null && masterPropertyPage.isLanguageSettingsProvidersEnabled()) { masterPropertyPage.applyLanguageSettingsProvidersEnabled(); } } @Override public boolean canBeVisible() { if (!ScannerDiscoveryLegacySupport.isLanguageSettingsProvidersFunctionalityEnabled(null)) { return false; } // filter out files not associated with any languages such as *.o if (page.isForFile()) { List<String> languageIds = LanguageSettingsManager.getLanguages(getResDesc()); if (languageIds.isEmpty() || (languageIds.size() == 1 && languageIds.get(0) == null)) { // for legacy projects check if the file is associated with any CDT language IResource rc = getResource(); if (rc instanceof IFile) { try { ILanguage language = LanguageManager.getInstance().getLanguageForFile((IFile)rc, null); return language != null; } catch (CoreException e) { // who cares, not even logging } } return false; } else { // for regular MBS project verify language against toolchain language for (String langId : languageIds) { if (langId != null) { ILanguage language = LanguageManager.getInstance().getLanguage(langId); if (language != null) { return true; } } } } return false; } return true; } }