From 17cc072b5a127263dd648133241c09d8d31490e8 Mon Sep 17 00:00:00 2001 From: Zoey Gerrit Prigge Date: Fri, 4 May 2018 14:36:06 +0200 Subject: [PATCH] [532244] adequate HTML label doubleClicking support - new DotHtmlLabelDoubleClickStrategy implemented - adapted DotTerminalsTokenTypeToPartitionMapper to introduce custom HTML label partitionType - custom DotDoubleClickStrategyProvider to provide DotHtmlLabelDoubleClickStrategy for custom HTML label partitionType - adapted DotHtmlLabelTerminalsTokenTypeToPartitionMapper to introduce custom HTML text type - custom DotHtmlLabelDoubleClickStrategyProvider to map text type - bound custom DotDoubleClickStrategyProvider in DotUiModule - bound custom DotHtmlLabelDoubleClickStrategyProvider in DotHtmlLabelUiModule - DotEditorDoubleClickingTests extended for HTML label cases - DotHtmlLabelTokenTypeToPartitionMapperTests and DotTokenTypeToPartitionMapperTests changed to expect amended results Signed-off-by: Zoey Gerrit Prigge Bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=532244 --- .../tests/DotEditorDoubleClickingTests.xtend | 319 ++++++++++++++++++ ...LabelTokenTypeToPartitionMapperTests.xtend | 10 +- .../DotTokenTypeToPartitionMapperTests.xtend | 10 +- .../ui/language/DotHtmlLabelUiModule.java | 12 +- .../dot/internal/ui/language/DotUiModule.java | 27 +- .../DotDoubleClickStrategyProvider.java | 33 ++ .../DotHtmlLabelDoubleClickStrategy.java | 186 ++++++++++ ...tHtmlLabelDoubleClickStrategyProvider.java | 34 ++ ...elTerminalsTokenTypeToPartitionMapper.java | 24 +- ...otTerminalsTokenTypeToPartitionMapper.java | 24 +- 10 files changed, 661 insertions(+), 18 deletions(-) create mode 100644 org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/doubleclicking/DotDoubleClickStrategyProvider.java create mode 100644 org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/doubleclicking/DotHtmlLabelDoubleClickStrategy.java create mode 100644 org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/doubleclicking/DotHtmlLabelDoubleClickStrategyProvider.java diff --git a/org.eclipse.gef.dot.tests/src/org/eclipse/gef/dot/tests/DotEditorDoubleClickingTests.xtend b/org.eclipse.gef.dot.tests/src/org/eclipse/gef/dot/tests/DotEditorDoubleClickingTests.xtend index e15d0f1ca3..50b1ff11c7 100644 --- a/org.eclipse.gef.dot.tests/src/org/eclipse/gef/dot/tests/DotEditorDoubleClickingTests.xtend +++ b/org.eclipse.gef.dot.tests/src/org/eclipse/gef/dot/tests/DotEditorDoubleClickingTests.xtend @@ -472,6 +472,199 @@ class DotEditorDoubleClickingTests extends AbstractEditorDoubleClickTextSelectio '''.assertSelectedTextAfterDoubleClicking('''"x11"''') } + @Test def edge_html_label_001() { + ''' + digraph { + 1->2[label=<bold Te«c»xt>] + } + '''.assertSelectedTextAfterDoubleClicking('''Text''') + } + + @Test def edge_html_label_002() { + ''' + digraph { + 1->2[label=<<«c»b>bold Text>] + } + '''.assertSelectedTextAfterDoubleClicking('''b''') + } + + @Test def edge_html_label_003() { + ''' + digraph { + 1->2[label=<«c»bold Text>] + } + '''.assertSelectedTextAfterDoubleClicking('''<''') + } + + @Test def edge_html_label_004() { + ''' + digraph { + 1->2[label=<serif Text>] + } + '''.assertSelectedTextAfterDoubleClicking('''="''') + } + + @Test def edge_html_label_005() { + ''' + digraph { + 1->2[label=<serif Text>] + } + '''.assertSelectedTextAfterDoubleClicking('''Times''') + } + + @Test def edge_html_label_006() { + ''' + digraph { + 1->2[label=<serif Text>] + } + '''.assertSelectedTextAfterDoubleClicking('''face''') + } + + @Test def edge_html_label_007() { + ''' + digraph { + 1->2[label=<serif Text>] + } + '''.assertSelectedTextAfterDoubleClicking('''face''') + } + + @Test def edge_html_label_008() { + ''' + digraph { + 1->2[label=<serif Text>] + } + '''.assertSelectedTextAfterDoubleClicking('''font''') + } + + + @Test def edge_html_label_009() { + ''' + digraph { + 1->2[label=«c»<serif Text>] + } + '''.assertSelectedTextAfterDoubleClicking('''<serif Text>''') + } + + @Test def edge_html_label_010() { + ''' + digraph{1->2[label=<«c»text>]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_011() { + ''' + digraph{1->2[label=]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_012() { + ''' + digraph{1->2[label=]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_013() { + ''' + digraph{1->2[label=]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_014() { + ''' + digraph{1->2[label=]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_015() { + ''' + digraph{1->2[label=< «c»text >]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_016() { + ''' + digraph{1->2[label=< t«c»ext >]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_017() { + ''' + digraph{1->2[label=< te«c»xt >]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_018() { + ''' + digraph{1->2[label=< tex«c»t >]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_019() { + ''' + digraph{1->2[label=< text«c» >]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_020() { + ''' + digraph{1->2[label=<«c»text>]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_021() { + ''' + digraph{1->2[label=<t«c»ext>]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_022() { + ''' + digraph{1->2[label=<te«c»xt>]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_023() { + ''' + digraph{1->2[label=<tex«c»t>]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_024() { + ''' + digraph{1->2[label=<text«c»>]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_025() { + ''' + digraph{1->2[label=< «c»text >]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_026() { + ''' + digraph{1->2[label=< t«c»ext >]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_027() { + ''' + digraph{1->2[label=< te«c»xt >]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_028() { + ''' + digraph{1->2[label=< tex«c»t >]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + + @Test def edge_html_label_029() { + ''' + digraph{1->2[label=< text«c» >]} + '''.assertSelectedTextAfterDoubleClicking('''text''') + } + @Test def edge_style_001() { ''' graph{ @@ -986,6 +1179,132 @@ class DotEditorDoubleClickingTests extends AbstractEditorDoubleClickTextSelectio '''.assertSelectedTextAfterDoubleClicking('''"2.3"''') } + @Test def node_html_label_001() { + ''' + graph { + 1[label=< + + + + +
Cate«c»gory One
+ >] + } + '''.assertSelectedTextAfterDoubleClicking('''Category''') + } + + @Test def node_html_label_002() { + ''' + graph { + 1[label=< + + + + +
Category«c» One
+ >] + } + '''.assertSelectedTextAfterDoubleClicking('''Category''') + } + + @Test def node_html_label_003() { + ''' + graph { + 1[label=< + + + + +
C«c»ategory One
+ >] + } + '''.assertSelectedTextAfterDoubleClicking('''Category''') + } + + @Test def node_html_label_004() { + ''' + graph { + 1[label=< + + + + +
Category «c»One
+ >] + } + '''.assertSelectedTextAfterDoubleClicking('''One''') + } + + @Test def node_html_label_005() { + ''' + graph { + 1[label=< + + + + +
Category
+ >] + } + '''.assertSelectedTextAfterDoubleClicking('''align''') + } + + @Test def node_html_label_006() { + ''' + graph { + 1[label=< + + + + +
Category
+ >] + } + '''.assertSelectedTextAfterDoubleClicking('''center''') + } + + @Test def node_html_label_007() { + ''' + graph { + 1[label=< + + + <«c»td align="center">Category + +
+ >] + } + '''.assertSelectedTextAfterDoubleClicking('''td''') + } + + @Test def node_html_label_008() { + ''' + graph { + 1[label=< + + + + +
Category
+ >] + } + '''.assertSelectedTextAfterDoubleClicking('''tr''') + } + + @Test def node_html_label_009() { + ''' + graph { + 1[label=< + + + + +
«c»Category Five
+ >] + } + '''.assertSelectedTextAfterDoubleClicking('''Category''') + } + @Test def node_record_label_001() { ''' graph{ diff --git a/org.eclipse.gef.dot.tests/src/org/eclipse/gef/dot/tests/DotHtmlLabelTokenTypeToPartitionMapperTests.xtend b/org.eclipse.gef.dot.tests/src/org/eclipse/gef/dot/tests/DotHtmlLabelTokenTypeToPartitionMapperTests.xtend index 5f234d9cf5..d39c0cb4d3 100644 --- a/org.eclipse.gef.dot.tests/src/org/eclipse/gef/dot/tests/DotHtmlLabelTokenTypeToPartitionMapperTests.xtend +++ b/org.eclipse.gef.dot.tests/src/org/eclipse/gef/dot/tests/DotHtmlLabelTokenTypeToPartitionMapperTests.xtend @@ -7,12 +7,14 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Tamas Miklossy (itemis AG) - initial API and implementation + * Tamas Miklossy (itemis AG) - initial API and implementation + * Zoey Gerrit Prigge (itemis AG) - introduced textPartition (bug #532244) *******************************************************************************/ package org.eclipse.gef.dot.tests import com.google.inject.Inject import org.eclipse.gef.dot.internal.language.DotHtmlLabelUiInjectorProvider +import org.eclipse.gef.dot.internal.ui.language.editor.DotHtmlLabelTerminalsTokenTypeToPartitionMapper import org.eclipse.jface.text.IDocument import org.eclipse.xtext.junit4.InjectWith import org.eclipse.xtext.junit4.XtextRunner @@ -49,7 +51,7 @@ class DotHtmlLabelTokenTypeToPartitionMapperTests { @Test def RULE_WS() { "RULE_WS".hasDefaultPartition } - @Test def RULE_TEXT() { "RULE_TEXT".hasDefaultPartition } + @Test def RULE_TEXT() { "RULE_TEXT".hasTextPartition } private def hasDefaultPartition(String tokenName) { tokenName.hasPartition(IDocument.DEFAULT_CONTENT_TYPE) @@ -62,6 +64,10 @@ class DotHtmlLabelTokenTypeToPartitionMapperTests { private def hasCommentPartition(String tokenName) { tokenName.hasPartition(TerminalsTokenTypeToPartitionMapper.COMMENT_PARTITION) } + + private def hasTextPartition(String tokenName) { + tokenName.hasPartition(DotHtmlLabelTerminalsTokenTypeToPartitionMapper.TEXT_PARTITION) + } private def hasPartition(String tokenName, String expectedPartition) { val actualPartition = tokenName.tokenType.partitionType diff --git a/org.eclipse.gef.dot.tests/src/org/eclipse/gef/dot/tests/DotTokenTypeToPartitionMapperTests.xtend b/org.eclipse.gef.dot.tests/src/org/eclipse/gef/dot/tests/DotTokenTypeToPartitionMapperTests.xtend index fa7aeea6c5..64314a86c8 100644 --- a/org.eclipse.gef.dot.tests/src/org/eclipse/gef/dot/tests/DotTokenTypeToPartitionMapperTests.xtend +++ b/org.eclipse.gef.dot.tests/src/org/eclipse/gef/dot/tests/DotTokenTypeToPartitionMapperTests.xtend @@ -7,12 +7,14 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Tamas Miklossy (itemis AG) - initial API and implementation + * Tamas Miklossy (itemis AG) - initial API and implementation + * Zoey Gerrit Prigge (itemis AG) - introduced htmlStringPartition (bug #532244) *******************************************************************************/ package org.eclipse.gef.dot.tests import com.google.inject.Inject import org.eclipse.gef.dot.internal.language.DotUiInjectorProvider +import org.eclipse.gef.dot.internal.ui.language.editor.DotTerminalsTokenTypeToPartitionMapper import org.eclipse.jface.text.IDocument import org.eclipse.xtext.junit4.InjectWith import org.eclipse.xtext.junit4.XtextRunner @@ -77,7 +79,7 @@ class DotTokenTypeToPartitionMapperTests { @Test def RULE_HTML_CHARS() { "RULE_HTML_CHARS".hasDefaultPartition } - @Test def RULE_HTML_STRING() { "RULE_HTML_STRING".hasDefaultPartition } + @Test def RULE_HTML_STRING() { "RULE_HTML_STRING".hasHtmlStringPartition } @Test def RULE_ML_COMMENT() { "RULE_ML_COMMENT".hasCommentPartition } @@ -102,6 +104,10 @@ class DotTokenTypeToPartitionMapperTests { private def hasCommentPartition(String tokenName) { tokenName.hasPartition(TerminalsTokenTypeToPartitionMapper.COMMENT_PARTITION) } + + private def hasHtmlStringPartition(String tokenName) { + tokenName.hasPartition(DotTerminalsTokenTypeToPartitionMapper.HTML_STRING_PARTITION) + } private def hasPartition(String tokenName, String expectedPartition) { val actualPartition = tokenName.tokenType.partitionType diff --git a/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/DotHtmlLabelUiModule.java b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/DotHtmlLabelUiModule.java index 3469829a4d..d647a4b61e 100644 --- a/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/DotHtmlLabelUiModule.java +++ b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/DotHtmlLabelUiModule.java @@ -7,16 +7,19 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Matthias Wienand (itemis AG) - initial API and implementation - * Tamas Miklossy (itemis AG) - improve html-label highlighting/folding + * Matthias Wienand (itemis AG) - initial API and implementation + * Tamas Miklossy (itemis AG) - improve html-label highlighting/folding + * Zoey Gerrit Prigge (itemis AG) - bind double click strategy provider (bug #532244) * *******************************************************************************/ package org.eclipse.gef.dot.internal.ui.language; +import org.eclipse.gef.dot.internal.ui.language.doubleclicking.DotHtmlLabelDoubleClickStrategyProvider; import org.eclipse.gef.dot.internal.ui.language.editor.DotHtmlLabelTerminalsTokenTypeToPartitionMapper; import org.eclipse.gef.dot.internal.ui.language.folding.DotHtmlLabelFoldingRegionProvider; import org.eclipse.gef.dot.internal.ui.language.highlighting.DotHtmlLabelSemanticHighlightingCalculator; import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.eclipse.xtext.ui.editor.doubleClicking.DoubleClickStrategyProvider; import org.eclipse.xtext.ui.editor.folding.IFoldingRegionProvider; import org.eclipse.xtext.ui.editor.model.ITokenTypeToPartitionTypeMapper; import org.eclipse.xtext.ui.editor.syntaxcoloring.ISemanticHighlightingCalculator; @@ -41,4 +44,9 @@ public Class bindIFoldingRegionProvider() { public Class bindITokenTypeToPartitionTypeMapper() { return DotHtmlLabelTerminalsTokenTypeToPartitionMapper.class; } + + public Class bindDoubleClickStrategyProvider() { + return DotHtmlLabelDoubleClickStrategyProvider.class; + } + } diff --git a/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/DotUiModule.java b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/DotUiModule.java index 5b6f8a345a..b2addd8981 100644 --- a/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/DotUiModule.java +++ b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/DotUiModule.java @@ -7,20 +7,22 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Alexander Nyßen (itemis AG) - initial API and implementation - * Tamas Miklossy (itemis AG) - add binding for template proposal provider (bug #321775) - * - add binding for folding region provider (bug #321775) - * - add binding for EObject hover/hover provider (bug #461506) - * - add binding for hyperlink helper (bug #461506) - * - add binding for rename strategy (bug #530423) - * - add binding for occurrence computer (bug #530699) - * - add binding for reference finder/reference query executor (bug #531049) - * - add binding for the Xtext Editor - * - add binding for token type to partition mapper (bug #532244) + * Alexander Nyßen (itemis AG) - initial API and implementation + * Tamas Miklossy (itemis AG) - add binding for template proposal provider (bug #321775) + * - add binding for folding region provider (bug #321775) + * - add binding for EObject hover/hover provider (bug #461506) + * - add binding for hyperlink helper (bug #461506) + * - add binding for rename strategy (bug #530423) + * - add binding for occurrence computer (bug #530699) + * - add binding for reference finder/reference query executor (bug #531049) + * - add binding for the Xtext Editor + * - add binding for token type to partition mapper (bug #532244) + * Zoey Gerrit Prigge (itemis AG) - add binding for doubleClickStrategyProvider (bug #532244) *******************************************************************************/ package org.eclipse.gef.dot.internal.ui.language; import org.eclipse.gef.dot.internal.ui.language.contentassist.DynamicTemplateProposalProvider; +import org.eclipse.gef.dot.internal.ui.language.doubleclicking.DotDoubleClickStrategyProvider; import org.eclipse.gef.dot.internal.ui.language.editor.DotEditor; import org.eclipse.gef.dot.internal.ui.language.editor.DotTerminalsTokenTypeToPartitionMapper; import org.eclipse.gef.dot.internal.ui.language.findreferences.DotFindReferencesQueryExecutor; @@ -37,6 +39,7 @@ import org.eclipse.ui.plugin.AbstractUIPlugin; import org.eclipse.xtext.ui.editor.XtextEditor; import org.eclipse.xtext.ui.editor.contentassist.ITemplateProposalProvider; +import org.eclipse.xtext.ui.editor.doubleClicking.DoubleClickStrategyProvider; import org.eclipse.xtext.ui.editor.findrefs.IReferenceFinder; import org.eclipse.xtext.ui.editor.findrefs.ReferenceQueryExecutor; import org.eclipse.xtext.ui.editor.folding.IFoldingRegionProvider; @@ -117,4 +120,8 @@ public Class bindXtextEditor() { public Class bindITokenTypeToPartitionTypeMapper() { return DotTerminalsTokenTypeToPartitionMapper.class; } + + public Class bindDoubleClickStrategyProvider() { + return DotDoubleClickStrategyProvider.class; + } } diff --git a/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/doubleclicking/DotDoubleClickStrategyProvider.java b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/doubleclicking/DotDoubleClickStrategyProvider.java new file mode 100644 index 0000000000..7a9ac4c5e0 --- /dev/null +++ b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/doubleclicking/DotDoubleClickStrategyProvider.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2018 itemis AG 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: + * Zoey Gerrit Prigge (itemis AG) - initial API and implementation (bug #532244) + *******************************************************************************/ +package org.eclipse.gef.dot.internal.ui.language.doubleclicking; + +import org.eclipse.gef.dot.internal.ui.language.editor.DotTerminalsTokenTypeToPartitionMapper; +import org.eclipse.jface.text.ITextDoubleClickStrategy; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.xtext.ui.editor.doubleClicking.DoubleClickStrategyProvider; + +public class DotDoubleClickStrategyProvider + extends DoubleClickStrategyProvider { + + @Override + public ITextDoubleClickStrategy getStrategy(ISourceViewer sourceViewer, + String contentType, String documentPartitioning) { + if (DotTerminalsTokenTypeToPartitionMapper.HTML_STRING_PARTITION + .equals(contentType)) { + return new DotHtmlLabelDoubleClickStrategy(); + } + return super.getStrategy(sourceViewer, contentType, + documentPartitioning); + } + +} diff --git a/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/doubleclicking/DotHtmlLabelDoubleClickStrategy.java b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/doubleclicking/DotHtmlLabelDoubleClickStrategy.java new file mode 100644 index 0000000000..483858e2d1 --- /dev/null +++ b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/doubleclicking/DotHtmlLabelDoubleClickStrategy.java @@ -0,0 +1,186 @@ +/******************************************************************************* + * Copyright (c) 2018 itemis AG 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: + * Zoey Gerrit Prigge (itemis AG) - initial API and implementation (bug #532244) + *******************************************************************************/ +package org.eclipse.gef.dot.internal.ui.language.doubleclicking; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.eclipse.gef.dot.internal.ui.language.editor.DotEditorUtils; +import org.eclipse.gef.dot.internal.ui.language.internal.DotActivator; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.DefaultTextDoubleClickStrategy; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextDoubleClickStrategy; +import org.eclipse.jface.text.ITypedRegion; +import org.eclipse.jface.text.Region; +import org.eclipse.xtext.ui.editor.doubleClicking.DoubleClickStrategyProvider; +import org.eclipse.xtext.ui.editor.model.IXtextDocument; +import org.eclipse.xtext.ui.editor.model.XtextDocument; + +import com.google.inject.Injector; + +public class DotHtmlLabelDoubleClickStrategy + extends DefaultTextDoubleClickStrategy { + + @Override + protected IRegion findWord(IDocument document, int offset) { + ITypedRegion region = null; + try { + region = document.getPartition(offset); + } catch (BadLocationException e) { + e.printStackTrace(); + return null; + } + + // Translate the partition offset for the HtmlLabel by one to point to + // the position after the angle bracket indicating an HtmlLabelStart in + // the host grammar. + int htmlLabelStartOffset = region.getOffset() + 1; + // Translate the partition length by two points to discount for both + // HtmlLabel indicating angle brackets (start and end) only present in + // the dot host grammar. + int htmlLabelLength = region.getLength() - 2; + + String htmlLabel = null; + try { + htmlLabel = document.get(htmlLabelStartOffset, htmlLabelLength); + } catch (BadLocationException e) { + e.printStackTrace(); + return null; + } + + Injector injector = DotActivator.getInstance().getInjector( + DotActivator.ORG_ECLIPSE_GEF_DOT_INTERNAL_LANGUAGE_DOTHTMLLABEL); + + IXtextDocument htmlDocument = null; + try { + htmlDocument = DotEditorUtils.getDocument(injector, htmlLabel); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + // translate the offset of the double-click position relative to + // the htmlDocument + int htmlLabelClickOffset = offset - htmlLabelStartOffset; + + ITextDoubleClickStrategy doubleClickStrategy = null; + try { + doubleClickStrategy = injector + .getInstance(DoubleClickStrategyProvider.class) + .getStrategy(null, + htmlDocument.getContentType(htmlLabelClickOffset), + XtextDocument.DEFAULT_PARTITIONING); + } catch (BadLocationException e) { + e.printStackTrace(); + return null; + } + + IRegion htmlRegion = findRegionHtml(htmlDocument, htmlLabelClickOffset, + doubleClickStrategy); + + return new Region(htmlLabelStartOffset + htmlRegion.getOffset(), + htmlRegion.getLength()); + } + + private IRegion findRegionHtml(IXtextDocument htmlDocument, + int htmlLabelClickOffset, + ITextDoubleClickStrategy doubleClickStrategy) { + IRegion htmlRegion = findExtendedSelectionHtml(doubleClickStrategy, + htmlDocument, htmlLabelClickOffset); + + if (htmlRegion != null) + return htmlRegion; + + return findWordHtml(doubleClickStrategy, htmlDocument, + htmlLabelClickOffset); + } + + private IRegion findExtendedSelectionHtml( + ITextDoubleClickStrategy doubleClickStrategy, + IXtextDocument htmlDocument, int htmlLabelClickOffset) { + Method findExtendedSelection = findExtendedDoubleClickSelectionMethod( + doubleClickStrategy.getClass()); + return invokeMethodOn(findExtendedSelection, doubleClickStrategy, + htmlDocument, htmlLabelClickOffset); + } + + private IRegion findWordHtml(ITextDoubleClickStrategy doubleClickStrategy, + IXtextDocument htmlDocument, int htmlLabelClickOffset) { + Method findWord = findWordMethod(doubleClickStrategy.getClass()); + return invokeMethodOn(findWord, doubleClickStrategy, htmlDocument, + htmlLabelClickOffset); + } + + /** + * Returns a Method Object encapsulating the protected findWord Method + * inherited from DefaultTextDoubleClickStrategy. + * + * The method object is set to be accessible. + * + * @param strategyClass + * may not be null + * @return + */ + private Method findWordMethod(Class strategyClass) { + return methodByName("findWord", strategyClass); //$NON-NLS-1$ + } + + /** + * Returns a Method Object encapsulating the protected + * findExtendedDoubleClickSelection Method inherited from + * DefaultTextDoubleClickStrategy. + * + * The method object is set to be accessible. + * + * @param strategyClass + * may not be null + * @return + */ + private Method findExtendedDoubleClickSelectionMethod( + Class strategyClass) { + return methodByName("findExtendedDoubleClickSelection", //$NON-NLS-1$ + strategyClass); + } + + private Method methodByName(String name, Class strategyClass) { + Method method; + try { + method = strategyClass.getDeclaredMethod(name, IDocument.class, + int.class); + } catch (NoSuchMethodException | SecurityException e) { + Class superClass = strategyClass.getSuperclass(); + if (superClass != null) + return methodByName(name, strategyClass.getSuperclass()); + return null; + } + method.setAccessible(true); + return method; + } + + private IRegion invokeMethodOn(Method method, + ITextDoubleClickStrategy doubleClickStrategy, + IXtextDocument htmlDocument, int htmlLabelClickOffset) { + IRegion htmlRegion = null; + try { + htmlRegion = (IRegion) method.invoke(doubleClickStrategy, + htmlDocument, htmlLabelClickOffset); + } catch (IllegalAccessException | IllegalArgumentException + | InvocationTargetException | ClassCastException e) { + e.printStackTrace(); + return null; + } + return htmlRegion; + } + +} diff --git a/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/doubleclicking/DotHtmlLabelDoubleClickStrategyProvider.java b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/doubleclicking/DotHtmlLabelDoubleClickStrategyProvider.java new file mode 100644 index 0000000000..40066c6ed0 --- /dev/null +++ b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/doubleclicking/DotHtmlLabelDoubleClickStrategyProvider.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2018 itemis AG 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: + * Zoey Gerrit Prigge (itemis AG) - initial API and implementation (bug #532244) + *******************************************************************************/ +package org.eclipse.gef.dot.internal.ui.language.doubleclicking; + +import org.eclipse.gef.dot.internal.ui.language.editor.DotHtmlLabelTerminalsTokenTypeToPartitionMapper; +import org.eclipse.jface.text.ITextDoubleClickStrategy; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.xtext.ui.editor.doubleClicking.AbstractWordAwareDoubleClickStrategy; +import org.eclipse.xtext.ui.editor.doubleClicking.DoubleClickStrategyProvider; + +public class DotHtmlLabelDoubleClickStrategyProvider + extends DoubleClickStrategyProvider { + + @Override + public ITextDoubleClickStrategy getStrategy(ISourceViewer sourceViewer, + String contentType, String documentPartitioning) { + if (DotHtmlLabelTerminalsTokenTypeToPartitionMapper.TEXT_PARTITION + .equals(contentType)) { + return new AbstractWordAwareDoubleClickStrategy(); + } + return super.getStrategy(sourceViewer, contentType, + documentPartitioning); + } + +} diff --git a/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/editor/DotHtmlLabelTerminalsTokenTypeToPartitionMapper.java b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/editor/DotHtmlLabelTerminalsTokenTypeToPartitionMapper.java index e4ba09b79d..194d39ac6d 100644 --- a/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/editor/DotHtmlLabelTerminalsTokenTypeToPartitionMapper.java +++ b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/editor/DotHtmlLabelTerminalsTokenTypeToPartitionMapper.java @@ -7,15 +7,22 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Tamas Miklossy (itemis AG) - initial API and implementation + * Tamas Miklossy (itemis AG) - initial API and implementation + * Zoey Gerrit Prigge (itemis AG) - add TEXT_PARTITION type (bug #532244) *******************************************************************************/ package org.eclipse.gef.dot.internal.ui.language.editor; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import org.eclipse.xtext.ui.editor.model.TerminalsTokenTypeToPartitionMapper; public class DotHtmlLabelTerminalsTokenTypeToPartitionMapper extends TerminalsTokenTypeToPartitionMapper { + public static final String TEXT_PARTITION = "__html_text"; //$NON-NLS-1$ + @Override protected String calculateId(String tokenName, int tokenType) { switch (tokenName) { @@ -31,8 +38,23 @@ protected String calculateId(String tokenName, int tokenType) { * otherwise, the double click text selection does not work properly */ return STRING_LITERAL_PARTITION; + case "RULE_TEXT": //$NON-NLS-1$ + /** + * assign the TEXT_PARTITION to the TEXT rule, to assign double + * click strategy manually as double click text selection does not + * work properly otherwise. + */ + return TEXT_PARTITION; default: return super.calculateId(tokenName, tokenType); } } + + @Override + public String[] getSupportedPartitionTypes() { + List supportedTypes = new ArrayList<>( + Arrays.asList(super.getSupportedPartitionTypes())); + supportedTypes.add(TEXT_PARTITION); + return supportedTypes.toArray(new String[supportedTypes.size()]); + } } diff --git a/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/editor/DotTerminalsTokenTypeToPartitionMapper.java b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/editor/DotTerminalsTokenTypeToPartitionMapper.java index 31e7004f32..978a8a8b58 100644 --- a/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/editor/DotTerminalsTokenTypeToPartitionMapper.java +++ b/org.eclipse.gef.dot.ui/src/org/eclipse/gef/dot/internal/ui/language/editor/DotTerminalsTokenTypeToPartitionMapper.java @@ -7,16 +7,23 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Tamas Miklossy (itemis AG) - initial API and implementation (bug #532244) + * Tamas Miklossy (itemis AG) - initial API and implementation (bug #532244) + * Zoey Gerrit Prigge (itemis AG) - added HTML_STRING_PARTITION type (bug #532244) *******************************************************************************/ package org.eclipse.gef.dot.internal.ui.language.editor; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import org.eclipse.jface.text.IDocument; import org.eclipse.xtext.ui.editor.model.TerminalsTokenTypeToPartitionMapper; public class DotTerminalsTokenTypeToPartitionMapper extends TerminalsTokenTypeToPartitionMapper { + public static final String HTML_STRING_PARTITION = "__html_string"; //$NON-NLS-1$ + @Override protected String calculateId(String tokenName, int tokenType) { /** @@ -41,8 +48,23 @@ protected String calculateId(String tokenName, int tokenType) { return IDocument.DEFAULT_CONTENT_TYPE; case "RULE_QUOTED_STRING": //$NON-NLS-1$ return STRING_LITERAL_PARTITION; + /** + * Html strings ('RULE_HTML_STRING') in dot use a specific syntax, hence + * for double clicking support, we need to implement a custom double + * click strategy using the HTML_STRING_PARTITION. + */ + case "RULE_HTML_STRING": //$NON-NLS-1$ + return HTML_STRING_PARTITION; default: return super.calculateId(tokenName, tokenType); } } + + @Override + public String[] getSupportedPartitionTypes() { + List supportedTypes = new ArrayList<>( + Arrays.asList(super.getSupportedPartitionTypes())); + supportedTypes.add(HTML_STRING_PARTITION); + return supportedTypes.toArray(new String[supportedTypes.size()]); + } }