/******************************************************************************* * Copyright (c) 2015 ARM Ltd. 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: * ARM Ltd and ARM Germany GmbH - Initial API and implementation *******************************************************************************/ package com.arm.cmsis.pack.ui.widgets; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; 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.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Tree; import com.arm.cmsis.pack.common.CmsisConstants; import com.arm.cmsis.pack.data.CpItem; import com.arm.cmsis.pack.data.ICpDeviceItem; import com.arm.cmsis.pack.data.ICpItem; import com.arm.cmsis.pack.enums.EDeviceHierarchyLevel; import com.arm.cmsis.pack.info.CpDeviceInfo; import com.arm.cmsis.pack.info.ICpDeviceInfo; import com.arm.cmsis.pack.rte.devices.IRteDeviceItem; import com.arm.cmsis.pack.ui.CpPlugInUI; import com.arm.cmsis.pack.ui.CpStringsUI; import com.arm.cmsis.pack.ui.IStatusMessageListener; import com.arm.cmsis.pack.ui.OpenURL; import com.arm.cmsis.pack.ui.StatusMessageListerenList; import com.arm.cmsis.pack.ui.tree.TreeObjectContentProvider; import com.arm.cmsis.pack.utils.WildCards; /** * Widget to select a CMSIS device */ public class RteDeviceSelectorWidget extends Composite { private Text text; Text txtSearch; private Label lblVendor; private Label lblDevice; private Label lblCpu; Combo comboFpu; Combo comboEndian; IRteDeviceItem fDevices = null; IRteDeviceItem fSelectedItem = null; private ICpDeviceItem fSelectedDevice = null; private ICpDeviceInfo fDeviceInfo = null; private TreeViewer treeViewer; // list of listeners (e.g parent widgets to monitor events) StatusMessageListerenList listeners = new StatusMessageListerenList(); String fSearchString = CmsisConstants.EMPTY_STRING; String selectedFpu; String selectedEndian; boolean updatingControls = false; private Label lblMemory; private Link linkUrl; String url = CmsisConstants.EMPTY_STRING; private Label lblPack; private Label lblClock; public class RteDeviceLabeProvider extends LabelProvider{ @Override public Image getImage(Object element) { if(element instanceof IRteDeviceItem) { IRteDeviceItem item = (IRteDeviceItem)element; if(item.getLevel() == EDeviceHierarchyLevel.VENDOR.ordinal()) { return CpPlugInUI.getImage(CpPlugInUI.ICON_COMPONENT); } else if(item.hasChildren()) { return CpPlugInUI.getImage(CpPlugInUI.ICON_COMPONENT_CLASS); } return CpPlugInUI.getImage(CpPlugInUI.ICON_DEVICE); } return null; } @Override public String getText(Object element) { if(element instanceof IRteDeviceItem) { IRteDeviceItem item = (IRteDeviceItem)element; return item.getName(); } return CmsisConstants.EMPTY_STRING; } } /** * Create the composite. * @param parent * @param style */ public RteDeviceSelectorWidget(Composite parent) { super(parent, SWT.NONE); GridLayout gridLayout = new GridLayout(6, false); gridLayout.horizontalSpacing = 8; setLayout(gridLayout); Label lblDeviceLabel = new Label(this, SWT.NONE); lblDeviceLabel.setText(CpStringsUI.RteDeviceSelectorWidget_DeviceLabel); lblDevice = new Label(this, SWT.NONE); lblDevice.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); new Label(this, SWT.NONE); Label lblCpuLabel = new Label(this, SWT.NONE); lblCpuLabel.setText(CpStringsUI.RteDeviceSelectorWidget_CPULabel); lblCpuLabel.setBounds(0, 0, 36, 13); lblCpu = new Label(this, SWT.NONE); lblCpu.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); lblCpu.setBounds(0, 0, 32, 13); new Label(this, SWT.NONE); Label lblVendorLabel = new Label(this, SWT.NONE); lblVendorLabel.setText(CpStringsUI.RteDeviceSelectorWidget_VendorLabel); lblVendor = new Label(this, SWT.NONE); lblVendor.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); new Label(this, SWT.NONE); Label lblClocklabel = new Label(this, SWT.NONE); lblClocklabel.setText(CpStringsUI.RteDeviceSelectorWidget_lblClocklabel_text); lblClock = new Label(this, SWT.NONE); lblClock.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); new Label(this, SWT.NONE); Label lblPackLabel = new Label(this, SWT.NONE); lblPackLabel.setText(CpStringsUI.RteDeviceSelectorWidget_lblPack_text); lblPack = new Label(this, SWT.NONE); lblPack.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); new Label(this, SWT.NONE); Label lblMemoryLabel = new Label(this, SWT.NONE); lblMemoryLabel.setText(CpStringsUI.RteDeviceSelectorWidget_lblMemory); lblMemory = new Label(this, SWT.NONE); lblMemory.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); new Label(this, SWT.NONE); Label lblUrlLabel = new Label(this, SWT.NONE); lblUrlLabel.setText(CpStringsUI.RteDeviceSelectorWidget_lblUrl); linkUrl = new Link(this, SWT.NONE); linkUrl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); linkUrl.addSelectionListener(new SelectionAdapter(){ @Override public void widgetSelected(SelectionEvent e) { OpenURL.open(url, getShell()); } }); new Label(this, SWT.NONE); Label lblFpuLabel = new Label(this, SWT.NONE); lblFpuLabel.setText(CpStringsUI.RteDeviceSelectorWidget_FPULabel); lblFpuLabel.setBounds(0, 0, 38, 13); comboFpu = new Combo(this, SWT.READ_ONLY); comboFpu.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { if(updatingControls) { return; } int index = comboFpu.getSelectionIndex(); selectedFpu = fpuIndexToString(index); } }); comboFpu.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); new Label(this, SWT.NONE); Label lblSearch = new Label(this, SWT.NONE); lblSearch.setText(CpStringsUI.RteDeviceSelectorWidget_SearchLabel); txtSearch = new Text(this, SWT.BORDER); txtSearch.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { setSearchText(txtSearch.getText()); } }); txtSearch.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); txtSearch.setToolTipText(CpStringsUI.RteDeviceSelectorWidget_SearchTooltip); new Label(this, SWT.NONE); Label lblEndian = new Label(this, SWT.NONE); lblEndian.setText(CpStringsUI.RteDeviceSelectorWidget_Endian); lblEndian.setBounds(0, 0, 37, 13); comboEndian = new Combo(this, SWT.READ_ONLY); comboEndian.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { if(updatingControls) { return; } selectedEndian = adjustEndianString(comboEndian.getText()); } }); comboEndian.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); new Label(this, SWT.NONE); treeViewer = new TreeViewer(this, SWT.BORDER); treeViewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { handleTreeSelectionChanged(event); } }); Tree tree = treeViewer.getTree(); GridData gd_tree = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1); gd_tree.minimumWidth = 240; tree.setLayoutData(gd_tree); treeViewer.setContentProvider(new TreeObjectContentProvider()); treeViewer.setLabelProvider(new RteDeviceLabeProvider()); treeViewer.addFilter(new ViewerFilter() { @Override public boolean select(Viewer viewer, Object parentElement, Object element) { if(fSearchString.isEmpty() || fSearchString.equals("*")) { //$NON-NLS-1$ return true; } if(element instanceof IRteDeviceItem) { String s = CmsisConstants.EMPTY_STRING; if(!fSearchString.startsWith("*")) { //$NON-NLS-1$ s = "*"; //$NON-NLS-1$ } s += fSearchString; if(!s.endsWith("*")) { //$NON-NLS-1$ s += "*"; //$NON-NLS-1$ } // first check if parent elements (vendor, family, etc. match the pattern) IRteDeviceItem deviceItem = (IRteDeviceItem)element; for(IRteDeviceItem parent = deviceItem.getParent(); parent != null; parent = parent.getParent()) { if(WildCards.matchNoCase(s, parent.getName())) { return true; } } return deviceItem.getFirstItem(s) != null; } return false; } }); text = new Text(this, SWT.BORDER | SWT.WRAP | SWT.V_SCROLL); GridData gd_text = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1); gd_text.widthHint = 240; gd_text.minimumWidth = 200; text.setLayoutData(gd_text); text.setEditable(false); setTabList(new Control[]{txtSearch, tree, comboFpu, comboEndian}); addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(DisposeEvent e) { fSelectedItem = null; fDevices = null; listeners.removeAllListeners(); listeners = null; } }); } boolean setSearchText(String s) { // Search must be a substring of the existing value if(fSearchString != s){ fSearchString = s; IRteDeviceItem deviceItem = null; if(!fSearchString.isEmpty() && !fSearchString.equals("*")) { //$NON-NLS-1$ String pattern = fSearchString; if(!pattern.endsWith("*")) //$NON-NLS-1$ { pattern += "*"; //$NON-NLS-1$ } if(fSelectedItem != null && fSelectedItem.getFirstItem(pattern) == fSelectedItem){ deviceItem = fSelectedItem; } else { deviceItem = fDevices.getFirstItem(pattern); } } refreshTree(); if(deviceItem != null) { selectItem(deviceItem); treeViewer.setExpandedState(deviceItem, true); } } return false; } private void refreshTree(){ treeViewer.refresh(); } /** * Sets collection of the available devices * @param devices IRteDeviceItem root of device tree */ public void setDevices(IRteDeviceItem devices) { this.fDevices = devices; treeViewer.setInput(devices); } /** * Returns selected device item * @return selected IRteDeviceItem */ public IRteDeviceItem getSelectedDeviceItem() { if(fSelectedDevice != null) { return fSelectedItem; } return null; } protected void handleTreeSelectionChanged(SelectionChangedEvent event) { IRteDeviceItem selectedItem = getSelectedItem(); if(selectedItem == fSelectedItem) { return; } fSelectedItem = selectedItem; updateDeviceInfo(); updateControls(); } protected void updateControls() { updatingControls = true; String description = CmsisConstants.EMPTY_STRING; String vendorName = CmsisConstants.EMPTY_STRING; String deviceName = CmsisConstants.EMPTY_STRING; String cpu = CmsisConstants.EMPTY_STRING; String clock = CmsisConstants.EMPTY_STRING; String pack = CmsisConstants.EMPTY_STRING; String mem = CmsisConstants.EMPTY_STRING; url = CmsisConstants.EMPTY_STRING; String urlText = CmsisConstants.EMPTY_STRING; String message = null; if(fSelectedItem != null) { IRteDeviceItem vendorItem = fSelectedItem.getVendorItem(); if(vendorItem != null) { vendorName = vendorItem.getName(); } if(fSelectedItem.isDevice()) { deviceName = fSelectedItem.getName(); url = fSelectedItem.getUrl(); if(!url.isEmpty()) { urlText = "<a href=\"" + url + "\">" + url + "</a>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } description = fSelectedItem.getDescription(); } else { message = "Device is not installed. Please install the pack first, or select a new device"; //$NON-NLS-1$ } if(fDeviceInfo != null) { clock = fDeviceInfo.getClockSummary(); pack = fDeviceInfo.getPackId(); cpu = "ARM " + fDeviceInfo.getAttribute(CmsisConstants.DCORE); //$NON-NLS-1$ mem = fDeviceInfo.getMemorySummary(); // this happens in the import process, when the device is not installed if (deviceName.isEmpty()) { deviceName = fDeviceInfo.getDeviceName(); } if (vendorName.isEmpty()) { vendorName = fDeviceInfo.getVendor(); } if (url.isEmpty()) { url = fDeviceInfo.getUrl(); if (!url.isEmpty()) { urlText = "<a href=\"" + url + "\">" + url + "</a>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } } else { message = CpStringsUI.RteDeviceSelectorWidget_NoDeviceSelected; } lblVendor.setText(vendorName); lblDevice.setText(deviceName); text.setText(description); lblCpu.setText(cpu); lblClock.setText(clock); lblPack.setText(pack); linkUrl.setText(urlText); linkUrl.setToolTipText(url); lblMemory.setText(mem); updateFpu(); updateEndian(); updateStatus(message); updatingControls = false; } private void updateDeviceInfo() { if(fSelectedItem != null && fSelectedItem.isDevice()) { fSelectedDevice = fSelectedItem.getDevice(); fDeviceInfo = null; ICpItem props = fSelectedItem.getEffectiveProperties(); if(props != null) { fDeviceInfo = new CpDeviceInfo(null, fSelectedItem); } } else { fSelectedDevice = null; fDeviceInfo = null; } } /** * Returns IRteDeviceItem currently selected in the tree */ private IRteDeviceItem getSelectedItem() { IStructuredSelection sel= (IStructuredSelection)treeViewer.getSelection(); if(sel.size() == 1) { Object o = sel.getFirstElement(); if(o instanceof IRteDeviceItem ){ return (IRteDeviceItem)o; } } return null; } private void updateEndian() { String endian = null; if(fDeviceInfo != null) { endian = fDeviceInfo.getAttribute(CmsisConstants.DENDIAN); } String[] endianStrings = getEndianStrings(endian); comboEndian.setItems(endianStrings); endian = adjustEndianString(selectedEndian); int index = comboEndian.indexOf(endian); if(index < 0 || index >= endianStrings.length) { index = 0; } comboEndian.select(index); comboEndian.setEnabled(endianStrings.length > 1); } private String[] getEndianStrings(String endian){ if(endian != null) { switch(endian){ case CmsisConstants.BIGENDIAN: return new String[]{CmsisConstants.BIGENDIAN}; case CmsisConstants.CONFIGENDIAN: case "*": //$NON-NLS-1$ return new String[]{CmsisConstants.LITTLENDIAN, CmsisConstants.BIGENDIAN}; case CmsisConstants.LITTLENDIAN: default: return new String[]{CmsisConstants.LITTLENDIAN}; } } return new String[]{CmsisConstants.EMPTY_STRING}; } String adjustEndianString(String endian){ if(endian != null) { if(endian.equals(CmsisConstants.BIGENDIAN) || endian.equals(CmsisConstants.LITTLENDIAN)) { return endian; } } return CmsisConstants.LITTLENDIAN; } private void updateFpu() { String fpu = null; if(fDeviceInfo != null) { fpu = fDeviceInfo.getAttribute(CmsisConstants.DFPU); } String[] fpuStrings = getFpuStrings(fpu); int index = fpuStringToIndex(selectedFpu); if(index < 0 || index >= fpuStrings.length) { index = fpuStringToIndex(fpu); } if(index < 0) { index = 0; } comboFpu.setItems(fpuStrings); comboFpu.select(index); comboFpu.setEnabled(fpuStrings.length > 1); } private String[] getFpuStrings(String fpu){ if(fpu != null) { switch(fpu){ case "1": //$NON-NLS-1$ case CmsisConstants.FPU: case CmsisConstants.SP_FPU: return new String[]{CpStringsUI.RteDeviceSelectorWidget_none, CpStringsUI.RteDeviceSelectorWidget_SinglePrecision}; case CmsisConstants.DP_FPU: return new String[]{CpStringsUI.RteDeviceSelectorWidget_none, CpStringsUI.RteDeviceSelectorWidget_SinglePrecision, CpStringsUI.RteDeviceSelectorWidget_DoublePrecision}; default: return new String[]{CpStringsUI.RteDeviceSelectorWidget_none}; } } return new String[]{CmsisConstants.EMPTY_STRING}; } String fpuIndexToString(int index){ switch(index){ case 1: return CmsisConstants.SP_FPU; case 2: return CmsisConstants.DP_FPU; default: break; } return CmsisConstants.NO_FPU; } private int fpuStringToIndex(String fpu){ if(fpu != null) { switch(fpu){ case "1": //$NON-NLS-1$ case CmsisConstants.FPU: case CmsisConstants.SP_FPU: return 1; case CmsisConstants.DP_FPU: return 2; default: return 0; } } return -1; } private void updateStatus(String message) { // notify listeners listeners.notifyListeners(message); } public void addListener(IStatusMessageListener listener){ listeners.addListener(listener); } public void removeListener(IStatusMessageListener listener){ listeners.removeListener(listener); } /** * Returns device info for selected device * @return ICpDeviceInfo */ public ICpDeviceInfo getDeviceInfo() { if(fDeviceInfo != null){ int index = comboFpu.getSelectionIndex(); String fpu = fpuIndexToString(index); fDeviceInfo.attributes().setAttribute(CmsisConstants.DFPU, fpu); String endian = comboEndian.getText(); if(endian == null || endian.isEmpty()) { endian = CmsisConstants.LITTLENDIAN; } fDeviceInfo.attributes().setAttribute(CmsisConstants.DENDIAN, endian); } return fDeviceInfo; } public void setDeviceInfo(ICpDeviceInfo deviceInfo) { fDeviceInfo = deviceInfo; if(fDeviceInfo != null) { selectedFpu = fDeviceInfo.getAttribute(CmsisConstants.DFPU); selectedEndian = fDeviceInfo.getAttribute(CmsisConstants.DENDIAN); // set initial selection IRteDeviceItem item = fDevices.findItem(fDeviceInfo.attributes()); if(item != null ){ selectItem(item); } else { String message = NLS.bind(CpStringsUI.RteDeviceSelectorWidget_DeviceNotFound, CpItem.getDeviceName(deviceInfo.attributes())); updateStatus(message); } updateControls(); }else { updateStatus(CpStringsUI.RteDeviceSelectorWidget_NoDeviceSelected); } } /** * Selects given device item in the tree * @param item device item to select */ public void selectItem(IRteDeviceItem item){ if(item != null ){ Object[] path = item.getHierachyPath(); TreePath tp = new TreePath(path); TreeSelection ts = new TreeSelection(tp); treeViewer.setSelection(ts, true); } } }