/*******************************************************************************
* Copyright 2011 Google Inc. All Rights Reserved.
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.google.gwt.eclipse.oophm.breadcrumbs;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MenuDetectEvent;
import org.eclipse.swt.events.MenuDetectListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
/**
* The label and icon part of the breadcrumb item.
*
* NOTE: This code was derived from
* org.eclipse.jdt.internal.ui.javaeditor.breadcrumb.BreadcrumbItemDetails.
*
* @since 3.4
*/
class BreadcrumbItemDetails {
private final Label fElementImage;
private final Label fElementText;
private final Composite fDetailComposite;
private final BreadcrumbItem fParent;
private final Composite fTextComposite;
private final Composite fImageComposite;
private boolean fTextVisible;
private boolean fSelected;
private boolean fHasFocus;
public BreadcrumbItemDetails(BreadcrumbItem parent, Composite parentContainer) {
fParent = parent;
fTextVisible = true;
fDetailComposite = new Composite(parentContainer, SWT.NONE);
fDetailComposite.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER,
false, false));
GridLayout layout = new GridLayout(2, false);
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.horizontalSpacing = 0;
fDetailComposite.setLayout(layout);
addElementListener(fDetailComposite);
fImageComposite = new Composite(fDetailComposite, SWT.NONE);
fImageComposite.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER,
false, false));
layout = new GridLayout(1, false);
layout.marginHeight = 1;
layout.marginWidth = 2;
fImageComposite.setLayout(layout);
fImageComposite.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
if (fHasFocus && !isTextVisible()) {
e.gc.drawFocus(e.x, e.y, e.width, e.height);
}
}
});
installFocusComposite(fImageComposite);
addElementListener(fImageComposite);
fElementImage = new Label(fImageComposite, SWT.NONE);
GridData layoutData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false);
fElementImage.setLayoutData(layoutData);
addElementListener(fElementImage);
fTextComposite = new Composite(fDetailComposite, SWT.NONE);
fTextComposite.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false,
false));
layout = new GridLayout(1, false);
layout.marginHeight = 2;
layout.marginWidth = 2;
fTextComposite.setLayout(layout);
addElementListener(fTextComposite);
fTextComposite.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
if (fHasFocus && isTextVisible()) {
e.gc.drawFocus(e.x, e.y, e.width, e.height);
}
}
});
installFocusComposite(fTextComposite);
addElementListener(fTextComposite);
fElementText = new Label(fTextComposite, SWT.NONE);
layoutData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false);
fElementText.setLayoutData(layoutData);
addElementListener(fElementText);
fTextComposite.getAccessible().addAccessibleListener(
new AccessibleAdapter() {
public void getName(AccessibleEvent e) {
e.result = fElementText.getText();
}
});
fImageComposite.getAccessible().addAccessibleListener(
new AccessibleAdapter() {
public void getName(AccessibleEvent e) {
e.result = fElementText.getText();
}
});
fDetailComposite.setTabList(new Control[] {fTextComposite});
}
/**
* Returns the width of this element.
*
* @return current width of this element
*/
public int getWidth() {
int result = 2;
if (fElementImage.getImage() != null)
result += fElementImage.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
if (fTextVisible && fElementText.getText().length() > 0)
result += fElementText.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
return result;
}
/**
* Returns whether this element has the keyboard focus.
*
* @return true if this element has the keyboard focus.
*/
public boolean hasFocus() {
return fHasFocus;
}
/**
* Tells whether this item shows a text or only an image.
*
* @return <code>true</code> if it shows a text and an image, false if it only
* shows the image
*/
public boolean isTextVisible() {
return fTextVisible;
}
public void setFocus(boolean enabled) {
if (enabled == fHasFocus)
return;
fHasFocus = enabled;
if (fHasFocus) {
if (isTextVisible()) {
fTextComposite.setFocus();
} else {
fImageComposite.setFocus();
}
}
updateSelection();
}
/**
* Sets the image to the given image.
*
* @param image the image to use
*/
public void setImage(Image image) {
if (image != fElementImage.getImage()) {
fElementImage.setImage(image);
}
}
public void setSelected(boolean selected) {
if (selected == fSelected)
return;
fSelected = selected;
if (!fSelected)
fHasFocus = false;
updateSelection();
}
/**
* Sets the text to the given text.
*
* @param text the text to use
*/
public void setText(String text) {
if (text == null) {
text = ""; //$NON-NLS-1$
}
if (!text.equals(fElementText.getText())) {
fElementText.setText(text);
}
}
public void setTextVisible(boolean enabled) {
if (fTextVisible == enabled)
return;
fTextVisible = enabled;
GridData data = (GridData) fTextComposite.getLayoutData();
data.exclude = !enabled;
fTextComposite.setVisible(enabled);
if (fTextVisible) {
fDetailComposite.setTabList(new Control[] {fTextComposite});
} else {
fDetailComposite.setTabList(new Control[] {fImageComposite});
}
if (fHasFocus) {
if (isTextVisible()) {
fTextComposite.setFocus();
} else {
fImageComposite.setFocus();
}
}
updateSelection();
}
/**
* Sets the tool tip to the given text.
*
* @param text the tool tip
*/
public void setToolTip(String text) {
if (isTextVisible()) {
fElementText.getParent().setToolTipText(text);
fElementText.setToolTipText(text);
fElementImage.setToolTipText(text);
} else {
fElementText.getParent().setToolTipText(null);
fElementText.setToolTipText(null);
fElementImage.setToolTipText(text);
}
}
/**
* Sets whether details should be shown.
*
* @param visible <code>true</code> if details should be shown
*/
public void setVisible(boolean visible) {
fDetailComposite.setVisible(visible);
GridData data = (GridData) fDetailComposite.getLayoutData();
data.exclude = !visible;
}
/**
* Add mouse listeners to the given control.
*
* @param control the control to which may be clicked
*/
private void addElementListener(Control control) {
control.addMouseListener(new MouseListener() {
public void mouseDoubleClick(MouseEvent e) {
}
public void mouseDown(MouseEvent e) {
BreadcrumbViewer viewer = fParent.getViewer();
int parentIndex = viewer.getIndexOfItem(fParent) - 1;
Shell shell = null;
if (parentIndex >= 0) {// sanity check, must always hold
BreadcrumbItem dropDownItem = viewer.getItem(parentIndex);
shell = dropDownItem.getDropDownShell();
}
viewer.selectItem(fParent);
if (shell == null && e.button == 1 && e.stateMask == 0) {
fParent.getViewer().fireDoubleClick();
}
}
public void mouseUp(MouseEvent e) {
}
});
control.addMenuDetectListener(new MenuDetectListener() {
public void menuDetected(MenuDetectEvent e) {
BreadcrumbViewer viewer = fParent.getViewer();
viewer.selectItem(fParent);
fParent.getViewer().fireMenuDetect(e);
}
});
}
/**
* Install focus and key listeners to the given composite.
*
* @param composite the composite which may get focus
*/
private void installFocusComposite(Composite composite) {
composite.addTraverseListener(new TraverseListener() {
public void keyTraversed(TraverseEvent e) {
if (e.detail == SWT.TRAVERSE_TAB_NEXT
|| e.detail == SWT.TRAVERSE_TAB_PREVIOUS) {
int index = fParent.getViewer().getIndexOfItem(fParent);
if (e.detail == SWT.TRAVERSE_TAB_NEXT) {
index++;
} else {
index--;
}
if (index > 0 && index < fParent.getViewer().getItemCount()) {
fParent.getViewer().selectItem(fParent.getViewer().getItem(index));
}
e.doit = true;
}
}
});
composite.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
BreadcrumbViewer viewer = fParent.getViewer();
switch (e.keyCode) {
case SWT.ARROW_LEFT:
if (fSelected) {
viewer.doTraverse(false);
e.doit = false;
} else {
viewer.selectItem(fParent);
}
break;
case SWT.ARROW_RIGHT:
if (fSelected) {
viewer.doTraverse(true);
e.doit = false;
} else {
viewer.selectItem(fParent);
}
break;
case SWT.ARROW_DOWN:
if (!fSelected) {
viewer.selectItem(fParent);
}
openDropDown();
e.doit = false;
break;
case SWT.KEYPAD_ADD:
if (!fSelected) {
viewer.selectItem(fParent);
}
openDropDown();
e.doit = false;
break;
case SWT.CR:
if (!fSelected) {
viewer.selectItem(fParent);
}
viewer.fireOpen();
break;
default:
if (e.character == ' ') {
if (!fSelected) {
viewer.selectItem(fParent);
}
openDropDown();
e.doit = false;
}
break;
}
}
public void keyReleased(KeyEvent e) {
}
private void openDropDown() {
BreadcrumbViewer viewer = fParent.getViewer();
int index = viewer.getIndexOfItem(fParent);
BreadcrumbItem parent = fParent.getViewer().getItem(index - 1);
Shell shell = parent.getDropDownShell();
if (shell == null) {
parent.openDropDownMenu();
shell = parent.getDropDownShell();
}
shell.setFocus();
}
});
composite.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
if (!fHasFocus) {
fHasFocus = true;
updateSelection();
}
}
public void focusLost(FocusEvent e) {
if (fHasFocus) {
fHasFocus = false;
updateSelection();
}
}
});
}
private void updateSelection() {
Color background;
Color foreground;
if (fSelected && fHasFocus) {
background = Display.getDefault().getSystemColor(SWT.COLOR_LIST_SELECTION);
foreground = Display.getDefault().getSystemColor(
SWT.COLOR_LIST_SELECTION_TEXT);
} else {
foreground = null;
background = null;
}
if (isTextVisible()) {
fTextComposite.setBackground(background);
fElementText.setBackground(background);
fElementText.setForeground(foreground);
fImageComposite.setBackground(null);
fElementImage.setBackground(null);
} else {
fImageComposite.setBackground(background);
fElementImage.setBackground(background);
fTextComposite.setBackground(null);
fElementText.setBackground(null);
fElementText.setForeground(null);
}
fTextComposite.redraw();
fImageComposite.redraw();
}
}