Skip to content

Commit

Permalink
Enable searchable tree for the e4 model editor
Browse files Browse the repository at this point in the history
Setting is relatively hidden for new users (or existing ones) and it is
really useful. The readonly tab is not a big functionality loss as this
text is rarely modified directly.
  • Loading branch information
vogella committed Sep 30, 2024
1 parent f9b743f commit 6ca4635
Showing 1 changed file with 211 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
/*******************************************************************************
* Copyright (c) 2014, 2017 TwelveTone LLC and others.
* Copyright (c) 2010-2014 BestSolution.at and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Steven Spungin <[email protected]> - initial API and implementation, Bug 391089, Bug 437543, Ongoing Maintenance
*******************************************************************************/

package org.eclipse.e4.tools.emf.ui.internal.common.component.tabs;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.core.services.nls.Translation;
import org.eclipse.e4.tools.emf.ui.internal.Messages;
import org.eclipse.e4.tools.emf.ui.internal.common.xml.AnnotationAccess;
import org.eclipse.e4.tools.emf.ui.internal.common.xml.EMFDocumentResourceMediator;
import org.eclipse.e4.tools.emf.ui.internal.common.xml.XMLConfiguration;
import org.eclipse.e4.tools.emf.ui.internal.common.xml.XMLPartitionScanner;
import org.eclipse.e4.tools.services.IResourcePool;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource.Diagnostic;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.rules.FastPartitioner;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.AnnotationModel;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.text.source.VerticalRuler;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;

public class XmiTab extends Composite {

private static final String ORG_ECLIPSE_E4_TOOLS_MODELEDITOR_FILTEREDTREE_ENABLED_XMITAB_DISABLED = "org.eclipse.e4.tools.modeleditor.filteredtree.enabled.xmitab.disabled";//$NON-NLS-1$
private static final int VERTICAL_RULER_WIDTH = 20;

@Inject
private IEclipseContext context;

@Optional
@Inject
private IProject project;
@Inject
private EMFDocumentResourceMediator emfDocumentProvider;
@Inject
private IResourcePool resourcePool;
@Inject
private IEclipsePreferences preferences;

@Inject
@Translation
protected Messages Messages;

private Text text;
protected int offsetStart;
private SourceViewer sourceViewer;

@Inject
public XmiTab(Composite parent) {
super(parent, SWT.NONE);
setLayout(new GridLayout(1, false));
}

@PostConstruct
protected void postConstruct() {
text = new Text(this, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
text.setMessage(Messages.XmiTab_TypeTextToSearch);
text.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.keyCode != SWT.CR) {
offsetStart = 0;
}
offsetStart = searchAndHighlight(text.getText(), offsetStart);
}
});

final AnnotationModel model = new AnnotationModel();
final VerticalRuler verticalRuler = new VerticalRuler(VERTICAL_RULER_WIDTH, new AnnotationAccess(resourcePool));
final int styles = SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION;
sourceViewer = new SourceViewer(this, verticalRuler, styles);
sourceViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

sourceViewer.configure(new XMLConfiguration(resourcePool));
sourceViewer.setEditable(project != null);
sourceViewer.getTextWidget().setFont(JFaceResources.getTextFont());

final IDocument document = emfDocumentProvider.getDocument();
final IDocumentPartitioner partitioner = new FastPartitioner(new XMLPartitionScanner(), new String[] {
XMLPartitionScanner.XML_TAG, XMLPartitionScanner.XML_COMMENT });
partitioner.connect(document);
document.setDocumentPartitioner(partitioner);
sourceViewer.setDocument(document);
verticalRuler.setModel(model);

emfDocumentProvider.setValidationChangedCallback(() -> {
model.removeAllAnnotations();

for (final Diagnostic d : emfDocumentProvider.getErrorList()) {
final Annotation a = new Annotation("e4xmi.error", false, d.getMessage()); //$NON-NLS-1$
int l;
try {
l = document.getLineOffset(d.getLine() - 1);
model.addAnnotation(a, new Position(l));
} catch (final BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});

final String property = System
.getProperty(ORG_ECLIPSE_E4_TOOLS_MODELEDITOR_FILTEREDTREE_ENABLED_XMITAB_DISABLED);
if (property != null || preferences.getBoolean("tab-form-search-show", true)) { //$NON-NLS-1$
sourceViewer.setEditable(false);
sourceViewer.getTextWidget().setEnabled(false);
}
}

/**
*
* @param text
* @param startOffset
* @return The endOFfset, or -1 if not found
*/
protected int searchAndHighlight(String text, int startOffset) {
try {
// select the entire start tag
IRegion region;
region = emfDocumentProvider.findText(text, startOffset);
if (region == null && startOffset > 0) {
region = emfDocumentProvider.findText(text, 0);
}
if (region != null) {
sourceViewer.setSelection(new TextSelection(region.getOffset(), region.getLength()), true);
return region.getOffset() + region.getLength();
}
sourceViewer.setSelection(new TextSelection(0, 0), true);
return -1;
} catch (final Exception e) {
e.printStackTrace();
return -1;
}
}

public IEclipseContext getContext() {
return context;
}

public void gotoEObject(EObject object) {
// select the entire start tag
final IRegion region = emfDocumentProvider.findStartTag(object);
if (region != null) {
sourceViewer.setSelection(new TextSelection(region.getOffset(), region.getLength()), true);
} else {
sourceViewer.setSelection(new TextSelection(0, 0), true);
}
}

public void paste() {
if (isFilterTextFocused()) {
text.paste();
} else {
sourceViewer.getTextWidget().paste();
}
}

public void copy() {
if (isFilterTextFocused()) {
text.copy();
} else {
sourceViewer.getTextWidget().copy();
}
}

public void cut() {
if (isFilterTextFocused()) {
text.cut();
} else {
sourceViewer.getTextWidget().cut();
}
}

private boolean isFilterTextFocused() {
return text.isFocusControl();
}

}

0 comments on commit 6ca4635

Please sign in to comment.