Java tutorial
/******************************************************************************* * Copyright (c) 2011 Petri Tuononen 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: * Petri Tuononen - Initial implementation *******************************************************************************/ package org.eclipse.cdt.managedbuilder.pkgconfig.properties; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICResourceDescription; import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; import org.eclipse.cdt.managedbuilder.core.ITool; import org.eclipse.cdt.managedbuilder.core.IToolChain; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.pkgconfig.Activator; import org.eclipse.cdt.managedbuilder.pkgconfig.preferences.LibDirFieldEditor; import org.eclipse.cdt.managedbuilder.pkgconfig.preferences.Messages; import org.eclipse.cdt.managedbuilder.pkgconfig.preferences.PkgConfigPathListEditor; import org.eclipse.cdt.managedbuilder.pkgconfig.preferences.PkgConfigSettingsDialog; import org.eclipse.cdt.managedbuilder.pkgconfig.preferences.PreferenceStore; import org.eclipse.cdt.managedbuilder.pkgconfig.settings.PkgConfigExternalSettingProvider; import org.eclipse.cdt.managedbuilder.pkgconfig.util.Parser; import org.eclipse.cdt.managedbuilder.pkgconfig.util.PathToToolOption; import org.eclipse.cdt.managedbuilder.pkgconfig.util.PkgConfigUtil; import org.eclipse.cdt.ui.newui.AbstractCPropertyTab; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; /** * Property tab to select packages and add pkg-config output of checked packages * to compiler and linker (MBS). * */ public class PkgConfigPropertyTab extends AbstractCPropertyTab { PkgConfigPathListEditor configPathListEditor; LibDirFieldEditor libDirEditor; CheckboxTableViewer pkgCfgViewer; private Set<Object> previouslyChecked; private ArrayList<Object> newItems = new ArrayList<Object>(); private static final int BUTTON_SELECT = 0; private static final int BUTTON_DESELECT = 1; private static final int BUTTON_ADVANCED = 2; private final String PACKAGES = "packages"; //$NON-NLS-1$ private boolean reindexToggle = false; private SashForm sashForm; private static final String[] BUTTONS = new String[] { "Select", //$NON-NLS-1$ "Deselect", //$NON-NLS-1$ "Advanced..." //$NON-NLS-1$ }; private IToolChain selectedToolChain; /* * (non-Javadoc) * * @see * org.eclipse.cdt.ui.newui.AbstractCPropertyTab#createControls(org.eclipse * .swt.widgets.Composite) */ @Override public void createControls(Composite parent) { super.createControls(parent); this.usercomp.setLayout(new GridLayout(1, false)); this.sashForm = new SashForm(this.usercomp, SWT.NONE); this.sashForm.setBackground(this.sashForm.getDisplay().getSystemColor(SWT.COLOR_GRAY)); this.sashForm.setLayoutData(new GridData(GridData.FILL_BOTH)); GridLayout layout = new GridLayout(1, false); layout.marginHeight = 5; this.sashForm.setLayout(layout); final Composite c1 = new Composite(this.sashForm, SWT.NONE); GridLayout layout2 = new GridLayout(3, false); c1.setLayout(layout2); this.pkgCfgViewer = CheckboxTableViewer.newCheckList(c1, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER); final Table tbl = this.pkgCfgViewer.getTable(); tbl.setHeaderVisible(true); tbl.setLinesVisible(true); GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd = new GridData(GridData.FILL_BOTH); gd.horizontalSpan = 2; tbl.setLayoutData(gd); createColumns(c1, this.pkgCfgViewer); this.pkgCfgViewer.setContentProvider(new ArrayContentProvider()); this.selectedToolChain = getSelectedToolchain(); updatePkgConfigBinPath(); this.pkgCfgViewer.setInput(new DataModelProvider(this.page.getProject().getName()).getEntries()); this.pkgCfgViewer.addCheckStateListener(new PkgListener()); this.pkgCfgViewer.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(DoubleClickEvent event) { TableItem itm = tbl.getSelection()[0]; if (itm.getChecked()) { itm.setChecked(false); } else { itm.setChecked(true); } handleCheckStateChange(); } }); // buttons Composite compositeButtons = new Composite(c1, SWT.NONE); initButtons(compositeButtons, BUTTONS); initializePackageStates(); this.previouslyChecked = new HashSet<Object>(Arrays.asList(getCheckedItems())); } @Override public void handleTabEvent(int kind, Object data) { if (this.selectedToolChain != null && this.selectedToolChain.getId() != getSelectedToolchain().getId()) { this.selectedToolChain = getSelectedToolchain(); updatePkgConfigBinPath(); if (PkgConfigPropertyTab.this.pkgCfgViewer != null) { PkgConfigPropertyTab.this.pkgCfgViewer.setInput( new DataModelProvider(PkgConfigPropertyTab.this.page.getProject().getName()).getEntries()); PkgConfigPropertyTab.this.pkgCfgViewer.refresh(); } } } /** * Get checked items. * * @return */ private Object[] getCheckedItems() { return this.pkgCfgViewer.getCheckedElements(); } /** * Action for the check state change. */ void handleCheckStateChange() { Object[] checkedItems = getCheckedItems(); // check if new items checked if (checkedItems.length > this.previouslyChecked.size()) { // add checked items to an array list for (Object o : checkedItems) { // if new item if (!this.previouslyChecked.contains(o)) { this.newItems.add(o); } } addPackageValues(this.newItems.toArray(), this.page.getProject()); this.reindexToggle = true; } saveChecked(); updateData(getResDesc()); this.previouslyChecked = new HashSet<Object>(Arrays.asList(checkedItems)); this.newItems.clear(); } /** * Add new flags that the packages need to Tools' Options. Only for other * flags. * * @param addedItems * Object[] * @param proj * IProject */ private static void addPackageValues(Object[] addedItems, IProject proj) { for (Object item : addedItems) { // handle options String cflags = PkgConfigUtil.getCflags(item.toString(), proj.getName()); String[] optionsArray = Parser.parseCflagOptions(cflags); if (optionsArray != null) { for (String option : optionsArray) { PathToToolOption.addOtherFlag(option, proj); } } } ManagedBuildManager.saveBuildInfo(proj, true); } /** * Initializes the check state of the packages from the storage. */ private void initializePackageStates() { ICConfigurationDescription desc = getResDesc().getConfiguration(); ICStorageElement strgElem = null; try { strgElem = desc.getStorage(this.PACKAGES, true); TableItem[] items = this.pkgCfgViewer.getTable().getItems(); String value = null; for (TableItem item : items) { /* * The package names with + symbols were converted so that + -> * plus in order to prevent an error when saving to * ICStorageElement. */ if (item.getText().contains("+")) { //$NON-NLS-1$ String newItemName = item.getText().replace("+", "plus"); //$NON-NLS-1$ //$NON-NLS-2$ value = strgElem.getAttribute(newItemName); } else { value = strgElem.getAttribute(item.getText()); } if (value != null) { if (value.equals("true")) { //$NON-NLS-1$ item.setChecked(true); } } } } catch (CoreException e) { Activator.getDefault().log(e, "Initialization of packages failed."); //$NON-NLS-1$ } } /** * Saves checked state of the packages. */ private void saveChecked() { ICConfigurationDescription desc = getResDesc().getConfiguration(); ICStorageElement strgElem = null; // get storage or create one if it doesn't exist try { strgElem = desc.getStorage(this.PACKAGES, true); } catch (CoreException e) { Activator.getDefault().log(e, "Getting packages from the storage failed."); //$NON-NLS-1$ } TableItem[] items = this.pkgCfgViewer.getTable().getItems(); for (TableItem item : items) { if (item != null) { String chkd; // form literal form of boolean state if (item.getChecked()) { chkd = "true"; //$NON-NLS-1$ } else { chkd = "false"; //$NON-NLS-1$ } /* * add package name and the checkbox state to the storage */ try { String pkgName = item.getText(); // need to convert + symbols to "plus" if (pkgName.contains("+")) { //$NON-NLS-1$ String newPkgName = pkgName.replace("+", "plus"); //$NON-NLS-1$ //$NON-NLS-2$ if (strgElem != null) { strgElem.setAttribute(newPkgName, chkd); } } else { if (strgElem != null) { strgElem.setAttribute(pkgName, chkd); } } } catch (Exception e) { Activator.getDefault().log(e, "Setting attribute to ICStorageElement failed."); //$NON-NLS-1$ // Seems like ICStorageElement cannot store Strings with + /* * INVALID_CHARACTER_ERR: An invalid or illegal XML * character is specified. */ } } } } @Override protected void performApply(ICResourceDescription src, ICResourceDescription dst) { updateData(getResDesc()); } @Override protected void performDefaults() { // uncheck every checkbox this.pkgCfgViewer.setCheckedElements(new Object[] {}); // remove values from Tools Options handleCheckStateChange(); } @Override protected void performOK() { // freshen index if new packages have been selected if (this.reindexToggle) { rebuiltIndex(); } this.reindexToggle = false; } @Override protected void updateButtons() { // nothing here } @Override protected void updateData(ICResourceDescription cfg) { final ICConfigurationDescription confDesc = cfg.getConfiguration(); ICProjectDescription projDesc = confDesc.getProjectDescription(); Job j = new Job("Update Pkg-config exernal settings provider") { //$NON-NLS-1$ @Override protected IStatus run(IProgressMonitor monitor) { // a set holding external setting providers Set<String> externalSettingsProviders = new LinkedHashSet<String>( Arrays.asList(confDesc.getExternalSettingsProviderIds())); // remove pkg-config external setting provider externalSettingsProviders.remove(PkgConfigExternalSettingProvider.ID); confDesc.setExternalSettingsProviderIds( externalSettingsProviders.toArray(new String[externalSettingsProviders.size()])); // add pkg-config external setting provider externalSettingsProviders.add(PkgConfigExternalSettingProvider.ID); confDesc.setExternalSettingsProviderIds( externalSettingsProviders.toArray(new String[externalSettingsProviders.size()])); // update external setting providers confDesc.updateExternalSettingsProviders(new String[] { PkgConfigExternalSettingProvider.ID }); return Status.OK_STATUS; } }; j.setPriority(Job.INTERACTIVE); j.schedule(); try { CoreModel.getDefault().setProjectDescription(this.page.getProject(), projDesc); } catch (CoreException e) { Activator.getDefault().log(e, "Setting/updating the project description failed."); //$NON-NLS-1$ } } /** * Check state listener for the table viewer. * */ public class PkgListener implements ICheckStateListener { @Override public void checkStateChanged(CheckStateChangedEvent e) { handleCheckStateChange(); } } /** * Creates table columns, headers and sets the size of the columns. * * @param parent * @param viewer */ private void createColumns(@SuppressWarnings("unused") final Composite parent, @SuppressWarnings("unused") final TableViewer viewer) { String[] titles = { "Packages", "Description" }; //$NON-NLS-1$ //$NON-NLS-2$ int[] bounds = { 200, 450 }; // first column is for the package TableViewerColumn col = createTableViewerColumn(titles[0], bounds[0]); col.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object element) { DataModel dm = (DataModel) element; return dm.getPackage(); } }); // second column is for the description col = createTableViewerColumn(titles[1], bounds[1]); col.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object element) { DataModel dm = (DataModel) element; return dm.getDescription(); } }); } /** * Creates a column for the table viewer. * * @param title * @param bound * @return */ private TableViewerColumn createTableViewerColumn(String title, int bound) { final TableViewerColumn viewerColumn = new TableViewerColumn(this.pkgCfgViewer, SWT.NONE); final TableColumn column = viewerColumn.getColumn(); column.setText(title); column.setWidth(bound); column.setResizable(true); return viewerColumn; } /** * Get selected item(s). * * @return */ private TableItem[] getSelected() { TableItem[] selected = this.pkgCfgViewer.getTable().getSelection(); return selected; } /* * (non-Javadoc) * * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#buttonPressed(int) */ @Override public void buttonPressed(int n) { switch (n) { case BUTTON_SELECT: selectedButtonPressed(); break; case BUTTON_DESELECT: deselectedButtonPressed(); break; case BUTTON_ADVANCED: advancedButtonPressed(); break; default: break; } updateButtons(); } /** * Action for the Select button. */ private void selectedButtonPressed() { TableItem[] selected = getSelected(); for (TableItem itm : selected) { itm.setChecked(true); } handleCheckStateChange(); } /** * Action for the Deselect button. */ private void deselectedButtonPressed() { TableItem[] selected = getSelected(); for (TableItem itm : selected) { itm.setChecked(false); } handleCheckStateChange(); } /** * Action for the Select button. */ private void advancedButtonPressed() { // Create new dialog PkgConfigSettingsDialog dialog = new PkgConfigSettingsDialog(this.usercomp.getShell(), Messages.PkgConfigPropertyTab_0, this.page.getProject()); dialog.open(); if (PkgConfigPropertyTab.this.pkgCfgViewer != null) { // Update pkg-config libraries for the project updatePkgConfigBinPath(); PkgConfigPropertyTab.this.pkgCfgViewer.setInput( new DataModelProvider(PkgConfigPropertyTab.this.page.getProject().getName()).getEntries()); } } /** * Update the pkg-config path according to the toolchain if the default * toolchain executable is selected by the user in the pkg-config advanced * preferences. */ private void updatePkgConfigBinPath() { // Search if a toolchain tool defines the pkg-config tool bin // path String pkgConfigPath = ""; //$NON-NLS-1$ if (this.page != null && PreferenceStore.isPkgConfigExecutableDefault(this.page.getProject().getName())) { for (ITool tool : this.selectedToolChain .getToolsBySuperClassId("org.eclipse.cdt.managedbuilder.pkgconfig.tool")) { //$NON-NLS-1$ pkgConfigPath = tool.getToolCommand(); } PreferenceStore.setPkgConfigBinPath(pkgConfigPath, this.page.getProject().getName()); } } private IToolChain getSelectedToolchain() { if (this.page != null) { IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(this.page.getProject()); if (info != null) { return info.getDefaultConfiguration().getToolChain(); } } return null; } /** * Rebuilts the index of the selected project in the workspace. */ private void rebuiltIndex() { ICProject cproject = CoreModel.getDefault().getCModel().getCProject(this.page.getProject().getName()); CCorePlugin.getIndexManager().reindex(cproject); } }