blob: 51afa97c7815877951bfffd8f7807b8cef98ef9e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2015 Xored Software Inc 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:
* Xored Software Inc - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.rcptt.ui.editors;
import static com.google.common.util.concurrent.Uninterruptibles.sleepUninterruptibly;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.eclipse.rcptt.ui.launching.LaunchUtils.runResource;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.resources.IResource;
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.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.emf.databinding.EMFObservables;
import org.eclipse.emf.databinding.EMFProperties;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.window.Window;
import org.eclipse.rcptt.core.model.IQ7NamedElement;
import org.eclipse.rcptt.core.model.ModelException;
import org.eclipse.rcptt.core.scenario.NamedElement;
import org.eclipse.rcptt.core.scenario.ScenarioPackage;
import org.eclipse.rcptt.core.tags.Tag;
import org.eclipse.rcptt.core.utils.TagsUtil;
import org.eclipse.rcptt.internal.ui.Images;
import org.eclipse.rcptt.internal.ui.Messages;
import org.eclipse.rcptt.launching.IExecutable;
import org.eclipse.rcptt.launching.ILaunchListener;
import org.eclipse.rcptt.launching.LaunchAdapter;
import org.eclipse.rcptt.launching.Q7Launcher;
import org.eclipse.rcptt.ui.commons.OneSelectionListener;
import org.eclipse.rcptt.ui.launching.LaunchUtils;
import org.eclipse.rcptt.ui.tags.SelectTagDialog;
import org.eclipse.rcptt.util.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.IFormColors;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.internal.forms.widgets.FormImages;
@SuppressWarnings("restriction")
public abstract class EditorHeader {
protected DataBindingContext dbc = new DataBindingContext();
protected StyledText nameText;
protected ControlDecoration nameDecoration;
protected Button addTag;
protected StyledText tagsControl;
private Button recordButton;
private Button replayButton;
private IQ7NamedElement model;
private NamedElement element;
private Binding nameBinding;
private Binding tagsBinging;
public EditorHeader(IQ7NamedElement model, NamedElement element) {
this.model = model;
this.element = element;
}
public IQ7NamedElement getModel() {
return model;
}
public NamedElement getElement() {
return element;
}
public DataBindingContext getDataBindingContext() {
return dbc;
}
public StyledText getTagsControl() {
return tagsControl;
}
public Button getRecordButton() {
return recordButton;
}
public Button getReplayButton() {
return replayButton;
}
public Composite createContent(Composite parent, FormToolkit toolkit) {
GridLayoutFactory.fillDefaults().margins(0, 0).spacing(0, 0)
.equalWidth(true).applyTo(parent);
createGeneral(parent, toolkit);
Composite composite = toolkit.createComposite(parent);
GridDataFactory.fillDefaults().grab(true, true).applyTo(composite);
GridLayoutFactory.fillDefaults().margins(5, 5).spacing(0, 0)
.equalWidth(true).applyTo(composite);
update(this.model, this.element);
return composite;
}
protected void createGeneral(Composite parent, FormToolkit toolkit) {
Composite composite = toolkit.createComposite(parent);
GridLayoutFactory.swtDefaults().numColumns(getTotalColumns())
.spacing(10, 4).applyTo(composite);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP)
.grab(true, false).applyTo(composite);
createNameControl(composite, toolkit);
recordButton = createRecordButton(composite, toolkit);
createTagControl(composite, toolkit);
replayButton = createReplayButton(composite, toolkit);
int height = composite.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
Color top = toolkit.getColors().getColor(IFormColors.H_GRADIENT_END);
Color bot = toolkit.getColors().getColor(IFormColors.H_GRADIENT_START);
Image gradientImage = FormImages.getInstance().getGradient(
new Color[] { top, bot }, new int[] { 100 }, height, true,
toolkit.getColors().getColor(IFormColors.TB_BG),
composite.getDisplay());
// No need to dispose the gradient image cause it's created and stored
// in resource manager
composite.setBackgroundImage(gradientImage);
Composite c1 = toolkit.createComposite(parent);
GridDataFactory.fillDefaults().hint(SWT.DEFAULT, 1).span(4, 1)
.grab(true, false).applyTo(c1);
c1.setBackground(toolkit.getColors().getColor(
IFormColors.H_BOTTOM_KEYLINE1));
Composite c2 = toolkit.createComposite(parent);
GridDataFactory.fillDefaults().hint(SWT.DEFAULT, 1).span(4, 1)
.grab(true, false).applyTo(c2);
c2.setBackground(toolkit.getColors().getColor(
IFormColors.H_BOTTOM_KEYLINE2));
// if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
// // We need to simulate transparent background for labels
// composite.layout();
// setBackgroundToHeaderLabel(nameLabel, gradientImage);
// setBackgroundToHeaderLabel(tagsLabel, gradientImage);
// }
}
protected int getTotalColumns() {
return 4;
}
public void focus() {
nameText.setFocus();
}
protected void createNameControl(Composite parent, FormToolkit toolkit) {
createLabel(parent, toolkit,
Messages.NamedElementEditorPage_NameLabel);
nameText = createWrappedText(parent, toolkit, element.getName(), 2);
nameText.setBackground(null);
nameDecoration = new ControlDecoration(nameText, SWT.TOP | SWT.LEFT);
FieldDecoration errorFieldIndicator = FieldDecorationRegistry
.getDefault().getFieldDecoration(
FieldDecorationRegistry.DEC_ERROR);
nameDecoration.setImage(errorFieldIndicator.getImage());
nameDecoration.setMarginWidth(2);
nameDecoration.setShowHover(true);
nameDecoration.hide();
}
protected Menu createTextMenu(final StyledText text) {
Menu menu = new Menu(text);
MenuItem copy = new MenuItem(menu, SWT.PUSH);
copy.setText("Copy");
copy.addSelectionListener(new OneSelectionListener() {
@Override
public void selected(SelectionEvent e) {
if (TextUtils.canCopy(text))
TextUtils.copy(text);
}
});
MenuItem paste = new MenuItem(menu, SWT.PUSH);
paste.setText("Paste");
paste.addSelectionListener(new OneSelectionListener() {
@Override
public void selected(SelectionEvent e) {
if (TextUtils.canPaste(text))
TextUtils.paste(text);
}
});
MenuItem cut = new MenuItem(menu, SWT.PUSH);
cut.setText("Cut");
cut.addSelectionListener(new OneSelectionListener() {
@Override
public void selected(SelectionEvent e) {
if (TextUtils.canCut(text))
TextUtils.cut(text);
}
});
return menu;
}
protected StyledText createWrappedText(Composite parent,
FormToolkit toolkit, String text, int hSpan) {
Composite composite = toolkit.createComposite(parent);
GridLayoutFactory.fillDefaults().equalWidth(true).applyTo(composite);
GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER)
.span(hSpan, 1).grab(true, false).applyTo(composite);
StyledText textControl = new StyledText(composite, SWT.BORDER
| SWT.SINGLE | toolkit.getBorderStyle()
| toolkit.getOrientation());
textControl.setText(text);
toolkit.adapt(textControl);
GridDataFactory.swtDefaults().align(SWT.FILL, SWT.FILL)
.grab(true, true).hint(111, SWT.DEFAULT).applyTo(textControl);
textControl.setBackground(null);
textControl.setMenu(createTextMenu(textControl));
return textControl;
}
protected void createTagControl(Composite parent, FormToolkit toolkit) {
createLabel(parent, toolkit,
Messages.NamedElementEditorPage_TagsLabel);
Composite tags = toolkit.createComposite(parent, SWT.NONE);
tags.setBackground(null);
GridLayoutFactory.fillDefaults().spacing(3, 0).numColumns(2)
.margins(0, 0).applyTo(tags);
GridDataFactory.fillDefaults().grab(true, false)
.span(getTagsSpacing(), 1).applyTo(tags);
tagsControl = new StyledText(tags, SWT.BORDER | SWT.SINGLE
| toolkit.getBorderStyle() | toolkit.getOrientation());
toolkit.adapt(tagsControl);
tagsControl.setBackground(null);
tagsControl.setMenu(createTextMenu(tagsControl));
GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER)
.grab(true, false).applyTo(tagsControl);
addTag = toolkit.createButton(tags, "", SWT.PUSH); //$NON-NLS-1$
addTag.setToolTipText(Messages.NamedElementEditorPage_AddTagButton);
addTag.setBackground(null);
GridDataFactory.swtDefaults().align(SWT.LEFT, SWT.CENTER)
.applyTo(addTag);
addTag.setImage(PlatformUI.getWorkbench().getSharedImages()
.getImageDescriptor(ISharedImages.IMG_OBJ_ADD).createImage());
addTag.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
final List<String> existingTags = TagsUtil.extractTags(element
.getTags());
final SelectTagDialog dialog = new SelectTagDialog(tagsControl
.getShell(), existingTags);
if (dialog.open() == SelectTagDialog.OK) {
final StringBuilder sb = new StringBuilder(element
.getTags());
boolean first = existingTags.isEmpty();
if (!dialog.getResult().isEmpty()) {
for (final Tag tag : dialog.getResult()) {
if (!first) {
sb.append(", "); //$NON-NLS-1$
} else {
first = false;
}
sb.append(tag.getPath());
}
element.setTags(sb.toString());
} else if (dialog.getTagName() != null) {
if (sb.toString().length() != 0) {
sb.append(", "); //$NON-NLS-1$
}
sb.append(dialog.getTagName().trim());
element.setTags(sb.toString());
}
}
}
});
}
protected int getTagsSpacing() {
return 2;
}
protected Button createRecordButton(Composite composite, FormToolkit toolkit) {
Button button = toolkit.createButton(composite,
Messages.NamedElementEditorPage_RecordButton, SWT.PUSH);
button.setImage(Images.getImageDescriptor(Images.RECORD).createImage());
button.setBackground(null);
GridDataFactory.fillDefaults().applyTo(button);
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
record();
}
});
return button;
}
protected Button createReplayButton(Composite composite, FormToolkit toolkit) {
Button button = toolkit.createButton(composite,
Messages.NamedElementEditorPage_ReplayButton, SWT.PUSH);
button.setImage(DebugUITools.getImageDescriptor(
IDebugUIConstants.IMG_ACT_RUN).createImage());
button.setBackground(null);
GridDataFactory.fillDefaults().applyTo(button);
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
if ((e.stateMask & SWT.SHIFT) != 0)
multiReplay();
else
replay();
}
});
return button;
}
protected Label createLabel(Composite parent, FormToolkit toolkit,
final String label) {
Label labelControl = new Label(parent, SWT.NONE);
labelControl.setText(label);
labelControl.setForeground(toolkit.getColors().getColor(
IFormColors.TITLE));
GridDataFactory.swtDefaults().align(SWT.BEGINNING, SWT.CENTER)
.applyTo(labelControl);
labelControl.setBackground(null);
return labelControl;
}
protected void setBackgroundToHeaderLabel(Label label, Image backgroundImage) {
Rectangle bounds = label.getBounds();
bounds.x = 0;
bounds.width = 1;
final Image image = new Image(label.getDisplay(), bounds);
GC gc = new GC(image);
gc.drawImage(backgroundImage, bounds.x, bounds.y, bounds.width,
bounds.height, 0, 0, bounds.width, bounds.height);
gc.dispose();
label.setBackgroundImage(image);
label.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
image.dispose();
}
});
}
protected abstract void record();
protected void replay() {
IResource res = model.getResource();
if (res == null)
return;
LaunchUtils.launchContext(new IResource[] { res }, "run"); //$NON-NLS-1$
}
private static int getReplayCount() {
InputDialog in = new InputDialog(null,
Messages.NamedElementEditorPage_RunCounterDialogTitle,
Messages.NamedElementEditorPage_RunCounterDialogLabel,
Messages.NamedElementEditorPage_RunCounterDialogDefaultValue,
new IInputValidator() {
public String isValid(String newText) {
try {
int value = Integer.parseInt(newText);
if (value <= 0) {
return Messages.NamedElementEditorPage_RunCounterDialogNeagtiveIntErrorMsg;
}
} catch (Throwable e) {
return Messages.NamedElementEditorPage_RunCounterDialogIncorrectIntErrorMsg;
}
return null;
}
});
if (in.open() != Window.OK) {
return -1;
}
return Integer.parseInt(in.getValue());
}
private static boolean resourceSaved(IResource res) {
try {
return LaunchUtils.saveChanges(new IResource[] { res });
} catch (ModelException e) {
return false;
}
}
protected void multiReplay() {
final IResource res = model.getResource();
if (res == null) {
return;
}
int count = getReplayCount();
if (count == -1) {
return;
}
if (!resourceSaved(res)) {
return;
}
final AtomicInteger countAtom = new AtomicInteger(count);
final Job execJob = new Job("Times execute") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
runResource(res);
return Status.OK_STATUS;
}
};
final ILaunchListener listener = new LaunchAdapter() {
public void launchStatusChanged(IExecutable... executable) {
for (IExecutable e : executable) {
if (!e.getResultStatus().isOK()) {
countAtom.set(0);
}
}
}
public void finished() {
if (countAtom.decrementAndGet() > 0) {
execJob.schedule(500);
}
}
};
Job cancelationJob = new Job("Times execution") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
int count = countAtom.get();
monitor.beginTask("Times", count); //$NON-NLS-1$
while (!monitor.isCanceled() && (count = countAtom.get()) > 0) {
sleepUninterruptibly(100, MILLISECONDS);
monitor.worked(count - countAtom.get());
}
countAtom.set(0);
Q7Launcher.getInstance().removeListener(listener);
return Status.OK_STATUS;
}
};
cancelationJob.schedule();
cancelationJob.setPriority(Job.LONG);
Q7Launcher.getInstance().addListener(listener);
execJob.schedule();
}
public boolean isInFocus() {
if (nameText.isFocusControl() || tagsControl.isFocusControl()) {
return true;
}
return false;
}
public void doSelectAll() {
if (nameText.isFocusControl()) {
nameText.selectAll();
} else if (tagsControl.isFocusControl()) {
tagsControl.selectAll();
}
}
public void copy() {
if (nameText.isFocusControl()) {
TextUtils.copy(nameText);
} else if (tagsControl.isFocusControl()) {
TextUtils.copy(tagsControl);
}
}
public boolean canCopy() {
if (nameText.isFocusControl()) {
return TextUtils.canCopy(nameText);
} else if (tagsControl.isFocusControl()) {
return TextUtils.canCopy(tagsControl);
}
return false;
}
public boolean canPaste() {
if (nameText.isFocusControl()) {
return TextUtils.canPaste(nameText);
} else if (tagsControl.isFocusControl()) {
return TextUtils.canPaste(tagsControl);
}
return false;
}
public boolean canCut() {
if (nameText.isFocusControl()) {
return TextUtils.canCut(nameText);
} else if (tagsControl.isFocusControl()) {
return TextUtils.canCut(tagsControl);
}
return false;
}
public void paste() {
if (nameText.isFocusControl()) {
TextUtils.paste(nameText);
} else if (tagsControl.isFocusControl()) {
TextUtils.paste(tagsControl);
}
}
public void cut() {
if (nameText.isFocusControl()) {
TextUtils.cut(nameText);
} else if (tagsControl.isFocusControl()) {
TextUtils.cut(tagsControl);
}
}
private IStatus nameFail(String message) {
nameDecoration.setDescriptionText(message);
nameDecoration.show();
return Status.CANCEL_STATUS;
}
private IStatus nameWin() {
nameDecoration.hide();
return Status.OK_STATUS;
}
public void update(final IQ7NamedElement model, NamedElement element) {
this.model = model;
this.element = element;
if (nameText != null) {
if (nameBinding != null) {
nameBinding.dispose();
}
UpdateValueStrategy strategy = new UpdateValueStrategy();
strategy.setBeforeSetValidator(new IValidator() {
public IStatus validate(Object value) {
String text = (String) value;
if (StringUtils.isBlank(text))
return nameFail("Name must be non-blank string.");
// that is toooo slooooow
// IQ7NamedElement[] found = Q7SearchCore.findByName(text,
// new OneProjectScope(model.getQ7Project()),
// new NullProgressMonitor());
// for (IQ7NamedElement e : found)
// if (e != model && e.getClass() == model.getClass())
// return nameFail("Name is already in use.");
return nameWin();
}
});
nameBinding = dbc.bindValue(SWTObservables.observeText(nameText,
SWT.Modify), EMFObservables.observeValue(element,
ScenarioPackage.eINSTANCE.getNamedElement_Name()),
strategy, null);
}
if (tagsControl != null) {
if (tagsBinging != null) {
tagsBinging.dispose();
}
tagsBinging = dbc.bindValue(
SWTObservables.observeText(tagsControl, SWT.Modify),
EMFProperties.value(
ScenarioPackage.Literals.NAMED_ELEMENT__TAGS)
.observe(element));
}
}
public void doTextCommand(int fAction) {
if (nameText.isFocusControl()) {
nameText.invokeAction(fAction);
} else if (tagsControl.isFocusControl()) {
tagsControl.invokeAction(fAction);
}
}
public boolean canUndo() {
return false;
}
public boolean canRedo() {
return false;
}
public void undo() {
}
public void redo() {
}
protected StyledText getNameControl() {
return nameText;
}
}