/******************************************************************************* * Copyright (c) 2011, 2014 Mentor Graphics 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: * Vladimir Prus (Mentor Graphics) - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.internal.ui.osview; import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS2.IResourceClass; import org.eclipse.jface.action.ContributionItem; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; /** * @since 2.4 */ public class ResourceClassContributionItem extends ContributionItem { // In some places below, we are trying to determine size hint for Combo, given the list of // content. However, while we can determine width of content, we don't know how much width // the combobox itself is adding. This constant is our guess. private static final int COMBO_TRIM_WIDTH = 64; interface Listener { void resourceClassChanged(String newClass); } private Combo fResourceClassCombo; private IResourceClass[] resourceClasses = new IResourceClass[0]; private String fResourceClassId = null; private Listener fListener; private boolean blockListener = false; private ToolItem toolItem; private boolean enabled = true; private static IDialogSettings settings; private static IDialogSettings getDialogSettings() { if (settings != null) return settings; IDialogSettings topSettings = GdbUIPlugin.getDefault().getDialogSettings(); settings = topSettings.getSection(ResourceClassContributionItem.class.getName()); if (settings == null) { settings = topSettings.addNewSection(ResourceClassContributionItem.class.getName()); } return settings; } public void setListener(Listener listener) { fListener = listener; } public void setEnabled(boolean enable) { // It appears that every update of action bars will call 'fill' action below, creating // combo. So, we want to keep 'enabled' state as member variable, to make sure it is kept // if combo is recreated. enabled = enable; if (fResourceClassCombo != null) fResourceClassCombo.setEnabled(enable); } public String updateClasses(IResourceClass[] resourceClasses) { boolean different = false; if (this.resourceClasses.length != resourceClasses.length) different = true; else for (int i = 0; i < this.resourceClasses.length; ++i) { if (!this.resourceClasses[i].getId().equals(resourceClasses[i].getId()) || !this.resourceClasses[i].getHumanDescription().equals(resourceClasses[i].getHumanDescription())) { different = true; break; } } if (!different) return fResourceClassId; this.resourceClasses = resourceClasses; fResourceClassCombo.removeAll(); final int width = populateCombo(); // Now change the width. Call to setWidth causes relayout automatically. // IMPORTANT: the visibility check is critical. Without it, we appear to have hit // an SWT/Gtk bug whenever a debug session and a previously use OS resources view // is not shown. The bug manifests by 100% CPU consumption inside event loop, and // it further blocks asyncExec runnables from ever executing. I suppose it might // be specific to relayout of invisible toolbar. // If we're invisible, we don't arrange for relayout to happen when the view becomes // available, because it is not exactly trivial (we need to events on the right control) // and it only matters when we start a new session and it has a different set of // resource classes and that requires longer combobox. if (toolItem.getParent().isVisible()) toolItem.setWidth(width); return fResourceClassId; } /** Populate the combobox with resource classes. Return the width the * combobox must have, including any trim. If there are no resource classes, * returns some reasonable default width. */ private int populateCombo() { int width = 0; String lastResourceClassId = getDialogSettings().get("resourceClass"); //$NON-NLS-1$ int index = -1; int i = 0; GC gc = new GC(fResourceClassCombo); for (i = 0; i < resourceClasses.length; ++i) { String description = resourceClasses[i].getHumanDescription(); width = Math.max(width, gc.textExtent(description).x); fResourceClassCombo.add(description); if (resourceClasses[i].getId().equals(lastResourceClassId)) index = i; } if (index != -1) { fResourceClassId = lastResourceClassId; blockListener = true; fResourceClassCombo.select(index); blockListener = false; } if (width == 0) { // We have some hints what the longest element in combo will be. Even if it's different // in new GDB version, no problem -- the combo will be resized when it's populated. width = gc.textExtent("Shared memory regions").x; //$NON-NLS-1$ } // Because there's no way whatsoever to set the width // of the combobox list, only complete length, we just add // random padding. width = width + COMBO_TRIM_WIDTH; return width; } public String getResourceClassId() { return fResourceClassId; } @Override public void fill(ToolBar parent, int toolbarItemIndex) { fResourceClassCombo = new Combo(parent, SWT.NONE); fResourceClassCombo.setEnabled(enabled); int width = populateCombo(); fResourceClassCombo.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent e) { String description = fResourceClassCombo.getText(); String id = null; for (int i = 0; i < resourceClasses.length; ++i) if (resourceClasses[i].getHumanDescription().equals(description)) { id = resourceClasses[i].getId(); break; } // id is never null here, unless we messed up our data structures. assert id != null; if (id != null && !id.equals(fResourceClassId)) { fResourceClassId = id; getDialogSettings().put("resourceClass", id); //$NON-NLS-1$ if (fListener != null && !blockListener) fListener.resourceClassChanged(fResourceClassId); } } @Override public void widgetDefaultSelected(SelectionEvent e) { } }); toolItem = new ToolItem(parent, SWT.SEPARATOR); toolItem.setControl(fResourceClassCombo); toolItem.setWidth(width); } @Override public boolean isDynamic() { return false; } }