/* Copyright (C) 2009 Mobile Sorcery AB This program is free software; you can redistribute it and/or modify it under the terms of the Eclipse Public License v1.0. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Eclipse Public License v1.0 for more details. You should have received a copy of the Eclipse Public License v1.0 along with this program. It is also available at http://www.eclipse.org/legal/epl-v10.html */ package com.mobilesorcery.sdk.ui.internal.properties; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.AbstractListViewer; import org.eclipse.jface.viewers.ComboViewer; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.Text; import com.mobilesorcery.sdk.core.CoreMoSyncPlugin; import com.mobilesorcery.sdk.core.DefaultPackager; import com.mobilesorcery.sdk.core.IBuildConfiguration; import com.mobilesorcery.sdk.core.IPropertyOwner; import com.mobilesorcery.sdk.core.IsExperimentalTester; import com.mobilesorcery.sdk.core.MoSyncBuilder; import com.mobilesorcery.sdk.core.MoSyncExtension; import com.mobilesorcery.sdk.core.MoSyncExtensionManager; import com.mobilesorcery.sdk.core.MoSyncProject; import com.mobilesorcery.sdk.core.MoSyncProjectParameterResolver; import com.mobilesorcery.sdk.core.MoSyncTool; import com.mobilesorcery.sdk.core.NameSpacePropertyOwner; import com.mobilesorcery.sdk.core.ParameterResolver; import com.mobilesorcery.sdk.core.PropertyOwnerWorkingCopy; import com.mobilesorcery.sdk.core.PropertyUtil; import com.mobilesorcery.sdk.core.Util; import com.mobilesorcery.sdk.core.Version; import com.mobilesorcery.sdk.core.IPropertyOwner.IWorkingCopy; import com.mobilesorcery.sdk.core.templates.ITemplate; import com.mobilesorcery.sdk.core.templates.ProjectTemplate; import com.mobilesorcery.sdk.core.templates.TemplateManager; import com.mobilesorcery.sdk.ui.BuildConfigurationsContentProvider; import com.mobilesorcery.sdk.ui.BuildConfigurationsLabelProvider; import com.mobilesorcery.sdk.ui.DefaultMessageProvider; import com.mobilesorcery.sdk.ui.MoSyncPropertyPage; import com.mobilesorcery.sdk.ui.MosyncUIPlugin; import com.mobilesorcery.sdk.ui.Note; import com.mobilesorcery.sdk.ui.ParameterResolverContentProvider; import com.mobilesorcery.sdk.ui.UIUtils; import com.mobilesorcery.sdk.ui.UpdateListener; import com.mobilesorcery.sdk.ui.ValidationMessageProvider; public class BuildSettingsPropertyPage extends MoSyncPropertyPage implements PropertyChangeListener { public BuildSettingsPropertyPage() { super(true); } public class BuildConfigurationChangedListener implements ISelectionChangedListener { private boolean active = true; @Override public void selectionChanged(SelectionChangedEvent event) { if (!active) { return; } IStructuredSelection selection = (IStructuredSelection) event.getSelection(); String id = (String) selection.getFirstElement(); updateCurrentBuildConfiguration(); changeConfiguration(id); initUI(); } public void setActive(boolean active) { this.active = active; } } private final static String[] INCREMENTAL_BUILD_STRATEGY_OPTIONS = new String[] { "Use GCC -MF Option", "Always perform FULL build" }; private static final String BINARY_TYPE_NATIVE = "Native"; private static final String BINARY_TYPE_INTERPRETED = "Interpreted"; private static final String BINARY_TYPE_RECOMPILED = "Statically Recompiled"; private static final String[] BINARY_TYPES = new String[] { BINARY_TYPE_NATIVE, BINARY_TYPE_INTERPRETED, BINARY_TYPE_RECOMPILED }; private Text additionalIncludePathsText; private Text additionalNativeIncludePathsText; private Button ignoreDefaultIncludePaths; private Text additionalLibraryPathsText; private Button ignoreDefaultLibraryPaths; private Button deadCodeElim; private Text gccFlags; private Button applicationProjectType; private Button libraryProjectType; private Button extensionProjectType; private Text additionalLibrariesText; private Button ignoreDefaultLibraries; private Text extraRes; private Text extraLink; private Text libOutputPath; private Text appOutputPath; private Text extensions; private UpdateListener listener; private Button gccWall; private Button gccWerror; private Button gccWextra; private Combo incrementalBuildStrategy; private Button useDebugRuntimes; private ComboViewer buildConfigurations; private String currentConfigId; private BuildConfigurationChangedListener buildConfigurationListener; private final HashMap<Object, IPropertyOwner> workingCopies = new HashMap<Object, IPropertyOwner>(); private IWorkingCopy projectWorkingCopy; private final HashSet<String> buildProperties = new HashSet<String>(); private Composite main; private Composite placeHolder; private StackLayout buildPathsLayout; private Composite buildPathsInterpreted; private Composite buildPathsNative; private Composite buildPaths; private Text excludeFiles; private Group memoryGroup; private Text heapSize; private Text stackSize; private Text dataSize; private Text vendor; private Text version; private Text appName; private Combo binaryType; private boolean supportsExtensions; private Label librariesLabel; private Label excludeFilesLabel; private Label libraryPathsLabel; private Label gccWarningsLabel; private Label extraLinkLabel; @Override protected Control createContents(Composite parent) { supportsExtensions = MoSyncExtensionManager.supportsExtensions() || Boolean.TRUE.equals(IsExperimentalTester.isExperimental()); placeHolder = new Composite(parent, SWT.NONE); FillLayout placeHolderLayout = new FillLayout(); placeHolderLayout.marginHeight = 0; placeHolderLayout.marginWidth = 0; placeHolder.setLayout(placeHolderLayout); fillPlaceHolder(placeHolder); getProject().addPropertyChangeListener(this); return placeHolder; } protected void fillPlaceHolder(Composite placeHolder) { main = new Composite(placeHolder, SWT.NONE); main.setLayout(new GridLayout(1, false)); Group projectType = new Group(main, SWT.NONE); projectType.setLayout(new GridLayout(3, false)); projectType.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); projectType.setText("Project &Type"); applicationProjectType = new Button(projectType, SWT.RADIO); applicationProjectType.setText("&Application"); libraryProjectType = new Button(projectType, SWT.RADIO); libraryProjectType.setText("&Library"); if (supportsExtensions) { extensionProjectType = new Button(projectType, SWT.RADIO); extensionProjectType.setText("&Extension"); } Group buildStrategy = new Group(main, SWT.NONE); buildStrategy.setLayout(new GridLayout(2, false)); buildStrategy.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); buildStrategy.setText("Building"); Label binaryTypeLabel = new Label(buildStrategy, SWT.NONE); binaryTypeLabel.setText("Binary Type"); binaryType = new Combo(buildStrategy, SWT.READ_ONLY); binaryType.setItems(BINARY_TYPES); binaryType.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false)); Label binaryTypeInfo = new Label(buildStrategy, SWT.WRAP); binaryTypeInfo.setText("The binary type indicates how building should take place.\n" + "If a certain binary type is not available for a platform, " + "the 'Interpreted' binary type will be used."); binaryTypeInfo.setFont(MosyncUIPlugin.getDefault().getFont(MosyncUIPlugin.FONT_INFO_TEXT)); binaryTypeInfo.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1)); Label incrementalBuildStrategyLabel = new Label(buildStrategy, SWT.NONE); incrementalBuildStrategyLabel.setText("Incremental Build Strategy To Use:"); incrementalBuildStrategy = new Combo(buildStrategy, SWT.READ_ONLY); incrementalBuildStrategy.setItems(INCREMENTAL_BUILD_STRATEGY_OPTIONS); incrementalBuildStrategy.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false)); boolean hasConfigurations = getProject().areBuildConfigurationsSupported(); Group configurationsGroup = null; if (hasConfigurations) { configurationsGroup = new Group(main, SWT.NONE); configurationsGroup.setLayout(new GridLayout(1, false)); configurationsGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); configurationsGroup.setText("Build Configuration"); Composite configurationsComposite = new Composite(configurationsGroup, SWT.NONE); configurationsComposite.setLayout(new GridLayout(2, true)); configurationsComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Label configurationsLabel = new Label(configurationsComposite, SWT.NONE); configurationsLabel.setText("Configuratio&n:"); buildConfigurations = new ComboViewer(configurationsComposite, SWT.READ_ONLY); buildConfigurations.setContentProvider(new BuildConfigurationsContentProvider(getProject())); buildConfigurations.setLabelProvider(new BuildConfigurationsLabelProvider(getProject())); buildConfigurations.setInput(getProject()); buildConfigurations.getControl().setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); buildConfigurationListener = new BuildConfigurationChangedListener(); buildConfigurations.addSelectionChangedListener(buildConfigurationListener); } Composite configurationParent = hasConfigurations ? configurationsGroup : main; TabFolder tabs = new TabFolder(configurationParent, SWT.NONE); tabs.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); createTabs(tabs); listener = new UpdateListener(this); applicationProjectType.addListener(SWT.Selection, listener); libraryProjectType.addListener(SWT.Selection, listener); applicationProjectType.addListener(SWT.Selection, listener); incrementalBuildStrategy.addListener(SWT.Selection, listener); binaryType.addListener(SWT.Selection, listener); additionalIncludePathsText.addListener(SWT.Modify, listener); additionalNativeIncludePathsText.addListener(SWT.Modify, listener); additionalLibrariesText.addListener(SWT.Modify, listener); additionalLibraryPathsText.addListener(SWT.Modify, listener); libOutputPath.addListener(SWT.Modify, listener); appOutputPath.addListener(SWT.Modify, listener); stackSize.addListener(SWT.Modify, listener); heapSize.addListener(SWT.Modify, listener); dataSize.addListener(SWT.Modify, listener); version.addListener(SWT.Modify, listener); appName.addListener(SWT.Modify, listener); if (supportsExtensions) { extensionProjectType.addListener(SWT.Selection, listener); extensions.addListener(SWT.Modify, listener); } changeConfiguration(getProject().getActiveBuildConfiguration()); if (getProject().areBuildConfigurationsSupported()) { IBuildConfiguration cfg = getProject().getActiveBuildConfiguration(); if (cfg != null) { buildConfigurationListener.setActive(false); buildConfigurations.setSelection(new StructuredSelection(cfg.getId())); buildConfigurationListener.setActive(true); } } initUI(); placeHolder.layout(); } private void createTabs(TabFolder tabs) { createPathsTab(tabs); createCompilerOptionsTab(tabs); createPackagingTab(tabs); } private void createCompilerOptionsTab(TabFolder tabs) { TabItem compilerFlagsTab = new TabItem(tabs, SWT.NONE); compilerFlagsTab.setText("Compiler &Flags"); Composite compilerFlags = new Composite(tabs, SWT.NONE); compilerFlagsTab.setControl(compilerFlags); compilerFlags.setLayout(new GridLayout(2, false)); compilerFlags.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Label gccFlagsLabel = new Label(compilerFlags, SWT.NONE); gccFlagsLabel.setText("Additional GCC &Switches:"); gccFlags = new Text(compilerFlags, SWT.BORDER | SWT.SINGLE); gccFlags.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); addContentAssist(gccFlags); Label extraResLabel = new Label(compilerFlags, SWT.NONE); extraResLabel.setText("Extra &Resource Compiler Switches:"); extraRes = new Text(compilerFlags, SWT.BORDER | SWT.SINGLE); extraRes.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); addContentAssist(extraRes); extraLinkLabel = new Label(compilerFlags, SWT.NONE); extraLinkLabel.setText("Extra &Linker Switches:"); extraLink = new Text(compilerFlags, SWT.BORDER | SWT.SINGLE); extraLink.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); addContentAssist(extraLink); deadCodeElim = new Button(compilerFlags, SWT.CHECK); deadCodeElim.setText("Activate Dead Code &Elimination"); deadCodeElim.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1)); gccWarningsLabel = new Label(compilerFlags, SWT.NONE); gccWarningsLabel.setText("GCC &Warnings:"); gccWarningsLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 1, 3)); gccWerror = new Button(compilerFlags, SWT.CHECK); gccWerror.setText("Warnings as &Errors"); gccWall = new Button(compilerFlags, SWT.CHECK); gccWall.setText("&All Warnings"); gccWextra = new Button(compilerFlags, SWT.CHECK); gccWextra.setText("E&xtra Warnings"); memoryGroup = new Group(compilerFlags, SWT.NONE); memoryGroup.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1)); memoryGroup.setText("&Memory Settings"); memoryGroup.setLayout(new GridLayout(3, false)); Label heapSizeLabel = new Label(memoryGroup, SWT.NONE); heapSizeLabel.setText("&Heap Size:"); heapSize = new Text(memoryGroup, SWT.BORDER | SWT.SINGLE); heapSize.setLayoutData(new GridData(UIUtils.getDefaultFieldSize() / 2, SWT.DEFAULT)); Label kb1 = new Label(memoryGroup, SWT.NONE); kb1.setText("kb"); Label stackSizeLabel = new Label(memoryGroup, SWT.NONE); stackSizeLabel.setText("&Stack Size:"); stackSize = new Text(memoryGroup, SWT.BORDER | SWT.SINGLE); stackSize.setLayoutData(new GridData(UIUtils.getDefaultFieldSize() / 2, SWT.DEFAULT)); Label kb2 = new Label(memoryGroup, SWT.NONE); kb2.setText("kb"); Label dataSizeLabel = new Label(memoryGroup, SWT.NONE); dataSizeLabel.setText("&Data Size:"); dataSize = new Text(memoryGroup, SWT.BORDER | SWT.SINGLE); dataSize.setLayoutData(new GridData(UIUtils.getDefaultFieldSize() / 2, SWT.DEFAULT)); Label kb3 = new Label(memoryGroup, SWT.NONE); kb3.setText("kb"); } private void createPackagingTab(TabFolder tabs) { TabItem packagingTab = new TabItem(tabs, SWT.NONE); packagingTab.setText("&Packaging"); Composite packaging = new Composite(tabs, SWT.NONE); packagingTab.setControl(packaging); packaging.setLayout(new GridLayout(2, false)); packaging.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); useDebugRuntimes = new Button(packaging, SWT.CHECK); useDebugRuntimes.setText("Use Debug &Runtimes"); GridData useDebugRuntimesData = new GridData(GridData.FILL_HORIZONTAL); useDebugRuntimesData.horizontalSpan = 2; useDebugRuntimes.setLayoutData(useDebugRuntimesData); Label versionLabel = new Label(packaging, SWT.NONE); versionLabel.setText("&Version:"); version = new Text(packaging, SWT.BORDER | SWT.SINGLE); version.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Label vendorNameLabel = new Label(packaging, SWT.NONE); vendorNameLabel.setText("&Publisher:"); vendor = new Text(packaging, SWT.BORDER | SWT.SINGLE); vendor.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Label appNameLabel = new Label(packaging, SWT.NONE); appNameLabel.setText("&Application Name:"); appName = new Text(packaging, SWT.BORDER | SWT.SINGLE); appName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); } private void createPathsTab(TabFolder tabs) { TabItem buildPathsTab = new TabItem(tabs, SWT.NONE); buildPathsTab.setText("&Paths and Files"); buildPaths = new Composite(tabs, SWT.NONE); buildPathsTab.setControl(buildPaths); buildPathsLayout = new StackLayout(); buildPaths.setLayout(buildPathsLayout); buildPathsInterpreted = new Composite(buildPaths, SWT.NONE); buildPathsInterpreted.setLayout(new GridLayout(2, false)); buildPathsInterpreted.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Label includePathsLabel = new Label(buildPathsInterpreted, SWT.NONE); includePathsLabel.setText("Additional &Include Paths:"); includePathsLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1)); additionalIncludePathsText = new Text(buildPathsInterpreted, SWT.BORDER | SWT.SINGLE); additionalIncludePathsText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); addContentAssist(additionalIncludePathsText); ignoreDefaultIncludePaths = new Button(buildPathsInterpreted, SWT.CHECK); ignoreDefaultIncludePaths.setText("Ignore &Default"); libraryPathsLabel = new Label(buildPathsInterpreted, SWT.NONE); libraryPathsLabel.setText("Additional &Library Paths:"); libraryPathsLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1)); additionalLibraryPathsText = new Text(buildPathsInterpreted, SWT.BORDER | SWT.SINGLE); additionalLibraryPathsText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); addContentAssist(additionalLibraryPathsText); ignoreDefaultLibraryPaths = new Button(buildPathsInterpreted, SWT.CHECK); ignoreDefaultLibraryPaths.setText("Ignore De&fault"); librariesLabel = new Label(buildPathsInterpreted, SWT.NONE); librariesLabel.setText("Additional &Libraries:"); librariesLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1)); additionalLibrariesText = new Text(buildPathsInterpreted, SWT.BORDER | SWT.SINGLE); additionalLibrariesText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); ignoreDefaultLibraries = new Button(buildPathsInterpreted, SWT.CHECK); ignoreDefaultLibraries.setText("I&gnore Default"); excludeFilesLabel = new Label(buildPathsInterpreted, SWT.NONE); excludeFilesLabel.setText("Exclude file pattern"); excludeFilesLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1)); excludeFiles = new Text(buildPathsInterpreted, SWT.BORDER | SWT.SINGLE); GridData excludeFilesData = new GridData(GridData.FILL_HORIZONTAL); excludeFilesData.horizontalSpan = 2; excludeFiles.setLayoutData(excludeFilesData); Label outputPathLabel = new Label(buildPathsInterpreted, SWT.NONE); outputPathLabel.setText("&Output File (libraries only)"); outputPathLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1)); libOutputPath = new Text(buildPathsInterpreted, SWT.BORDER | SWT.SINGLE); GridData outputPathData = new GridData(GridData.FILL_HORIZONTAL); outputPathData.horizontalSpan = 2; libOutputPath.setLayoutData(outputPathData); Label appPathLabel = new Label(buildPathsInterpreted, SWT.NONE); appPathLabel.setText("&Output Directory (applications only)"); appPathLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1)); appOutputPath = new Text(buildPathsInterpreted, SWT.BORDER | SWT.SINGLE); GridData appPathData = new GridData(GridData.FILL_HORIZONTAL); appPathData.horizontalSpan = 2; appOutputPath.setLayoutData(appPathData); buildPathsNative = new Composite(buildPaths, SWT.NONE); buildPathsNative.setLayout(new GridLayout(2, false)); buildPathsNative.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Label includeNativePathsLabel = new Label(buildPathsNative, SWT.NONE); includeNativePathsLabel.setText("Additional &Include Paths (relative to project):"); includeNativePathsLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1)); additionalNativeIncludePathsText = new Text(buildPathsNative, SWT.BORDER | SWT.SINGLE); additionalNativeIncludePathsText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1)); addContentAssist(additionalIncludePathsText); if (supportsExtensions) { Label extensionsLabel = new Label(buildPathsNative, SWT.NONE); extensionsLabel.setText("Extensions"); extensionsLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1)); extensions = new Text(buildPathsNative, SWT.BORDER | SWT.SINGLE); GridData extensionsData = new GridData(GridData.FILL_HORIZONTAL); extensionsData.horizontalSpan = 2; extensions.setLayoutData(extensionsData); } } protected void reinitUI() { main.dispose(); fillPlaceHolder(placeHolder); } private void initUI() { listener.setActive(false); IPropertyOwner projectWorkingCopy = getWorkingCopyOfBuildConfiguration(getProject()); boolean isLibraryProject = MoSyncBuilder.PROJECT_TYPE_LIBRARY.equals(projectWorkingCopy.getProperty(addBuildProperty(MoSyncBuilder.PROJECT_TYPE))); boolean isExtensionProject = MoSyncBuilder.PROJECT_TYPE_EXTENSION.equals(projectWorkingCopy.getProperty(addBuildProperty(MoSyncBuilder.PROJECT_TYPE))); boolean isAppProject = !isLibraryProject && !isExtensionProject; libraryProjectType.setSelection(isLibraryProject); applicationProjectType.setSelection(isAppProject); binaryType.setText(getBinaryTypeLabel(getProject().getProperty(MoSyncBuilder.OUTPUT_TYPE))); incrementalBuildStrategy.select(PropertyUtil.getInteger(projectWorkingCopy, addBuildProperty(MoSyncProject.DEPENDENCY_STRATEGY), MoSyncProject.GCC_DEPENDENCY_STRATEGY)); IPropertyOwner configProperties = getWorkingCopyOfBuildConfiguration(); ignoreDefaultIncludePaths.setSelection(PropertyUtil.getBoolean(configProperties, addBuildProperty(MoSyncBuilder.IGNORE_DEFAULT_INCLUDE_PATHS))); setText(additionalIncludePathsText, configProperties.getProperty(addBuildProperty(MoSyncBuilder.ADDITIONAL_INCLUDE_PATHS))); setText(additionalNativeIncludePathsText, configProperties.getProperty(addBuildProperty(MoSyncBuilder.ADDITIONAL_NATIVE_INCLUDE_PATHS))); ignoreDefaultLibraryPaths.setSelection(PropertyUtil.getBoolean(configProperties, addBuildProperty(MoSyncBuilder.IGNORE_DEFAULT_LIBRARY_PATHS))); setText(additionalLibraryPathsText, configProperties.getProperty(addBuildProperty(MoSyncBuilder.ADDITIONAL_LIBRARY_PATHS))); ignoreDefaultLibraries.setSelection(PropertyUtil.getBoolean(configProperties, addBuildProperty(MoSyncBuilder.IGNORE_DEFAULT_LIBRARIES))); setText(additionalLibrariesText, configProperties.getProperty(addBuildProperty(MoSyncBuilder.ADDITIONAL_LIBRARIES))); setText(excludeFiles, configProperties.getProperty(addBuildProperty(MoSyncProject.EXCLUDE_FILTER_KEY))); setText(libOutputPath, configProperties.getProperty(addBuildProperty(MoSyncBuilder.LIB_OUTPUT_PATH))); setText(appOutputPath, configProperties.getProperty(addBuildProperty(MoSyncBuilder.APP_OUTPUT_PATH))); deadCodeElim.setSelection(PropertyUtil.getBoolean(configProperties, addBuildProperty(MoSyncBuilder.DEAD_CODE_ELIMINATION))); setText(gccFlags, configProperties.getProperty(addBuildProperty(MoSyncBuilder.EXTRA_COMPILER_SWITCHES))); setText(extraRes, configProperties.getProperty(addBuildProperty(MoSyncBuilder.EXTRA_RES_SWITCHES))); setText(extraLink, configProperties.getProperty(addBuildProperty(MoSyncBuilder.EXTRA_LINK_SWITCHES))); Integer gcc = PropertyUtil.getInteger(configProperties, addBuildProperty(MoSyncBuilder.GCC_WARNINGS)); gccWerror.setSelection(gcc != null && (gcc & MoSyncBuilder.GCC_WERROR) != 0); gccWall.setSelection(gcc != null && (gcc & MoSyncBuilder.GCC_WALL) != 0); gccWextra.setSelection(gcc != null && (gcc & MoSyncBuilder.GCC_WEXTRA) != 0); setText(heapSize, configProperties.getProperty(addBuildProperty(MoSyncBuilder.MEMORY_HEAPSIZE_KB))); setText(stackSize, configProperties.getProperty(addBuildProperty(MoSyncBuilder.MEMORY_STACKSIZE_KB))); setText(dataSize, configProperties.getProperty(addBuildProperty(MoSyncBuilder.MEMORY_DATASIZE_KB))); useDebugRuntimes.setSelection(PropertyUtil.getBoolean(configProperties, addBuildProperty(MoSyncBuilder.USE_DEBUG_RUNTIME_LIBS))); String outputType = configProperties.getProperty(addBuildProperty(MoSyncBuilder.OUTPUT_TYPE)); setText(version, configProperties.getProperty(addBuildProperty(MoSyncBuilder.PROJECT_VERSION))); setText(vendor, configProperties.getProperty(addBuildProperty(DefaultPackager.APP_VENDOR_NAME_BUILD_PROP))); setText(appName, configProperties.getProperty(addBuildProperty(MoSyncBuilder.APP_NAME))); if (supportsExtensions) { setText(extensions, configProperties.getProperty(addBuildProperty(MoSyncBuilder.EXTENSIONS))); extensionProjectType.setSelection(isExtensionProject); } listener.setActive(true); updateUI(); } private String addBuildProperty(String buildProperty) { buildProperties.add(buildProperty); return buildProperty; } public void changeConfiguration(IBuildConfiguration cfg) { this.currentConfigId = cfg == null ? null : cfg.getId(); } public void changeConfiguration(String id) { this.currentConfigId = id; } public IPropertyOwner getBuildConfigurationProperties() { if (currentConfigId == null) { return getProject(); } else { IBuildConfiguration cfg = getProject().getBuildConfiguration(currentConfigId); return cfg == null ? getProject() : cfg.getProperties(); } } public IPropertyOwner getWorkingCopyOfBuildConfiguration() { IPropertyOwner original = getBuildConfigurationProperties(); return getWorkingCopyOfBuildConfiguration(original); } public IPropertyOwner getWorkingCopyOfBuildConfiguration(IPropertyOwner original) { IPropertyOwner workingCopy = workingCopies.get(original); if (workingCopy == null) { if (original == getProject()) { projectWorkingCopy = new PropertyOwnerWorkingCopy(original); workingCopy = projectWorkingCopy; } else { String ns = ((NameSpacePropertyOwner) original).getNamespace(); workingCopy = new NameSpacePropertyOwner(getWorkingCopyOfBuildConfiguration(getProject()), ns); } workingCopies.put(original, workingCopy); } return workingCopy; } void clearWorkingCopies() { workingCopies.clear(); } boolean applyWorkingCopies() { boolean result = projectWorkingCopy.apply(); return result; } @Override public void updateUI() { boolean wasActive = listener.isActive(); listener.setActive(false); boolean isLibOrExtProject = !applicationProjectType.getSelection(); deadCodeElim.setEnabled(!isLibOrExtProject); libOutputPath.setEnabled(isLibOrExtProject); appOutputPath.setEnabled(!isLibOrExtProject); boolean isInterpreted = getBinaryType().equals(MoSyncBuilder.OUTPUT_TYPE_INTERPRETED); incrementalBuildStrategy.setEnabled(isInterpreted); libraryProjectType.setEnabled(isInterpreted); boolean isNative = getBinaryType().equals(MoSyncBuilder.OUTPUT_TYPE_NATIVE_COMPILE); librariesLabel.setEnabled(!isNative); excludeFilesLabel.setEnabled(!isNative); libraryPathsLabel.setEnabled(!isNative); additionalLibrariesText.setEnabled(!isNative); additionalLibrariesText.setEchoChar(isNative ? ' ' : '\0'); additionalLibraryPathsText.setEnabled(!isNative); additionalLibraryPathsText.setEchoChar(isNative ? ' ' : '\0'); ignoreDefaultLibraries.setEnabled(!isNative); ignoreDefaultLibraryPaths.setEnabled(!isNative); excludeFiles.setEnabled(!isNative); additionalLibraryPathsText.setEchoChar(isNative ? ' ' : '\0'); extraLinkLabel.setVisible(!isNative); extraLink.setVisible(!isNative); deadCodeElim.setVisible(!isNative); gccWarningsLabel.setVisible(!isNative); gccWall.setVisible(!isNative); gccWerror.setVisible(!isNative); gccWextra.setVisible(!isNative); memoryGroup.setVisible(!isNative); heapSize.setEnabled(!isNative); stackSize.setEnabled(!isNative); dataSize.setEnabled(!isNative); heapSize.setEchoChar(isNative ? ' ' : '\0'); stackSize.setEchoChar(isNative ? ' ' : '\0'); dataSize.setEchoChar(isNative ? ' ' : '\0'); Control oldTop = buildPathsLayout.topControl; Control newTop = isNative ? buildPathsNative : buildPathsInterpreted; if (oldTop != newTop) { buildPathsLayout.topControl = newTop; buildPaths.layout(); } super.updateUI(); listener.setActive(wasActive); } @Override protected void validate() { ValidationMessageProvider message = new ValidationMessageProvider(); if (appName.getText().indexOf('.') != -1) { message.setMessage(appName, new DefaultMessageProvider("Application name should not have an extension", IMessageProvider.ERROR)); } validatePathsField(message, "Additional Libraries", additionalLibrariesText, null); validatePathsField(message, "Additional Library Paths", additionalLibraryPathsText, null); validatePathsField(message, "Additional Include Paths", additionalIncludePathsText, null); validateMemorySettings(message); if (libraryProjectType.getSelection() || (supportsExtensions && extensionProjectType.getSelection())) { if (libOutputPath.getText().length() > 0 && Util.getExtension(new File(libOutputPath.getText())).length() == 0) { message.setMessage(libOutputPath, new DefaultMessageProvider("Output file has no extension", IMessageProvider.WARNING)); } if (libOutputPath.getText().length() == 0) { message.setMessage(libOutputPath, new DefaultMessageProvider("Library output file must be set", IMessageProvider.ERROR)); } } if (supportsExtensions) { String[] extensionList = PropertyUtil.toStrings(extensions.getText()); for (String extensionName : extensionList) { MoSyncExtension extension = MoSyncExtensionManager.getDefault().getExtension(extensionName); if (extension == null) { message.setMessage(extensions, new DefaultMessageProvider("Extension does not exist: " + extensionName, IMessageProvider.WARNING)); } } } setMessage(message); } private void validateMemorySettings(ValidationMessageProvider provider) { if (!new Version(version.getText()).isValid()) { provider.setMessage(version, new DefaultMessageProvider("Invalid version format, must comply to major[.minor][.micro][.qualifier]", IMessageProvider.ERROR)); } provider.setMessage(stackSize, validateInteger(stackSize.getText(), "Stack size", 1L << 22)); provider.setMessage(heapSize, validateInteger(heapSize.getText(), "Heap size", 1L << 22)); provider.setMessage(dataSize, validateInteger(dataSize.getText(), "Data size", 1L << 22)); if (provider.isEmpty(stackSize) && provider.isEmpty(heapSize) && provider.isEmpty(dataSize)) { // They're all integers long stackSize = Long.parseLong(this.stackSize.getText()); long heapSize = Long.parseLong(this.heapSize.getText()); long dataSize = Long.parseLong(this.dataSize.getText()); if (dataSize < stackSize + heapSize) { provider.setMessage(this.dataSize, new DefaultMessageProvider("Data size must be at least as large as the stack and heap sizes combined", IMessageProvider.ERROR)); } else if (ceil2p(dataSize) != dataSize) { provider.setMessage(this.dataSize, new DefaultMessageProvider(MessageFormat.format("Will round up data size to nearest power of 2 ({0} kb)", ceil2p(dataSize)), IMessageProvider.INFORMATION)); } } } private long ceil2p(long size) { size--; for (int i = 1; i < 64 / 2; i <<= 1) { size = size | (size >> i); } size++; return size; } private IMessageProvider validateInteger(String value, String fieldName, long max) { try { long numericalValue = Long.parseLong(value); if (numericalValue > max) { return new DefaultMessageProvider(MessageFormat.format("Value of {0} too large; must be no more than {1}", fieldName, max), IMessageProvider.ERROR); } } catch (Exception e) { return new DefaultMessageProvider(MessageFormat.format("{0} must be an integer value", fieldName), IMessageProvider.ERROR); } return DefaultMessageProvider.EMPTY; } @Override public void performDefaults() { ArrayList<IPropertyOwner> workingCopies = new ArrayList<IPropertyOwner>(); MoSyncProject project = getProject(); if (project.areBuildConfigurationsSupported()) { for (String configId : project.getBuildConfigurations()) { IPropertyOwner wc = getWorkingCopyOfBuildConfiguration(project.getBuildConfiguration(configId).getProperties()); workingCopies.add(wc); } } IPropertyOwner projectWorkingCopy = getWorkingCopyOfBuildConfiguration(project); workingCopies.add(projectWorkingCopy); for (IPropertyOwner workingCopy : workingCopies) { for (String property : buildProperties) { workingCopy.setToDefault(property); } } // TODO: That container based properties stuff :) // Because we might have wanted this behaviour in all // property & preference pages String templateId = getProject().getProperty(MoSyncProject.TEMPLATE_ID); ProjectTemplate template = templateId == null ? null : TemplateManager.getDefault().getProjectTemplate(templateId); if (template != null) { Map<String, String> defaultTemplateProperties = template.getSettings(); for (String property : defaultTemplateProperties.keySet()) { // This is not fool-proof, but will cover most of the templates we've created I guess. String key = NameSpacePropertyOwner.getKey(property); if (buildProperties.contains(key)) { String value = defaultTemplateProperties.get(property); projectWorkingCopy.setProperty(property, value); } } } initUI(); } @Override public boolean performOk() { // First, update. updateCurrentBuildConfiguration(); // Then, apply. boolean changed = applyWorkingCopies(); changed |= !getBinaryType().equals(getProject().getProperty(MoSyncBuilder.OUTPUT_TYPE)); try { if (changed) { getProject().setOutputType(getBinaryType()); } } catch (IllegalArgumentException e) { String message = MessageFormat.format( "The current project build settings are not suitable for {0} projects:\n\n{1}\n\nDo you want to automatically adjust the project?", getBinaryType(), e.getMessage()); if (MessageDialog.openQuestion(getShell(), "Change project?", message)) { getProject().forceOutputType(getBinaryType()); } } return true; } @Override public boolean performCancel() { clearWorkingCopies(); return super.performCancel(); } public boolean updateCurrentBuildConfiguration() { IPropertyOwner configProperties = getWorkingCopyOfBuildConfiguration(); boolean changed = false; changed |= PropertyUtil.setInteger(getProject(), MoSyncProject.DEPENDENCY_STRATEGY, incrementalBuildStrategy.getSelectionIndex()); changed |= configProperties.setProperty(MoSyncBuilder.ADDITIONAL_INCLUDE_PATHS, additionalIncludePathsText.getText().replace(';', ',')); changed |= PropertyUtil.setBoolean(configProperties, MoSyncBuilder.IGNORE_DEFAULT_INCLUDE_PATHS, ignoreDefaultIncludePaths.getSelection()); changed |= configProperties.setProperty(MoSyncBuilder.ADDITIONAL_NATIVE_INCLUDE_PATHS, additionalNativeIncludePathsText.getText().replace(';', ',')); changed |= configProperties.setProperty(MoSyncBuilder.ADDITIONAL_LIBRARY_PATHS, additionalLibraryPathsText.getText().replace(';', ',')); changed |= PropertyUtil.setBoolean(configProperties, MoSyncBuilder.IGNORE_DEFAULT_LIBRARY_PATHS, ignoreDefaultLibraryPaths.getSelection()); changed |= configProperties.setProperty(MoSyncBuilder.ADDITIONAL_LIBRARIES, additionalLibrariesText.getText().replace(';', ',')); changed |= PropertyUtil.setBoolean(configProperties, MoSyncBuilder.IGNORE_DEFAULT_LIBRARIES, ignoreDefaultLibraries.getSelection()); changed |= configProperties.setProperty(MoSyncProject.EXCLUDE_FILTER_KEY, excludeFiles.getText()); changed |= configProperties.setProperty(MoSyncBuilder.LIB_OUTPUT_PATH, libOutputPath.getText()); changed |= configProperties.setProperty(MoSyncBuilder.APP_OUTPUT_PATH, appOutputPath.getText()); changed |= PropertyUtil.setBoolean(configProperties, MoSyncBuilder.DEAD_CODE_ELIMINATION, deadCodeElim.getSelection()); String projectTypeProperty = MoSyncBuilder.PROJECT_TYPE_APPLICATION; if (libraryProjectType.getSelection()) { projectTypeProperty = MoSyncBuilder.PROJECT_TYPE_LIBRARY; } if (supportsExtensions && extensionProjectType.getSelection()) { projectTypeProperty = MoSyncBuilder.PROJECT_TYPE_EXTENSION; } changed |= getProject().setProperty(MoSyncBuilder.PROJECT_TYPE, projectTypeProperty); changed |= configProperties.setProperty(MoSyncBuilder.EXTRA_COMPILER_SWITCHES, gccFlags.getText()); changed |= configProperties.setProperty(MoSyncBuilder.EXTRA_RES_SWITCHES, extraRes.getText()); changed |= configProperties.setProperty(MoSyncBuilder.EXTRA_LINK_SWITCHES, extraLink.getText()); int gccWarnings = 0; gccWarnings |= gccWerror.getSelection() ? MoSyncBuilder.GCC_WERROR : 0; gccWarnings |= gccWall.getSelection() ? MoSyncBuilder.GCC_WALL : 0; gccWarnings |= gccWextra.getSelection() ? MoSyncBuilder.GCC_WEXTRA : 0; changed |= PropertyUtil.setInteger(configProperties, MoSyncBuilder.GCC_WARNINGS, gccWarnings); changed |= configProperties.setProperty(MoSyncBuilder.MEMORY_HEAPSIZE_KB, heapSize.getText()); changed |= configProperties.setProperty(MoSyncBuilder.MEMORY_STACKSIZE_KB, stackSize.getText()); changed |= configProperties.setProperty(MoSyncBuilder.MEMORY_DATASIZE_KB, dataSize.getText()); changed |= PropertyUtil.setBoolean(configProperties, MoSyncBuilder.USE_DEBUG_RUNTIME_LIBS, useDebugRuntimes.getSelection()); changed |= configProperties.setProperty(MoSyncBuilder.PROJECT_VERSION, version.getText()); changed |= configProperties.setProperty(DefaultPackager.APP_VENDOR_NAME_BUILD_PROP, vendor.getText()); changed |= configProperties.setProperty(MoSyncBuilder.APP_NAME, appName.getText()); if (supportsExtensions) { changed |= configProperties.setProperty(MoSyncBuilder.EXTENSIONS, extensions.getText()); } return changed; } private String getBinaryTypeLabel(String binaryType) { if (MoSyncBuilder.OUTPUT_TYPE_NATIVE_COMPILE.equals(binaryType)) { return BINARY_TYPE_NATIVE; } else if (MoSyncBuilder.OUTPUT_TYPE_STATIC_RECOMPILATION.equals(binaryType)) { return BINARY_TYPE_RECOMPILED; } else { return BINARY_TYPE_INTERPRETED; } } private String getBinaryType() { String selectedType = binaryType.getText(); if (BINARY_TYPE_NATIVE.equals(selectedType)) { return MoSyncBuilder.OUTPUT_TYPE_NATIVE_COMPILE; } else if (BINARY_TYPE_RECOMPILED.equals(selectedType)) { return MoSyncBuilder.OUTPUT_TYPE_STATIC_RECOMPILATION; } else { return MoSyncBuilder.OUTPUT_TYPE_INTERPRETED; } } @Override public void propertyChange(PropertyChangeEvent event) { String property = event.getPropertyName(); if (MoSyncProject.BUILD_CONFIGURATION_SUPPORT_CHANGED.equals(property) || MoSyncProject.BUILD_CONFIGURATION_CHANGED.equals(property)) { reinitUI(); } } @Override public void dispose() { getProject().removePropertyChangeListener(this); super.dispose(); } }