diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml new file mode 100644 index 00000000000..c6c3f3df57b --- /dev/null +++ b/.github/workflows/copilot-setup-steps.yml @@ -0,0 +1,32 @@ +name: "Copilot Setup Steps" + +# Automatically run the setup steps when they are changed to allow for easy validation, and +# allow manual testing through the repository's "Actions" tab +on: + workflow_dispatch: + pull_request: + paths: + - .github/workflows/copilot-setup-steps.yml + +jobs: + # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot. + copilot-setup-steps: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + java-version: '21' + distribution: 'temurin' + cache: 'maven' + + - name: Set up Maven 3.9.11 + uses: stCarolas/setup-maven@v5 + with: + maven-version: '3.9.11' + diff --git a/AGENTS.md b/AGENTS.md index 4cc513fb396..2fcd3d9e28b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,8 +7,8 @@ This file provides guidance to AI Agents (claude-code, codex, gemini cli, ...) w Eclipse Platform UI provides the UI building blocks for Eclipse IDE and Eclipse Rich Client Platform (RCP). This includes JFace, workbench, commands framework, data binding, dialogs, editors, views, perspectives, and more. Built on top of SWT (Eclipse Standard Widget Toolkit). **Key Facts:** -- **Language:** Java 17 -- **Build System:** Maven 3.9.x with Tycho (OSGi/Eclipse plugin build) +- **Language:** Java 21 +- **Build System:** Maven 3.9.11 with Tycho (OSGi/Eclipse plugin build) - **Architecture:** OSGi bundles, E4 application model ## Project Structure @@ -64,10 +64,6 @@ Each bundle contains: ### Critical Limitation -**⚠️ IMPORTANT:** Standalone `mvn clean verify` at repository root **WILL FAIL** with "Non-resolvable parent POM" error. This repository requires a parent POM from `eclipse.platform.releng.aggregator`. - -### Building Individual Bundles - Use the `-Pbuild-individual-bundles` profile: ```bash diff --git a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDocumentHandlerImpl.java b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDocumentHandlerImpl.java index 9a7dfe40eb1..150c95c4b7a 100644 --- a/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDocumentHandlerImpl.java +++ b/bundles/org.eclipse.e4.ui.css.core/src/org/eclipse/e4/ui/css/core/impl/sac/CSSDocumentHandlerImpl.java @@ -91,7 +91,6 @@ public void ignorableAtRule(String atRule) throws CSSException { if (!getNodeStack().empty()) { ((CSSRuleListImpl) getNodeStack().peek()).add(ir); } else { - // _getNodeStack().push(ir); nodeRoot = ir; } } @@ -100,10 +99,6 @@ public void ignorableAtRule(String atRule) throws CSSException { public void namespaceDeclaration(String prefix, String uri) throws CSSException { //TODO replace with eclipse logging - // if (logger.isDebugEnabled()) { - // logger.debug("Declare namespace [prefix=" + prefix + ", uri=" + uri - // + "]"); - // } } @Override @@ -116,7 +111,6 @@ public void importStyle(String uri, SACMediaList media, if (!getNodeStack().empty()) { ((CSSRuleListImpl) getNodeStack().peek()).add(ir); } else { - // _getNodeStack().push(ir); nodeRoot = ir; } } @@ -125,27 +119,12 @@ public void importStyle(String uri, SACMediaList media, public void startMedia(SACMediaList media) throws CSSException { ignore = true; - // // Create the media rule and add it to the rule list - // CSSMediaRuleImpl mr = new CSSMediaRuleImpl(parentStyleSheet, null, - // new MediaListImpl(media)); - // if (!getNodeStack().empty()) { - // ((CSSRuleListImpl) getNodeStack().peek()).add(mr); - // } - // - // // Create the rule list - // CSSRuleListImpl rules = new CSSRuleListImpl(); - // mr.setRuleList(rules); - // getNodeStack().push(mr); - // getNodeStack().push(rules); } @Override public void endMedia(SACMediaList media) throws CSSException { ignore = false; - // // Pop the rule list and media rule nodes - // getNodeStack().pop(); - // nodeRoot = getNodeStack().pop(); } @Override @@ -176,26 +155,11 @@ public void endPage(String name, String pseudo_page) throws CSSException { @Override public void startFontFace() throws CSSException { ignore = true; - // // Create the font face rule and add it to the rule list - // CSSFontFaceRuleImpl fontFaceRule = new CSSFontFaceRuleImpl( - // parentStyleSheet, null); - // if (!getNodeStack().empty()) { - // ((CSSRuleListImpl) getNodeStack().peek()).add(fontFaceRule); - // } - // - // // Create the style declaration - // CSSStyleDeclarationImpl decl = new CSSStyleDeclarationImpl(fontFaceRule); - // fontFaceRule.setStyle(decl); - // getNodeStack().push(fontFaceRule); - // getNodeStack().push(decl); } @Override public void endFontFace() throws CSSException { ignore = false; - // // Pop both the style declaration and the font face rule nodes - // getNodeStack().pop(); - // nodeRoot = getNodeStack().pop(); } @Override diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/MenuManagerShowProcessor.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/MenuManagerShowProcessor.java index 3c13ec562e9..138e5d8d4b4 100644 --- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/MenuManagerShowProcessor.java +++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/MenuManagerShowProcessor.java @@ -123,8 +123,8 @@ public void menuAboutToHide(IMenuManager manager) { * {@link MDynamicMenuContribution} application model elements */ private void processDynamicElements(MMenu menuModel, MenuManager menuManager) { - MMenuElement[] menuElements = menuModel.getChildren().toArray( - new MMenuElement[menuModel.getChildren().size()]); + List children = menuModel.getChildren(); + MMenuElement[] menuElements = children.toArray(new MMenuElement[children.size()]); for (MMenuElement currentMenuElement : menuElements) { if (currentMenuElement instanceof MDynamicMenuContribution dmc) { @@ -154,9 +154,9 @@ private void processDynamicElements(MMenu menuModel, MenuManager menuManager) { if (mel.size() > 0) { int position = 0; - while (position < menuModel.getChildren().size()) { - if (currentMenuElement == menuModel.getChildren().get( - position)) { + children = menuModel.getChildren(); + while (position < children.size()) { + if (currentMenuElement == children.get(position)) { position++; break; } diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRenderer.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRenderer.java index 41eb5e5c1dd..bc20b90c816 100644 --- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRenderer.java +++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRenderer.java @@ -313,7 +313,7 @@ private void initializeOnboardingInformationInEditorStack(CTabFolder editorStack String[] commandAndText = commands[i].split("\\$\\$\\$"); //$NON-NLS-1$ - WidgetFactory.label(SWT.NONE).text(commandAndText[0]).foreground(color) + WidgetFactory.label(SWT.NONE).text(commandAndText[0]).foreground(color).align(SWT.RIGHT) .supplyLayoutData(labelGridDataFactory::create).create(onboardingComposite); WidgetFactory.label(SWT.NONE).text(commandAndText[1]).foreground(color) .supplyLayoutData(commandGridDataFactory::create).create(onboardingComposite); diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/SelectionProcessor.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/SelectionProcessor.java index 835adc4498c..fcc1b46b430 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/SelectionProcessor.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/SelectionProcessor.java @@ -294,33 +294,6 @@ TextEdit replace(IMultiTextSelection selection, String replacement) { TextEdit replace= new ReplaceEdit(region.getOffset(), region.getLength(), string); root.addChild(replace); } - // while (lastDelim != -1) { - // // more stuff to insert - // String string; - // Match m= delimiterMatcher.indexOf(replacement, lastDelim); - // if (m == null) { - // string= replacement.substring(lastDelim); - // lastDelim= -1; - // } else { - // string= replacement.substring(lastDelim, m.getOffset()); - // lastDelim= m.getOffset() + m.getText().length(); - // } - // endLine++; - // TextEdit edit; - // if (endLine < fDocument.getNumberOfLines()) { - // edit= createReplaceEdit(endLine, visualStartColumn, visualEndColumn, string, delete); - // } else { - // // insertion reaches beyond the last line - // int insertLocation= root.getExclusiveEnd(); - // int spaces= visualStartColumn; - // char[] array= new char[spaces]; - // Arrays.fill(array, ' '); - // string= TextUtilities.getDefaultLineDelimiter(fDocument) + String.valueOf(array) + string; - // edit= new InsertEdit(insertLocation, string); - // insertLocation+= string.length(); - // } - // root.addChild(edit); - // } return root; } } diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/html/HTMLPrinter.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/html/HTMLPrinter.java index ecaf40de521..be088b03e6b 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/html/HTMLPrinter.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/html/HTMLPrinter.java @@ -129,7 +129,7 @@ public static String read(Reader rd) { * @param bgRGB Background-Color * @param styleSheet Stylesheet */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void insertPageProlog(StringBuffer buffer, int position, RGB fgRGB, RGB bgRGB, String styleSheet) { runOp(buffer, (sb) -> CORE.insertPageProlog(sb, position, fromRGB(fgRGB), fromRGB(bgRGB), styleSheet)); } @@ -164,7 +164,7 @@ public static void insertStyles(StringBuilder buffer, String[] styles) { * * @deprecated As of 3.13, replaced by {@link #insertStyles(StringBuilder, String[])} */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void insertStyles(StringBuffer buffer, String[] styles) { runOp(buffer, (sb) -> CORE.insertStyles(sb, styles)); } @@ -186,7 +186,7 @@ public static void insertPageProlog(StringBuilder buffer, int position) { * * @deprecated migrate to new StringBuilder API */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void insertPageProlog(StringBuffer buffer, int position) { runOp(buffer, (sb) -> CORE.insertPageProlog(sb, position)); } @@ -199,7 +199,7 @@ public static void insertPageProlog(StringBuffer buffer, int position) { * * @deprecated migrate to new StringBuilder API */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void insertPageProlog(StringBuffer buffer, int position, URL styleSheetURL) { runOp(buffer, (sb) -> CORE.insertPageProlog(sb, position, styleSheetURL)); } @@ -234,7 +234,7 @@ public static void insertPageProlog(StringBuilder buffer, int position, String s * * @deprecated migrate to new StringBuilder API */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void insertPageProlog(StringBuffer buffer, int position, String styleSheet) { runOp(buffer, (sb) -> CORE.insertPageProlog(sb, position, styleSheet)); } @@ -254,7 +254,7 @@ public static void addPageProlog(StringBuilder buffer) { * * @deprecated migrate to new StringBuilder API */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void addPageProlog(StringBuffer buffer) { runOp(buffer, CORE::addPageProlog); } @@ -269,7 +269,7 @@ public static void addPageEpilog(StringBuilder buffer) { * * @deprecated migrate to new StringBuilder API */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void addPageEpilog(StringBuffer buffer) { runOp(buffer, CORE::addPageEpilog); } @@ -289,7 +289,7 @@ public static void startBulletList(StringBuilder buffer) { * * @deprecated migrate to new StringBuilder API */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void startBulletList(StringBuffer buffer) { runOp(buffer, CORE::startBulletList); } @@ -311,7 +311,7 @@ public static void endBulletList(StringBuilder buffer) { * * @deprecated migrate to new StringBuilder API */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void endBulletList(StringBuffer buffer) { runOp(buffer, CORE::endBulletList); } @@ -335,7 +335,7 @@ public static void addBullet(StringBuilder buffer, String bullet) { * * @deprecated migrate to new StringBuilder API */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void addBullet(StringBuffer buffer, String bullet) { runOp(buffer, (sb) -> CORE.addBullet(sb, bullet)); } @@ -361,7 +361,7 @@ public static void addSmallHeader(StringBuilder buffer, String header) { * * @deprecated migrate to new StringBuilder API */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void addSmallHeader(StringBuffer buffer, String header) { runOp(buffer, (sb) -> CORE.addSmallHeader(sb, header)); } @@ -383,7 +383,7 @@ public static void addParagraph(StringBuilder buffer, String paragraph) { * * @deprecated migrate to new StringBuilder API */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void addParagraph(StringBuffer buffer, String paragraph) { runOp(buffer, (sb) -> CORE.addParagraph(sb, paragraph)); } @@ -391,9 +391,9 @@ public static void addParagraph(StringBuffer buffer, String paragraph) { /** * Appends a string and keeps its whitespace and newlines. *

- * Warning: This starts a new paragraph when rendered in a browser, but - * it doesn't starts a new paragraph when rendered with a {@link HTML2TextReader} - * (e.g. in a {@link DefaultInformationControl} that renders simple HTML). + * Warning: This starts a new paragraph when rendered in a browser, but it doesn't starts + * a new paragraph when rendered with a {@link HTML2TextReader} (e.g. in a + * {@link DefaultInformationControl} that renders simple HTML). * * @param buffer the output StringBuilder * @param preFormatted the string that should be rendered with whitespace preserved @@ -409,9 +409,9 @@ public static void addPreFormatted(StringBuilder buffer, String preFormatted) { /** * Appends a string and keeps its whitespace and newlines. *

- * Warning: This starts a new paragraph when rendered in a browser, but - * it doesn't starts a new paragraph when rendered with a {@link HTML2TextReader} - * (e.g. in a {@link DefaultInformationControl} that renders simple HTML). + * Warning: This starts a new paragraph when rendered in a browser, but it doesn't starts + * a new paragraph when rendered with a {@link HTML2TextReader} (e.g. in a + * {@link DefaultInformationControl} that renders simple HTML). * * @param buffer the output buffer * @param preFormatted the string that should be rendered with whitespace preserved @@ -422,7 +422,7 @@ public static void addPreFormatted(StringBuilder buffer, String preFormatted) { * @see #convertToHTMLContentWithWhitespace(String) * @since 3.7 */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void addPreFormatted(StringBuffer buffer, String preFormatted) { runOp(buffer, (sb) -> CORE.addPreFormatted(sb, preFormatted)); } @@ -444,7 +444,7 @@ public static void addParagraph(StringBuilder buffer, Reader paragraphReader) { * * @deprecated migrate to new StringBuilder API */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public static void addParagraph(StringBuffer buffer, Reader paragraphReader) { runOp(buffer, (sb) -> CORE.addParagraph(sb, paragraphReader)); } diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/revisions/RevisionPainter.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/revisions/RevisionPainter.java index a2f63a9e74a..0fe67b12efa 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/revisions/RevisionPainter.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/revisions/RevisionPainter.java @@ -382,7 +382,7 @@ protected IInformationControl doCreateInformationControl(Shell parent) { * * @deprecated use {@link #setInput(Object)} */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") @Override public void setInformation(String content) { content= addCSSToHTMLFragment(content); @@ -390,8 +390,8 @@ public void setInformation(String content) { } /** - * Adds a HTML header and CSS info if html is only an HTML fragment (has no - * <html> section). + * Adds a HTML header and CSS info if html is only an HTML fragment + * (has no <html> section). * * @param html the html / text produced by a revision * @return modified html diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/DefaultInformationControl.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/DefaultInformationControl.java index 84e8853c5a9..1429165e9cb 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/DefaultInformationControl.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/DefaultInformationControl.java @@ -232,7 +232,7 @@ public DefaultInformationControl(Shell parent, IInformationPresenter presenter) * @param presenter the presenter to be used * @deprecated As of 3.4, replaced by simpler constructors */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public DefaultInformationControl(Shell parent, int shellStyle, int style, IInformationPresenter presenter) { this(parent, shellStyle, style, presenter, null); } @@ -269,7 +269,7 @@ public DefaultInformationControl(Shell parentShell, int shellStyle, final int st * @param presenter the presenter to be used * @deprecated As of 3.4, replaced by {@link #DefaultInformationControl(Shell, DefaultInformationControl.IInformationPresenter)} */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public DefaultInformationControl(Shell parent, int textStyles, IInformationPresenter presenter) { this(parent, textStyles, presenter, null); } diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/TextViewer.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/TextViewer.java index ca86c49b3ab..a41a9a069f3 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/TextViewer.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/TextViewer.java @@ -2008,7 +2008,7 @@ protected int getEmptySelectionChangedEventDelay() { * {@link ITextViewerExtension2#prependAutoEditStrategy(IAutoEditStrategy, String)} and * {@link ITextViewerExtension2#removeAutoEditStrategy(IAutoEditStrategy, String)} instead */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") @Override public void setAutoIndentStrategy(IAutoIndentStrategy strategy, String contentType) { setAutoEditStrategies(new IAutoEditStrategy[] { strategy }, contentType); @@ -3212,7 +3212,7 @@ public void setTopIndex(int index) { * @return the view port height in lines * @deprecated as of 3.2 */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") protected int getVisibleLinesInViewport() { if (fTextWidget != null) { Rectangle clArea= fTextWidget.getClientArea(); @@ -3429,7 +3429,7 @@ protected void internalRevealRange(int start, int end) { * @return the width of the presentation of the given string * @deprecated use getWidthInPixels(int, int) instead */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") final protected int getWidthInPixels(String text) { GC gc= new GC(fTextWidget); gc.setFont(fTextWidget.getFont()); @@ -4308,7 +4308,7 @@ protected void copyMarkedRegion(boolean delete) { * * @deprecated use StyledText.invokeAction instead */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") protected void deleteText() { fTextWidget.invokeAction(ST.DELETE_NEXT); } @@ -4429,7 +4429,7 @@ private IRegion getTextBlockFromSelection(ITextSelection selection) throws BadLo * * @deprecated use shift(boolean, boolean, boolean) instead */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") protected void shift(boolean useDefaultPrefixes, boolean right) { shift(useDefaultPrefixes, right, false); } @@ -4712,7 +4712,7 @@ protected boolean canPerformFind() { * @return the model offset of the first match * @deprecated as of 3.0 use {@link #findAndSelect(int, String, boolean, boolean, boolean, boolean)} */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") protected int findAndSelect(int startPosition, String findString, boolean forwardSearch, boolean caseSensitive, boolean wholeWord) { try { return findAndSelect(startPosition, findString, forwardSearch, caseSensitive, wholeWord, false); diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/IContentAssistProcessorExtension.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/IContentAssistProcessorExtension.java index 2be67dc2e65..b5153c15b62 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/IContentAssistProcessorExtension.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/IContentAssistProcessorExtension.java @@ -98,13 +98,13 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int return processor.computeCompletionProposals(viewer, offset); } - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") @Override public char[] getCompletionProposalAutoActivationCharacters() { return processor.getCompletionProposalAutoActivationCharacters(); } - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") @Override public char[] getContextInformationAutoActivationCharacters() { return processor.getContextInformationAutoActivationCharacters(); diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/formatter/ContentFormatter.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/formatter/ContentFormatter.java index 83c0a963a2b..3d9512c2201 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/formatter/ContentFormatter.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/formatter/ContentFormatter.java @@ -323,7 +323,7 @@ public void setFormattingStrategy(IFormattingStrategy strategy, String contentTy * @deprecated incompatible with an open set of document partitionings. The provided information is only used * if this formatter can not compute the partition managing position categories. */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public void setPartitionManagingPositionCategories(String[] categories) { fExternalPartitonManagingCategories= TextUtilities.copy(categories); } diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/hyperlink/URLHyperlinkDetector.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/hyperlink/URLHyperlinkDetector.java index 5fee530004a..34937de993f 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/hyperlink/URLHyperlinkDetector.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/hyperlink/URLHyperlinkDetector.java @@ -47,7 +47,7 @@ public URLHyperlinkDetector() { * @param textViewer the text viewer in which to detect the hyperlink * @deprecated As of 3.2, replaced by {@link URLHyperlinkDetector} */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public URLHyperlinkDetector(ITextViewer textViewer) { } diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/rules/RuleBasedDamagerRepairer.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/rules/RuleBasedDamagerRepairer.java index 9397fd07611..00fb50b6ffd 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/rules/RuleBasedDamagerRepairer.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/rules/RuleBasedDamagerRepairer.java @@ -21,7 +21,7 @@ /** * @deprecated use DefaultDamagerRepairer */ -@Deprecated +@Deprecated(forRemoval= true, since= "2025-12") public class RuleBasedDamagerRepairer extends DefaultDamagerRepairer { /** @@ -34,7 +34,7 @@ public class RuleBasedDamagerRepairer extends DefaultDamagerRepairer { * * @deprecated use RuleBasedDamagerRepairer(RuleBasedScanner) instead */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public RuleBasedDamagerRepairer(RuleBasedScanner scanner, TextAttribute defaultTextAttribute) { super(scanner, defaultTextAttribute); } diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationBarHoverManager.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationBarHoverManager.java index 38a23782d87..3c365b35cf5 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationBarHoverManager.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationBarHoverManager.java @@ -177,7 +177,7 @@ public void stop() { * @param delayRestart true if restart should be delayed * @deprecated As of 3.4, replaced by {@link #stop()}. Note that delayRestart was never honored. */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") protected void stop(boolean delayRestart) { stop(); } @@ -313,7 +313,7 @@ public void widgetDisposed(DisposeEvent e) { * @param creator the information control creator * @deprecated As of 2.1, replaced by {@link AnnotationBarHoverManager#AnnotationBarHoverManager(IVerticalRulerInfo, ISourceViewer, IAnnotationHover, IInformationControlCreator)} */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public AnnotationBarHoverManager(ISourceViewer sourceViewer, IVerticalRuler ruler, IAnnotationHover annotationHover, IInformationControlCreator creator) { this(ruler, sourceViewer, annotationHover, creator); } diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationColumn.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationColumn.java index 50d164fed78..7cd9f91666f 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationColumn.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationColumn.java @@ -21,7 +21,7 @@ * instead. * @since 2.0 */ -@Deprecated +@Deprecated(forRemoval= true, since= "2025-12") public final class AnnotationColumn extends AnnotationRulerColumn { /** @@ -32,7 +32,7 @@ public final class AnnotationColumn extends AnnotationRulerColumn { * {@link org.eclipse.jface.text.source.AnnotationRulerColumn#AnnotationRulerColumn(int)} * instead */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public AnnotationColumn(int width) { super(width); } diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationPainter.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationPainter.java index 7e65b8f841b..959f92777b0 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationPainter.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationPainter.java @@ -1141,7 +1141,7 @@ public void setAnnotationTypeColor(Object annotationType, Color color) { * {@link #addTextStyleStrategy(Object, AnnotationPainter.ITextStyleStrategy)} and * {@link UnderlineStrategy} */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public void addAnnotationType(Object annotationType) { addAnnotationType(annotationType, SQUIGGLES); } diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/ChangeRulerColumn.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/ChangeRulerColumn.java index befc92e6c6f..fe9b77b16b6 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/ChangeRulerColumn.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/ChangeRulerColumn.java @@ -152,7 +152,7 @@ public void textChanged(TextEvent event) { * * @deprecated since 3.2 use {@link #ChangeRulerColumn(ISharedTextColors)} instead */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public ChangeRulerColumn() { fRevisionPainter= null; fDiffPainter= new DiffPainter(this, null); @@ -283,7 +283,7 @@ private void doubleBufferPaint(GC dest) { * @deprecated as of 3.2 the number of lines in the viewport cannot be computed because * StyledText supports variable line heights */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") protected int getVisibleLinesInViewport() { // Hack to reduce amount of copied code. return LineNumberRulerColumn.getVisibleLinesInViewport(fCachedTextWidget); diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/VerticalRuler.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/VerticalRuler.java index cc681382d3e..49e699709d0 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/VerticalRuler.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/VerticalRuler.java @@ -599,7 +599,7 @@ public void setLocationOfLastMouseButtonActivity(int x, int y) { * @deprecated will be removed * @since 2.0 */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public void addMouseListener(MouseListener listener) { if (fCanvas != null && !fCanvas.isDisposed()) { fCanvas.addMouseListener(listener); @@ -613,7 +613,7 @@ public void addMouseListener(MouseListener listener) { * @deprecated will be removed * @since 2.0 */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") public void removeMouseListener(MouseListener listener) { if (fCanvas != null && !fCanvas.isDisposed()) { fCanvas.removeMouseListener(listener); diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/templates/TemplateCompletionProcessor.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/templates/TemplateCompletionProcessor.java index 57316607327..f7b96bb690c 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/templates/TemplateCompletionProcessor.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/templates/TemplateCompletionProcessor.java @@ -106,7 +106,7 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int * @deprecated use the version specifying IRegion as third parameter * @since 3.1 */ - @Deprecated + @Deprecated(forRemoval= true, since= "2025-12") protected ICompletionProposal createProposal(Template template, TemplateContext context, Region region, int relevance) { return createProposal(template, context, (IRegion) region, relevance); } diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/dialogs/AnimatorFactory.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/dialogs/AnimatorFactory.java index c2358cf8749..985c44185b9 100644 --- a/bundles/org.eclipse.jface/src/org/eclipse/jface/dialogs/AnimatorFactory.java +++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/dialogs/AnimatorFactory.java @@ -20,7 +20,7 @@ /** * Factory for control animators used by JFace to animate the display of an SWT * Control. Through the use of the method - * {@link org.eclipse.jface.util.Policy#setAnimatorFactory(AnimatorFactory)} + * {@code org.eclipse.jface.util.Policy.setAnimatorFactory(AnimatorFactory)} * a new type of animator factory can be plugged into JFace. * * @since 3.2 diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/dialogs/Dialog.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/dialogs/Dialog.java index aecfc362190..12e534ad85b 100644 --- a/bundles/org.eclipse.jface/src/org/eclipse/jface/dialogs/Dialog.java +++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/dialogs/Dialog.java @@ -16,6 +16,7 @@ import java.util.Arrays; import java.util.HashMap; +import java.util.concurrent.atomic.AtomicReference; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -40,6 +41,7 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; /** @@ -1086,9 +1088,62 @@ protected static boolean dialogFontIsDefault() { @Override public void create() { super.create(); + hookZoomChangeListenerForDefaultSizedDialogs(); applyDialogFont(buttonBar); } + /* + * There is no linear relation between font size and containing control size + * scaled according to some zoom value. In consequence, text with a scaled font + * size may not fit into a control/shell with a size scaled by the same zoom. To + * adhere for this in case of Windows using the default computed size, ensure + * that on zoom change the new proper size is computed and applied. This will + * not affect Windows that have a custom size, either programmatically or + * manually applied. + */ + private void hookZoomChangeListenerForDefaultSizedDialogs() { + boolean hasCustomSize = !getShell().getSize().equals(getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true)); + boolean isEmpty = getShell().getChildren().length == 0; + if (resizeHasOccurred || hasCustomSize || isEmpty || isResizable()) { + return; + } + + AtomicReference customResizeListener = new AtomicReference<>(); + Listener adaptDefaultSizeListener = event -> { + Shell shell = getShell(); + if (shell == null || shell.isDisposed()) { + return; + } + Point size = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); + shell.setSize(size); + }; + AtomicReference zoomChangeListener = new AtomicReference<>(); + zoomChangeListener.set(event -> { + Shell shell = getShell(); + if (shell == null || shell.isDisposed()) { + return; + } + shell.addListener(SWT.Resize, adaptDefaultSizeListener); + shell.removeListener(SWT.Resize, customResizeListener.get()); + shell.getChildren()[0].removeListener(SWT.ZoomChanged, zoomChangeListener.get()); + }); + customResizeListener.set(event -> { + Shell shell = getShell(); + if (shell == null || shell.isDisposed()) { + return; + } + shell.getChildren()[0].removeListener(SWT.ZoomChanged, zoomChangeListener.get()); + }); + + // We need to detect the zoom change event before the resize triggered by the + // zoom change happened, which is why we cannot listen to the zoom change at the + // shell but must use one of its children + getShell().getChildren()[0].addListener(SWT.ZoomChanged, zoomChangeListener.get()); + // If custom resize happens before first zoom change, the dialog is custom sized + // and should not be auto-resized on zoom change + getShell().addListener(SWT.Resize, customResizeListener.get()); + } + /** * Get the IDialogBlockedHandler to be used by WizardDialogs and * ModalContexts. diff --git a/bundles/org.eclipse.search/search/org/eclipse/search/internal/ui/text/TextSearchPage.java b/bundles/org.eclipse.search/search/org/eclipse/search/internal/ui/text/TextSearchPage.java index a8a9bcd7b7e..64883c53ed8 100644 --- a/bundles/org.eclipse.search/search/org/eclipse/search/internal/ui/text/TextSearchPage.java +++ b/bundles/org.eclipse.search/search/org/eclipse/search/internal/ui/text/TextSearchPage.java @@ -643,13 +643,6 @@ private boolean initializePatternControl() { return false; } -// private void loadFilePatternDefaults() { -// SearchMatchInformationProviderRegistry registry= SearchPlugin.getDefault().getSearchMatchInformationProviderRegistry(); -// String[] defaults= registry.getDefaultFilePatterns(); -// fExtensions.setItems(defaults); -// fExtensions.setText(defaults[0]); -// } - private String insertEscapeChars(String text) { if (text == null || text.equals("")) { //$NON-NLS-1$ return ""; //$NON-NLS-1$ diff --git a/bundles/org.eclipse.text.quicksearch/src/org/eclipse/text/quicksearch/internal/ui/QuickSearchDialog.java b/bundles/org.eclipse.text.quicksearch/src/org/eclipse/text/quicksearch/internal/ui/QuickSearchDialog.java index a575f4c6ca9..76eb609ad32 100644 --- a/bundles/org.eclipse.text.quicksearch/src/org/eclipse/text/quicksearch/internal/ui/QuickSearchDialog.java +++ b/bundles/org.eclipse.text.quicksearch/src/org/eclipse/text/quicksearch/internal/ui/QuickSearchDialog.java @@ -58,6 +58,7 @@ import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.CursorLinePainter; +import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.source.CompositeRuler; @@ -1173,6 +1174,9 @@ private void refreshDetails() { viewer.revealRange(rangeStart, rangeEnd - rangeStart); var targetLineFirstMatch = getQuery().findFirst(document.get(item.getOffset(), contextLenght - (item.getOffset() - start))); + if (targetLineFirstMatch == null) { + return; // nothing to refresh + } int targetLineFirstMatchStart = item.getOffset() + targetLineFirstMatch.getOffset(); // sets caret position viewer.setSelectedRange(targetLineFirstMatchStart, 0); @@ -1289,6 +1293,10 @@ public void refreshWidgets() { //element is available in the list. openButton.setEnabled(itemCount>0); } + //Auto-select the first search result for preview to be shown. + if (itemCount >= 1 && list.getSelection().isEmpty()) { + list.getTable().select(0); + } refreshDetails(); } } @@ -1484,6 +1492,14 @@ public void update(LineItem match) { } else { //The QuickTextSearcher is already active update the query this.searcher.setQuery(newFilter, force); + if(newFilter.getPatternString().trim().isEmpty()) { + //When pattern is cleared, clear the preview section + viewer.setDocument(new Document("")); //$NON-NLS-1$ + if (lineNumberColumn != null) { + viewer.removeVerticalRulerColumn(lineNumberColumn); + viewer.addVerticalRulerColumn(lineNumberColumn); + } + } } if (progressJob!=null) { progressJob.schedule(); diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties index c4f7203e9c6..b79612e23ef 100644 --- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties @@ -538,7 +538,7 @@ IDEWorkspacePreference_fileLineDelimiter=New text &file line delimiter IDEWorkspacePreference_defaultLineDelim=D&efault ({0}) IDEWorkspacePreference_defaultLineDelimProj=Inh&erited from container ({0}) IDEWorkspacePreference_otherLineDelim= Ot&her: -IDEWorkspacePreference_relatedLink = See ''{0}'' for workspace startup and shutdown preferences. +IDEWorkspacePreference_relatedLink = See {0} for workspace startup and shutdown preferences. IDEWorkspacePreference_openReferencedProjects = Open referenced projects when a project is opened: IDEWorkspacePreference_closeUnrelatedProjectsToolTip = Close unrelated projects without prompt IDEWorkspacePreference_windowTitleGroupText=Window title @@ -1103,9 +1103,9 @@ CleanDialog_typeFilterText=type filter text CleanDialog_clearToolTip=Clear CleanDialog_AccessibleListenerClearButton=Clear filter field IDEEncoding_EncodingJob=Setting encoding -IDEEditorsPreferencePage_WorkbenchPreference_FileEditorsRelatedLink=See ''{0}'' for associating editors with file types. -IDEEditorsPreferencePage_WorkbenchPreference_viewsRelatedLink = See ''{0}'' for appearance preferences. -IDEEditorsPreferencePage_WorkbenchPreference_contentTypesRelatedLink = See ''{0}'' for content-type based file associations. +IDEEditorsPreferencePage_WorkbenchPreference_FileEditorsRelatedLink=See {0} for associating editors with file types. +IDEEditorsPreferencePage_WorkbenchPreference_viewsRelatedLink = See {0} for appearance preferences. +IDEEditorsPreferencePage_WorkbenchPreference_contentTypesRelatedLink = See {0} for content-type based file associations. WorkbenchEncoding_invalidCharset = {0} is not a valid charset. IDE_areYouSure={0} Do you want to continue? ExtendedFileEditorsPreferencePage_strategyForUnassociatedFiles=&Open unassociated files with: diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/views/markers/MarkerContentGenerator.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/views/markers/MarkerContentGenerator.java index ac2aff459f5..acba0703db3 100644 --- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/views/markers/MarkerContentGenerator.java +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/views/markers/MarkerContentGenerator.java @@ -758,9 +758,7 @@ void updateSelectedResource(Object[] newElements, boolean forceUpdate) { if (forceUpdate || updateNeededForSelection(newElements)) { internalUpdateSelectedElements(newElements); // See comments below and Bug 296695 - // if (contentChanged()) { requestMarkerUpdate(); - // } } } diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/views/markers/MarkersChangeListener.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/views/markers/MarkersChangeListener.java index 7c9d204c756..1b47a6efb5a 100644 --- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/views/markers/MarkersChangeListener.java +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/views/markers/MarkersChangeListener.java @@ -40,8 +40,6 @@ class MarkersChangeListener implements IResourceChangeListener { private String[] listeningTypes; private boolean receiving; - //private static final int UPDATE_TEST_CHECK_LIMIT = 1500; - // The time the build started. A -1 indicates no build in progress. private long preBuildTime; @@ -130,9 +128,6 @@ public synchronized void resourceChanged(IResourceChangeEvent event) { if(!hasApplicableTypes(event)){ return; } - // if (!needsUpdate(event)) { - // return; - // } if (!builder.isIncremental()) { builder.getUpdateScheduler().scheduleUpdate(); @@ -159,13 +154,6 @@ void setReceivingChange(boolean receiving) { this.receiving = receiving; } - /** - * Markers have not changed - */ - private void handleNoMarkerChange() { - //view.indicateUpdating(null, true, false); - } - /** * Handle changes incrementally. * The following performs incremental updation @@ -218,10 +206,7 @@ private void handleIncrementalChange(IResourceChangeEvent event) { MarkerUpdate update = new MarkerUpdate(added, removed, changed); builder.incrementalUpdate(update); builder.getUpdateScheduler().scheduleUpdate(); - } else { - handleNoMarkerChange(); } - return; } /** @@ -254,155 +239,6 @@ private boolean isApplicableType(String[] types, String typeId) { return false; } -// /** -// * Note: This has been left commented out for further -// * investigation(*),instead we we use the above for just checking types. -// * This may invoke contributed code; as a field filter can be contributed. -// * But again in such a case, the view would be a contributed as well.And, it -// * is the responsibility of the field filter code to ensure the select -// * method of filter remains fast. -// * -// */ -// private boolean needsUpdate(IResourceChangeEvent event) { -// IMarkerDelta[] markerDeltas = event.findMarkerDeltas(null, true); -// MarkerEntry[] presentEntries = builder.getClonedMarkers().getClone() -// .getMarkerEntryArray(); -// int deltaCount = markerDeltas.length; -// if (deltaCount == 0) { -// return false; -// } -// String[] types = listeningTypes; -// if (hasMarkerRemoval(presentEntries, null)) { -// return true; -// } -// int maxTestCount = deltaCount > UPDATE_TEST_CHECK_LIMIT ? UPDATE_TEST_CHECK_LIMIT -// : deltaCount; -// -// for (int i = 0; i < markerDeltas.length; i++) { -// String typeId = markerDeltas[i].getType(); -// if (!hasApplicableTypes(types, typeId)) { -// continue; -// } -// if (presentEntries == null || presentEntries.length == 0) { -// return true; -// } -// int kind = markerDeltas[i].getKind(); -// IMarker marker = markerDeltas[i].getMarker(); -// MarkerEntry markerEntry = new MarkerEntry(marker); -// if (affectsCurrentState(presentEntries, markerEntry, kind)) { -// return true; -// } -// if (i >= maxTestCount - 1) { -// return true; -// } -// } -// return false; -// } -// -// /** -// * Check if a marker change, removal, or addition is of interest to the -// * view. -// * -// *

-// * -// * @param marker -// * @param kind -// */ -// private boolean affectsCurrentState(MarkerEntry[] presentEntries, -// MarkerEntry marker, int kind) { -// switch (kind) { -// case IResourceDelta.REMOVED: { -// return hasMarkerRemoval(presentEntries, marker); -// } -// case IResourceDelta.ADDED: { -// return hasMarkerAdditionsofInterest(presentEntries, marker); -// } -// case IResourceDelta.CHANGED: { -// return hasMarkerChanges(presentEntries, marker); -// } -// default: { -// return false; -// } -// } -// } -// -// /** -// * Returns whether or not the given marker addition is of interest to the -// * view. -// * -// * @param presentEntries -// * current marker entries -// * @param marker -// * the marker entry -// * @return true if build is needed false if no -// * update needed -// */ -// private boolean hasMarkerAdditionsofInterest(MarkerEntry[] presentEntries, -// MarkerEntry marker) { -// MarkerContentGenerator generator = builder.getGenerator(); -// if (generator.select(marker)) { -// return true; -// } -// return false; -// } -// -// /** -// * Returns whether or not markers were removed from the view. -// * -// * @param presentEntriest -// * current marker entries -// * @param marker -// * the marker entry -// * @return true if build is needed false if no -// * update needed -// */ -// private boolean hasMarkerRemoval(MarkerEntry[] presentEntriest, -// MarkerEntry marker) { -// for (int i = 0; i < presentEntriest.length; i++) { -// if (presentEntriest[i].getStaleState() -// || presentEntriest[i].getMarker() == null) { -// return true; -// } -// if (marker != null) { -// if (presentEntriest[i].getMarker().equals(marker.getMarker())) { -// return false; -// } -// } -// } -// return false; -// } -// -// /** -// * Returns whether or not markers were removed from the view. -// * -// * @param presentEntriest -// * current marker entries -// * @param marker -// * the marker entry -// * @return true if build is needed false if no -// * update needed -// */ -// private boolean hasMarkerChanges(MarkerEntry[] presentEntriest, -// MarkerEntry marker) { -// MarkerContentGenerator generator = builder.getGenerator(); -// if (generator.select(marker)) { -// return true; -// } -// for (int i = 0; i < presentEntriest.length; i++) { -// if (presentEntriest[i].getMarker().equals(marker.getMarker())) { -// return true; -// } -// -// } -// return false; -// } - /** * We are in a pre-build state. */ @@ -604,31 +440,6 @@ void cancelQueuedUIUpdates() { view.cancelQueuedUpdates(); } - ///** - // * Indicate the status message on UI. - // * - // * @param messsage - // * the status to display - // */ - //void indicateStatus(String messsage) { - // indicateStatus(messsage, false); - //} - ////See Bug 294303 - ///** - // * Indicate the status message on UI. - // * - // * @param messsage - // * the status to display - // * @param updateUI - // * true update label to show changing status - // */ - //void indicateStatus(String messsage, boolean updateUI) { - // //See Bug 294303 - // view.indicateUpdating(messsage != null ? messsage - // : MarkerMessages.MarkerView_queueing_updates, updateUI); - //} - - /** * //Fix for Bug 294959.There is another patch(more exhaustive in terms * of possibilities to cover) on the bug in which we keep scheduling @@ -709,12 +520,6 @@ void update() { go(delay, cancelable); } } else { - //long diff =timeB4Update-currentTime; - //if (diff <= AFTER_MARGIN && diff >= 0) { - // go(0L, false); - //} else { - // go(LONG_DELAY, cancelable); - //} go(LONG_DELAY, cancelable); } } else { diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/contentassist/ContentAssistHandler.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/contentassist/ContentAssistHandler.java index faf9990b959..ae6692d460e 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/contentassist/ContentAssistHandler.java +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/contentassist/ContentAssistHandler.java @@ -82,6 +82,7 @@ public class ContentAssistHandler { * @param contentAssistant a configured content assistant * @return a new {@link ContentAssistHandler} */ + @Deprecated public static ContentAssistHandler createHandlerForCombo(Combo combo, SubjectControlContentAssistant contentAssistant) { return new ContentAssistHandler(combo, new ComboContentAssistSubjectAdapter(combo), contentAssistant); } @@ -95,6 +96,7 @@ public static ContentAssistHandler createHandlerForCombo(Combo combo, SubjectCon * @param contentAssistant a configured content assistant * @return a new {@link ContentAssistHandler} */ + @Deprecated public static ContentAssistHandler createHandlerForText(Text text, SubjectControlContentAssistant contentAssistant) { return new ContentAssistHandler(text, new TextContentAssistSubjectAdapter(text), contentAssistant); } @@ -120,6 +122,7 @@ private ContentAssistHandler( /** * @return true iff content assist is enabled */ + @Deprecated public boolean isEnabled() { return fFocusListener != null; } @@ -131,6 +134,7 @@ public boolean isEnabled() { * * @param enable enable content assist iff true */ + @Deprecated public void setEnabled(boolean enable) { if (enable == isEnabled()) { return; diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ConvertLineDelimitersAction.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ConvertLineDelimitersAction.java index bea90b4c86b..bdc3cafb444 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ConvertLineDelimitersAction.java +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ConvertLineDelimitersAction.java @@ -57,6 +57,7 @@ public class ConvertLineDelimitersAction extends TextEditorAction { * @param editor the editor * @param lineDelimiter the target line delimiter to convert the editor's document to */ + @Deprecated public ConvertLineDelimitersAction(ITextEditor editor, String lineDelimiter) { this(EditorMessages.getBundleForConstructedKeys(), "dummy", editor, lineDelimiter); //$NON-NLS-1$ } @@ -69,6 +70,7 @@ public ConvertLineDelimitersAction(ITextEditor editor, String lineDelimiter) { * @param editor the editor * @param lineDelimiter the target line delimiter to convert the editor's document to */ + @Deprecated public ConvertLineDelimitersAction(ResourceBundle bundle, String prefix, ITextEditor editor, String lineDelimiter) { super(bundle, prefix, editor); fLineDelimiter= lineDelimiter; @@ -79,6 +81,7 @@ public ConvertLineDelimitersAction(ResourceBundle bundle, String prefix, ITextEd update(); } + @Deprecated @Override public void run() { @@ -276,6 +279,7 @@ private static String getString(String key) { } } + @Deprecated @Override public void update() { super.update(); diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/InfoForm.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/InfoForm.java index b761ecae402..ebf7ccdea02 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/InfoForm.java +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/InfoForm.java @@ -63,6 +63,7 @@ public class InfoForm { * Creates a new info form. * @param parent the parent composite */ + @Deprecated public InfoForm(Composite parent) { Display display= parent.getDisplay(); @@ -113,6 +114,7 @@ public InfoForm(Composite parent) { * Hook method for creating an appropriate action control. * @param parent the action control's parent control */ + @Deprecated protected void createActionControls(Composite parent) { } @@ -120,6 +122,7 @@ protected void createActionControls(Composite parent) { * Returns the control of this form. * @return the root control of this form */ + @Deprecated public Control getControl() { return fScrolledComposite; } @@ -128,6 +131,7 @@ public Control getControl() { * Sets the header text of this info form. * @param header the header text */ + @Deprecated public void setHeaderText(String header) { fHeader.setText(header); } @@ -136,6 +140,7 @@ public void setHeaderText(String header) { * Sets the banner text of this info form. * @param banner the banner text */ + @Deprecated public void setBannerText(String banner) { fBanner.setText(banner); } @@ -144,6 +149,7 @@ public void setBannerText(String banner) { * Sets the info of this info form * @param info the info text */ + @Deprecated public void setInfo(String info) { fText.setText(info); } @@ -153,6 +159,7 @@ public void setInfo(String info) { * * @param event the property change event object describing which property changed and how */ + @Deprecated protected void handlePropertyChange(PropertyChangeEvent event) { if (fHeader != null) { diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/SaveAction.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/SaveAction.java index 33ceb932bbe..319f4cb9a3d 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/SaveAction.java +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/SaveAction.java @@ -41,15 +41,18 @@ public class SaveAction extends TextEditorAction { * @param editor the text editor * @see TextEditorAction#TextEditorAction(ResourceBundle, String, ITextEditor) */ + @Deprecated public SaveAction(ResourceBundle bundle, String prefix, ITextEditor editor) { super(bundle, prefix, editor); } + @Deprecated @Override public void run() { getTextEditor().getSite().getPage().saveEditor(getTextEditor(), false); } + @Deprecated @Override public void update() { setEnabled(getTextEditor().isDirty()); diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ValidateStateException.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ValidateStateException.java index e0d1aca3b4e..7f193cfc3fb 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ValidateStateException.java +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ValidateStateException.java @@ -42,7 +42,8 @@ public class ValidateStateException extends CoreException { /* * @see CoreException#CoreException(org.eclipse.core.runtime.IStatus) */ - public ValidateStateException(IStatus status) { + @Deprecated + public ValidateStateException(IStatus status) { super(status); } diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/WorkbenchChainedTextFontFieldEditor.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/WorkbenchChainedTextFontFieldEditor.java index a77e3247e9f..7d038f359ea 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/WorkbenchChainedTextFontFieldEditor.java +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/WorkbenchChainedTextFontFieldEditor.java @@ -52,6 +52,7 @@ public class WorkbenchChainedTextFontFieldEditor extends PropagatingFontFieldEdi * @param labelText the text shown as editor description * @param parent the editor's parent widget */ + @Deprecated public WorkbenchChainedTextFontFieldEditor(String name, String labelText, Composite parent) { super(name, labelText, parent, EditorMessages.WorkbenchChainedTextFontFieldEditor_defaultWorkbenchTextFont); } @@ -63,6 +64,7 @@ public WorkbenchChainedTextFontFieldEditor(String name, String labelText, Compos * @param target the target preference store * @param targetKey the key to be used in the target preference store */ + @Deprecated public static void startPropagate(IPreferenceStore target, String targetKey) { IPreferenceStore store= new ScopedPreferenceStore(InstanceScope.INSTANCE, "org.eclipse.ui.workbench"); //$NON-NLS-1$ PropagatingFontFieldEditor.startPropagate(store, JFaceResources.TEXT_FONT, target, targetKey); diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/templates/TemplatePreferencePage.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/templates/TemplatePreferencePage.java index f9984a6e28d..587a53a8319 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/templates/TemplatePreferencePage.java +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/templates/TemplatePreferencePage.java @@ -998,8 +998,9 @@ public void setSearchText(String s) { } @Override public boolean select(Viewer viewer, Object parentElement, Object element) { - if (searchString.isEmpty()) + if (searchString.isEmpty()) { return true; + } Template template = ((TemplatePersistenceData) element).getTemplate(); return template.getName().toLowerCase().contains(searchString) || template.getContextTypeId().toLowerCase().contains(searchString) diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/dialogs/FilteredItemsSelectionDialog.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/dialogs/FilteredItemsSelectionDialog.java index 5da18768f29..f02f5879852 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/dialogs/FilteredItemsSelectionDialog.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/dialogs/FilteredItemsSelectionDialog.java @@ -873,6 +873,26 @@ public void refresh() { tableViewer.setItemCount(contentProvider.getNumberOfElements()); tableViewer.refresh(); + // ⚠️ DEMONSTRATION: Inject delay to make race condition reproducible + // This simulates what happens on slow systems where tableViewer.refresh() + // takes longer to complete. On fast systems, the race condition is intermittent + // because refresh() usually completes quickly enough. This delay makes it + // fail consistently by preventing the table from being ready when setSelection() + // is called below. + // + // To see the race condition: + // 1. Compile this code + // 2. Run ResourceInitialSelectionTest + // 3. Tests will fail with: expected:<[...foo.txt]> but was:<[]> + // + // This demonstrates the root cause that was fixed by using Display.asyncExec() + // in commit 33748d2f3a. + try { + Thread.sleep(500); // 500ms delay - makes race condition 100% reproducible + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + if (tableViewer.getTable().getItemCount() > 0) { if (isShownForTheFirstTime) { isShownForTheFirstTime = false; diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/HeapStatus.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/HeapStatus.java index e5c15f63132..a108c2ce36a 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/HeapStatus.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/HeapStatus.java @@ -303,9 +303,6 @@ private void fillMenu(IMenuManager menuMgr) { menuMgr.add(new ClearMarkAction()); menuMgr.add(new ShowMaxAction()); menuMgr.add(new CloseHeapStatusAction()); -// if (isKyrsoftViewAvailable()) { -// menuMgr.add(new ShowKyrsoftViewAction()); -// } } /** diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchMessages.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchMessages.java index 7f1f1435b4f..4592061f679 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchMessages.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchMessages.java @@ -34,8 +34,6 @@ public class WorkbenchMessages extends NLS { public static String ThemingEnabled; - public static String HiDpiSettingsGroupTitle; - public static String RescaleAtRuntimeDescription; public static String RescaleAtRuntimeEnabled; diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPage.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPage.java index 9fbee4b235b..2e3300d0c22 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPage.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPage.java @@ -3423,16 +3423,18 @@ public void resetPerspective() { // Hide placeholders for parts that exist in the 'global' areas modelService.hideLocalPlaceholders(window, dummyPerspective); - int dCount = dummyPerspective.getChildren().size(); - while (!dummyPerspective.getChildren().isEmpty()) { - MPartSashContainerElement dChild = dummyPerspective.getChildren().remove(0); - persp.getChildren().add(dChild); + List dummyChildren = dummyPerspective.getChildren(); + List perspChildren = persp.getChildren(); + int dCount = dummyChildren.size(); + while (!dummyChildren.isEmpty()) { + MPartSashContainerElement dChild = dummyChildren.remove(0); + perspChildren.add(dChild); } - while (persp.getChildren().size() > dCount) { - MUIElement child = persp.getChildren().get(0); + while (perspChildren.size() > dCount) { + MUIElement child = perspChildren.get(0); child.setToBeRendered(false); - persp.getChildren().remove(0); + perspChildren.remove(0); } List existingDetachedWindows = new ArrayList<>(); diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/messages.properties b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/messages.properties index aa3e02edf00..3cb4caeadc2 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/messages.properties +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/messages.properties @@ -502,7 +502,6 @@ ThemeChangeWarningText = Restart for the theme changes to take full effect ThemeChangeWarningTitle = Theme Changed RescaleAtRuntimeSettingChangeWarningTitle = DPI Setting Changed RescaleAtRuntimeSettingChangeWarningText = Restart for the DPI setting changes to take effect -HiDpiSettingsGroupTitle = HiDPI settings RescaleAtRuntimeDescription = Activating this option will dynamically scale all windows according to the monitor they are currently in RescaleAtRuntimeEnabled = Use monitor-specific UI &scaling # --- Workbench ----- @@ -933,7 +932,7 @@ ContentTypes_fileAssociationsEditLabel = Ed&it... ContentTypes_fileAssociationsRemoveLabel = &Remove ContentTypes_contentTypesLabel = &Content types: ContentTypes_errorDialogMessage = There was an error removing content type file association(s). -ContentTypes_FileEditorsRelatedLink=See ''{0}'' for associating editors with file types. +ContentTypes_FileEditorsRelatedLink=See {0} for associating editors with file types. ContentTypes_addDialog_title=Add Content Type Association ContentTypes_addDialog_messageHeader=Define New Content Type Association ContentTypes_addDialog_message=Enter content type association to add: (*.doc or report.doc for example) diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/WizardsRegistryReader.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/WizardsRegistryReader.java index ed63e55b5e9..be425ba0637 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/WizardsRegistryReader.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/WizardsRegistryReader.java @@ -76,14 +76,15 @@ private static class CategoryNode { CategoryNode(Category cat) { category = cat; - path = ""; //$NON-NLS-1$ String[] categoryPath = category.getParentPath(); + StringBuilder pathBuilder = new StringBuilder(); if (categoryPath != null) { for (String parentPath : categoryPath) { - path += parentPath + '/'; + pathBuilder.append(parentPath).append('/'); } } - path += cat.getId(); + pathBuilder.append(cat.getId()); + path = pathBuilder.toString(); } String getPath() { diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/part/MultiPageEditorPart.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/part/MultiPageEditorPart.java index cc415b94423..6097c863995 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/part/MultiPageEditorPart.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/part/MultiPageEditorPart.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. + * Copyright (c) 2000, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -648,11 +648,8 @@ protected Control getControl(int pageIndex) { */ protected IEditorPart getEditor(int pageIndex) { Item item = getItem(pageIndex); - if (item != null) { - Object data = item.getData(); - if (data instanceof IEditorPart) { - return (IEditorPart) data; - } + if (item != null && !item.isDisposed() && item.getData() instanceof IEditorPart ep) { + return ep; } return null; } diff --git a/docs/e4/ToolBarContribution.md b/docs/e4/ToolBarContribution.md new file mode 100644 index 00000000000..37c394ac2aa --- /dev/null +++ b/docs/e4/ToolBarContribution.md @@ -0,0 +1,459 @@ +# E4 ToolBarContribution + +## Overview + +A `ToolBarContribution` (represented by `MToolBarContribution` in code) is a model element that allows you to dynamically contribute toolbar items to existing toolbars in an Eclipse 4 application. This is the E4 equivalent of the Eclipse 3.x toolbar extension mechanism, but implemented through the declarative E4 application model. + +ToolBarContributions enable modular development by allowing plugins to add toolbar items to toolbars defined elsewhere in the application model, without directly modifying the target toolbar's definition. + +## Use Cases + +ToolBarContributions are useful in several scenarios: + +1. **Plugin Contributions**: When your plugin needs to add toolbar buttons to application-level or view-specific toolbars without modifying the core application model. + +2. **Modular UI Design**: When building applications where different modules contribute their own toolbar items to a shared toolbar. + +3. **Dynamic Contributions**: When toolbar items need to be added or removed based on runtime conditions using visibility expressions. + +4. **Fragment-based Contributions**: When using model fragments to contribute to an existing application's toolbars from separate plugins. + +5. **Context-specific Actions**: When adding toolbar items that are only relevant in specific contexts (e.g., perspective-specific or view-specific toolbars). + +## Core Concepts + +### ToolBar vs ToolBarContribution + +- **`MToolBar`**: A concrete toolbar that is rendered in the UI. It has an `elementId` that other contributions can target. +- **`MToolBarContribution`**: A contribution descriptor that specifies: + - Which toolbar to contribute to (via `parentId`) + - Where in that toolbar to place the items (via `positionInParent`) + - What toolbar items to add (via its `children` list) + +### Key Attributes + +#### parentId +The `elementId` of the target toolbar where items will be contributed. Common targets include: +- `org.eclipse.ui.main.toolbar` - The main application toolbar +- View-specific toolbar IDs (typically the view's part ID) +- Custom toolbar IDs defined in your application + +#### positionInParent +Specifies where in the target toolbar the contributed items should appear. Format: `=` + +Supported modifiers: +- `after=` - Insert after the element with the given ID +- `before=` - Insert before the element with the given ID +- `first` - Insert at the beginning +- `endof=` - Insert at the end of a logical group (after a separator) +- `index:` - Insert at specific position (0-based) + +If not specified, items are appended to the end of the toolbar. + +Examples: +- `after=org.eclipse.ui.edit.save` - After the Save button +- `before=additions` - Before the "additions" separator +- `endof=file.group` - At the end of the file group + +#### children +A list of `MToolBarElement` items to contribute. Common types include: +- `MHandledToolItem` - A button that invokes a command +- `MDirectToolItem` - A button with direct implementation +- `MToolBarSeparator` - A visual separator +- `MToolControl` - A custom widget/control + +## Creating a ToolBarContribution + +### Using the E4 Model Editor + +1. **Open your fragment.e4xmi** with the E4 Model Editor (right-click → Open With → E4 Model Editor) + +2. **Create a StringModelFragment** (if not already present): + - In the Model Fragments section, click "Add" + - Select "StringModelFragment" + - Set `featurename` to `toolBarContributions` + - Set `parentElementId` to your application ID (e.g., `com.example.myapp.application`) + +3. **Add a ToolBarContribution**: + - Under the StringModelFragment elements, click "Add" + - Select "ToolBarContribution" + - Set the `elementId` (e.g., `com.example.myapp.toolbar.contribution`) + - Set `parentId` to the target toolbar ID (e.g., `org.eclipse.ui.main.toolbar`) + - Set `positionInParent` if you need specific placement (e.g., `after=save`) + +4. **Add Toolbar Items**: + - Select your ToolBarContribution + - In the Children section, click "Add" + - Select the appropriate item type (typically `HandledToolItem`) + - Configure the item: + - Set `elementId` (e.g., `com.example.myapp.toolbar.myaction`) + - Set `label` (tooltip text) + - Set `iconURI` (e.g., `platform:/plugin/com.example.myapp/icons/myicon.png`) + - For HandledToolItem, select or import the command to execute + +### XML Example + +Here's what a ToolBarContribution looks like in the fragment.e4xmi XML: + +```xml + + + + + + + + + + + + + + + + + + +``` + +## Example: Extending the E4 Application Template + +The [Eclipse PDE E4 Application template](https://github.com/eclipse-pde/eclipse.pde/blob/master/ui/org.eclipse.pde.ui.templates/templates_3.5/E4Application/Application.e4xmi) provides a basic E4 application with a main toolbar. + +Let's add a custom toolbar contribution to this application. + +### Step 1: Identify the Target Toolbar + +The template defines a main toolbar: +```xml + + + + + +``` + +The target `parentId` is `org.eclipse.ui.main.toolbar`. + +### Step 2: Create a Fragment + +Create a new plugin with a fragment.e4xmi: + +1. Create a plugin project (File → New → Plug-in Project) +2. Add a dependency on `org.eclipse.e4.ui.model.workbench` +3. Create `fragment.e4xmi` in the project root +4. Register it in plugin.xml: + +```xml + + + +``` + +### Step 3: Define the Contribution + +Edit fragment.e4xmi to add your toolbar contribution: + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +### Step 4: Implement the Handler + +Create the handler class referenced in the contribution: + +```java +package com.example.extension.handlers; + +import org.eclipse.e4.core.di.annotations.Execute; + +public class RefreshHandler { + + @Execute + public void execute() { + // Your refresh logic here + System.out.println("Refresh action executed!"); + } +} +``` + +### Step 5: Run the Application + +1. Run the application with the `-clearPersistedState` flag to see model changes +2. Your toolbar contribution should appear in the main toolbar after the Save button + +## Where Contributions Become Visible + +ToolBarContributions are processed at application startup and merged into the target toolbar at the position specified. The contributed items become part of the toolbar's children and are rendered like any other toolbar item. + +Key points about visibility: + +1. **Target Must Exist**: The toolbar specified in `parentId` must exist in the application model for the contribution to be processed. + +2. **Rendering**: Contributed items are rendered when the target toolbar is rendered. For the main toolbar, this is typically at application startup. + +3. **View Toolbars**: When contributing to view-specific toolbars, items appear when the view is opened. + +4. **Dynamic Visibility**: Individual contributed items can have `visibleWhen` expressions to control their visibility based on application state. + +## Visibility Control + +### Item-level Visibility + +You can add a `visibleWhen` expression to individual toolbar items: + +```xml + + + +``` + +### Contribution-level Visibility + +You can also add a `visibleWhen` expression to the entire ToolBarContribution: + +```xml + + + + +``` + +When the expression evaluates to false, none of the contributed items will be visible. + +## Dynamic Contributions with Factories + +For advanced scenarios, you can use a factory to dynamically generate toolbar items: + +```java +public class DynamicToolBarContributionFactory { + + @Execute + public void createItems(List items, + MToolBar toolbar, + ToolBarManagerRenderer renderer) { + // Dynamically create toolbar items based on runtime state + for (String action : getAvailableActions()) { + MHandledToolItem item = MenuFactoryImpl.eINSTANCE.createHandledToolItem(); + item.setElementId("dynamic." + action); + item.setLabel(action); + // Configure item... + items.add(item); + } + } + + private List getAvailableActions() { + // Return list based on runtime state + return Arrays.asList("Action1", "Action2", "Action3"); + } +} +``` + +Register the factory in the ToolBarContribution's transient data using the key `ToolBarContributionFactory`. + +## Common Patterns + +### Pattern 1: Adding a Single Button + +The simplest case - add one button to an existing toolbar: + +```xml + + + +``` + +### Pattern 2: Adding a Group with Separator + +Add multiple related items with separators: + +```xml + + + + + + + + + + +``` + +### Pattern 3: View-Specific Toolbar Contribution + +Contribute to a specific view's toolbar: + +```xml + + + +``` + +Note: The view must define a toolbar with the specified `elementId`. + +## Best Practices + +1. **Use Meaningful IDs**: Choose clear, unique element IDs that indicate purpose and origin (e.g., `com.mycompany.plugin.toolbar.contribution.export`). + +2. **Position Carefully**: Use `positionInParent` to place items in logical locations. Respect existing groupings and separators. + +3. **Provide Icons**: Always provide appropriate icons for toolbar items. Use scalable formats (SVG) when possible. + +4. **Set Tooltips**: Use the `tooltip` attribute (or `label` for basic tooltips) to describe what the button does. + +5. **Use Separators**: Group related items together and use separators to visually distinguish groups. + +6. **Test Visibility**: If using `visibleWhen` expressions, thoroughly test that items appear and disappear as expected. + +7. **Avoid Clutter**: Don't add too many items to a single toolbar. Consider using menus for less-frequently used actions. + +8. **Handle Missing Targets Gracefully**: If the target toolbar might not exist, ensure your contribution doesn't cause errors. The framework will silently ignore contributions to non-existent toolbars. + +9. **Clear Persisted State During Development**: When testing model changes, run with `-clearPersistedState` to ensure changes are picked up. + +10. **Document Your Contribution Points**: If you're providing a toolbar for others to contribute to, document its ID and preferred contribution patterns. + +## Troubleshooting + +### Contribution Not Appearing + +1. **Check parentId**: Ensure the target toolbar exists and has the correct ID +2. **Verify fragment registration**: Confirm plugin.xml registers the fragment correctly +3. **Clear persisted state**: Run with `-clearPersistedState` +4. **Check dependencies**: Ensure required plugins are available +5. **Review positioning**: Invalid `positionInParent` values may prevent contribution + +### Items in Wrong Position + +1. **Verify reference IDs**: The ID in `positionInParent` must match an existing element +2. **Check separator names**: Separator IDs are case-sensitive +3. **Consider order**: Multiple contributions to the same position are processed in plugin load order + +### Visibility Issues + +1. **Test expressions**: Ensure `visibleWhen` expressions are properly defined +2. **Check context**: Verify required context variables are available +3. **Debug rendering**: Enable E4 model debugging to see contribution processing + +## Related Concepts + +- **[MenuContribution](../Menu_Contributions.md)**: Similar concept for menu contributions +- **[E4 Commands](../Eclipse4_Commands.md)**: Commands that toolbar items invoke +- **[E4 Model](../Eclipse4_Model.md)**: General E4 model concepts +- **[Dependency Injection](../Eclipse4_RCP_Dependency_Injection.md)**: How handlers receive context + +## References + +- [Eclipse 4 Model API JavaDoc](https://help.eclipse.org/latest/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fe4%2Fui%2Fmodel%2Fapplication%2Fpackage-summary.html) +- [Eclipse 4 Wiki - Modeled UI](https://wiki.eclipse.org/Eclipse4/RCP/Modeled_UI) +- [E4 Application Template Source](https://github.com/eclipse-pde/eclipse.pde/tree/master/ui/org.eclipse.pde.ui.templates/templates_3.5/E4Application) + +--- + +*This documentation is part of the Eclipse Platform UI project and evolves with the codebase.* diff --git a/releng/org.eclipse.ui.releng/platformUiTools.p2f b/releng/org.eclipse.ui.releng/platformUiTools.p2f index a3ecbfc3c70..b30822d5be4 100644 --- a/releng/org.eclipse.ui.releng/platformUiTools.p2f +++ b/releng/org.eclipse.ui.releng/platformUiTools.p2f @@ -109,7 +109,7 @@ - + diff --git a/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/workbench/PartRenderingEngineTests.java b/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/workbench/PartRenderingEngineTests.java index a64873b5532..892e40a2c11 100644 --- a/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/workbench/PartRenderingEngineTests.java +++ b/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/workbench/PartRenderingEngineTests.java @@ -71,7 +71,6 @@ import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TestName; import org.junit.rules.TestWatcher; import org.osgi.service.log.LogLevel; import org.osgi.service.log.LogListener; @@ -99,9 +98,6 @@ public class PartRenderingEngineTests { private boolean logged = false; private Consumer runtimeExceptionHandler; - @Rule - public TestName testName = new TestName(); - @Before public void setUp() { logged = false; @@ -2470,12 +2466,13 @@ public void ensureCleanUpAddonCleansUp() { assertTrue(" PartStack with children should be rendered", partStackForPartBPartC.isToBeRendered()); partService.hidePart(partB); partService.hidePart(partC); - DisplayHelper.waitForCondition(Display.getDefault(), 5_000, - () -> partStackForPartBPartC.isToBeRendered() == false); - assertFalse( + // DisplayHelper.waitForCondition() handles event processing via Display.sleep() + // and retries. Calling spinEventLoop() here creates a race condition where + // events may be processed before CleanupAddon's asyncExec() is queued (line 352). + assertTrue( "CleanupAddon should ensure that partStack is not rendered anymore, as all childs have been removed", - partStackForPartBPartC.isToBeRendered()); - assertFalse("Part stack should be removed", partStackForPartBPartC.isToBeRendered()); + DisplayHelper.waitForCondition(Display.getDefault(), 5_000, + () -> !partStackForPartBPartC.isToBeRendered())); // PartStack with IPresentationEngine.NO_AUTO_COLLAPSE should not be removed // even if children are removed partService.hidePart(editor, true); diff --git a/tests/org.eclipse.search.tests/src/org/eclipse/search/tests/filesearch/FileSearchTests.java b/tests/org.eclipse.search.tests/src/org/eclipse/search/tests/filesearch/FileSearchTests.java index 919b50227d1..30234f5da60 100644 --- a/tests/org.eclipse.search.tests/src/org/eclipse/search/tests/filesearch/FileSearchTests.java +++ b/tests/org.eclipse.search.tests/src/org/eclipse/search/tests/filesearch/FileSearchTests.java @@ -35,6 +35,8 @@ import org.eclipse.core.runtime.IContributor; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.content.IContentType; +import org.eclipse.core.runtime.content.IContentTypeManager; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; @@ -601,13 +603,35 @@ private void testBinaryContentTypeWithDescriber(TestResultCollector collector) t .forEach(extension -> registry.removeExtension(extension, masterToken)); }) { - IFolder folder= ResourceHelper.createFolder(fProject.getFolder("folder1")); + // Wait for content type to be registered and available + // This prevents race conditions where the content type might not be immediately available + IContentTypeManager contentTypeManager= Platform.getContentTypeManager(); + IContentType binaryContentType= null; + for (int i= 0; i < 50 && binaryContentType == null; i++) { + binaryContentType= contentTypeManager.getContentType("org.eclipse.search.tests.binaryFile"); + if (binaryContentType == null) { + Thread.sleep(10); // Wait 10ms before retrying + } + } + if (binaryContentType == null) { + throw new AssertionError("Content type 'org.eclipse.search.tests.binaryFile' was not registered"); + } + + // Use unique folder name to avoid conflicts with other tests running in parallel + String uniqueFolderName= "binaryContentTypeTest-" + java.util.UUID.randomUUID().toString(); + IFolder folder= ResourceHelper.createFolder(fProject.getFolder(uniqueFolderName)); IFile textfile= ResourceHelper.createFile(folder, "textfile", "text hello"); IFile binaryfile= ResourceHelper.createFile(folder, "binaryfile", "binary hello"); + // Force content type detection on files to ensure the newly registered content type is applied + // This helps avoid race conditions where the content type might not be immediately available + textfile.getContentDescription(); + binaryfile.getContentDescription(); + Pattern searchPattern= PatternConstructor.createPattern("hello", true, false); - FileTextSearchScope scope= FileTextSearchScope.newSearchScope(new IResource[] { fProject }, (String[]) null, false); + // Search only in the unique folder to avoid interference from other tests + FileTextSearchScope scope= FileTextSearchScope.newSearchScope(new IResource[] { folder }, (String[]) null, false); TextSearchEngine.create().search(scope, collector, searchPattern, null); TestResult[] results= collector.getResults(); diff --git a/tests/org.eclipse.tests.urischeme/src/org/eclipse/urischeme/internal/registration/TestUnitRegistrationWindows.java b/tests/org.eclipse.tests.urischeme/src/org/eclipse/urischeme/internal/registration/TestUnitRegistrationWindows.java index 68b513196f4..5122a21102f 100644 --- a/tests/org.eclipse.tests.urischeme/src/org/eclipse/urischeme/internal/registration/TestUnitRegistrationWindows.java +++ b/tests/org.eclipse.tests.urischeme/src/org/eclipse/urischeme/internal/registration/TestUnitRegistrationWindows.java @@ -26,15 +26,10 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TestName; public class TestUnitRegistrationWindows { - @Rule - public TestName name = new TestName(); - private static final String PATH_TO_OTHER_APPLICATION_EXE = "c:\\path\\to\\otherApplication.exe"; private static final String PATH_TO_ECLIPSE_EXE = "c:\\path\\with spaces\\to\\eclipse\\Eclipse.exe"; private static final String PATH_TO_ECLIPSE_HOME = "c:\\path\\with spaces\\to\\eclipse"; @@ -161,7 +156,6 @@ public void getLauncherPathFromLauncherProperty() throws Exception { @Test public void getLauncherPathFromEclipseHomeProperty() throws Exception { - System.out.println("registrationWindows1: " + registrationWindows); System.clearProperty("eclipse.launcher"); System.setProperty("eclipse.home.location", URL_TO_ECLIPSE_HOME); fileProvider.fileExistsAnswers.put(PATH_TO_ECLIPSE_HOME, true); @@ -169,7 +163,6 @@ public void getLauncherPathFromEclipseHomeProperty() throws Exception { fileProvider.newDirectoryStreamAnswers.computeIfAbsent(PATH_TO_ECLIPSE_HOME, path -> new HashMap<>()) .put("*.exe", Arrays.asList(PATH_TO_ECLIPSE_HOME + "\\Eclipse.exe")); - System.out.println("registrationWindows2: " + registrationWindows); assertEquals(PATH_TO_ECLIPSE_EXE, registrationWindows.getEclipseLauncher()); } diff --git a/tests/org.eclipse.text.quicksearch.tests/src/org/eclipse/text/quicksearch/tests/QuickAccessComputerTest.java b/tests/org.eclipse.text.quicksearch.tests/src/org/eclipse/text/quicksearch/tests/QuickAccessComputerTest.java index 21e0ff1ce08..0212239ba28 100644 --- a/tests/org.eclipse.text.quicksearch.tests/src/org/eclipse/text/quicksearch/tests/QuickAccessComputerTest.java +++ b/tests/org.eclipse.text.quicksearch.tests/src/org/eclipse/text/quicksearch/tests/QuickAccessComputerTest.java @@ -9,7 +9,6 @@ *******************************************************************************/ package org.eclipse.text.quicksearch.tests; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; @@ -55,8 +54,16 @@ void testQuickAccessComputer() throws CoreException, IOException { dialog.setInitialPattern(request); dialog.setBlockOnOpen(false); dialog.open(); - assertTrue(DisplayHelper.waitForCondition(dialog.getShell().getDisplay(), 2000, () -> dialog.getResult().length > 0)); + var display = dialog.getShell().getDisplay(); + assertTrue(DisplayHelper.waitForCondition(display, 2000, () -> dialog.getResult().length > 0)); dialog.close(); - assertEquals(1, new QuickSearchQuickAccessComputer().computeElements(request, new NullProgressMonitor()).length); + + // Wait for the QuickAccessComputer to return results, as the search happens asynchronously. + // Retry the search if it initially returns no results, allowing time for the background + // search job to find matches. This addresses race conditions on slower CI systems. + assertTrue(DisplayHelper.waitForCondition(display, 5000, () -> { + QuickSearchQuickAccessComputer computer = new QuickSearchQuickAccessComputer(); + return computer.computeElements(request, new NullProgressMonitor()).length == 1; + }), "Expected QuickAccessComputer to find exactly one result within timeout"); } } diff --git a/tests/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/HoverTest.java b/tests/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/HoverTest.java index 8bf2aa2fa41..a52be637056 100644 --- a/tests/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/HoverTest.java +++ b/tests/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/HoverTest.java @@ -33,6 +33,7 @@ import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; @@ -80,7 +81,13 @@ public void testEnabledWhenHover(TestInfo info) throws Exception { assertNotNull(findControl(shell, StyledText.class, AlrightyHoverProvider.LABEL)); assertNull(findControl(shell, StyledText.class, WorldHoverProvider.LABEL)); + // Capture the first shell and its display to wait for disposal + Shell firstShell = shell; + Display display = firstShell.getDisplay(); cleanFileAndEditor(); + // Wait for the hover shell to be disposed after editor cleanup + DisplayHelper.waitForCondition(display, 3000, () -> firstShell.isDisposed()); + EnabledPropertyTester.setEnabled(false); createAndOpenFile("enabledWhen.txt", "bar 'bar'"); shell= getHoverShell(info, triggerCompletionAndRetrieveInformationControlManager(), true); diff --git a/tests/org.eclipse.ui.monitoring.tests/META-INF/MANIFEST.MF b/tests/org.eclipse.ui.monitoring.tests/META-INF/MANIFEST.MF index 2d30229ef5d..3c7cc52e1f9 100644 --- a/tests/org.eclipse.ui.monitoring.tests/META-INF/MANIFEST.MF +++ b/tests/org.eclipse.ui.monitoring.tests/META-INF/MANIFEST.MF @@ -2,6 +2,9 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Import-Package: org.junit.jupiter.api;version="[5.14.0,6.0.0)", + org.junit.jupiter.api.extension;version="[5.14.0,6.0.0)", + org.junit.jupiter.api.function;version="[5.14.0,6.0.0)", + org.junit.jupiter.engine;version="[5.14.0,6.0.0)", org.junit.platform.suite.api;version="[1.14.0,2.0.0)" Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SymbolicName: org.eclipse.ui.monitoring.tests;singleton:=true @@ -9,6 +12,5 @@ Bundle-Vendor: %Bundle-Vendor Bundle-Version: 1.3.0.qualifier Fragment-Host: org.eclipse.ui.monitoring;bundle-version="1.0.0" Require-Bundle: org.eclipse.jface;bundle-version="[3.10.0,4.0.0)", - org.eclipse.ui.workbench;bundle-version="[3.106.0,4.0.0)", - org.junit;bundle-version="[4.12.0,5.0.0)" + org.eclipse.ui.workbench;bundle-version="[3.106.0,4.0.0)" Automatic-Module-Name: org.eclipse.ui.monitoring.tests diff --git a/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/DefaultLoggerTests.java b/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/DefaultLoggerTests.java index 917461efd5d..07c7e12ff0f 100644 --- a/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/DefaultLoggerTests.java +++ b/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/DefaultLoggerTests.java @@ -15,8 +15,8 @@ *******************************************************************************/ package org.eclipse.ui.internal.monitoring; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; @@ -30,8 +30,8 @@ import org.eclipse.ui.monitoring.PreferenceConstants; import org.eclipse.ui.monitoring.StackSample; import org.eclipse.ui.monitoring.UiFreezeEvent; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * JUnit test for the {@link DefaultUiFreezeEventLogger}. @@ -45,7 +45,7 @@ public class DefaultLoggerTests { private ThreadInfo thread; private IStatus loggedStatus; - @Before + @BeforeEach public void setUp() { logger = new DefaultUiFreezeEventLogger(DURATION * 10); createLogListener(); @@ -68,30 +68,31 @@ private UiFreezeEvent createFreezeEvent() { } @Test - public void testLogEvent() { - UiFreezeEvent event = createFreezeEvent(); - String expectedTime = dateFormat.format(new Date(TIME).toInstant()); - String expectedHeader = - String.format("UI freeze of %.2gs at %s", DURATION / 1000.0, expectedTime); - String expectedEventMessage = String.format("Sample at %s (+%.3fs)", expectedTime, 0.000); + void testLogEvent() { + UiFreezeEvent event = createFreezeEvent(); + String expectedTime = dateFormat.format(new Date(TIME).toInstant()); + String expectedHeader = + String.format("UI freeze of %.2gs at %s", DURATION / 1000.0, expectedTime); + String expectedEventMessage = String.format("Sample at %s (+%.3fs)", expectedTime, 0.000); - logger.log(event); + logger.log(event); - assertEquals(PreferenceConstants.PLUGIN_ID, loggedStatus.getPlugin()); - assertTrue("Logged status was not a MultiStatus", loggedStatus.isMultiStatus()); - assertEquals(expectedHeader, loggedStatus.getMessage()); - assertEquals("One nested IStatus did not get logged correctly.", 1, - loggedStatus.getChildren().length); + assertEquals(PreferenceConstants.PLUGIN_ID, loggedStatus.getPlugin()); + assertTrue(loggedStatus.isMultiStatus(), "Logged status was not a MultiStatus"); + assertEquals(expectedHeader, loggedStatus.getMessage()); + assertEquals(1, loggedStatus.getChildren().length, + "One nested IStatus did not get logged correctly."); - IStatus freezeEvent = loggedStatus.getChildren()[0]; - assertTrue(freezeEvent.getMessage().contains(expectedEventMessage)); + IStatus freezeEvent = loggedStatus.getChildren()[0]; + assertTrue(freezeEvent.getMessage().contains(expectedEventMessage)); - StackTraceElement[] threadStackTrace = thread.getStackTrace(); - StackTraceElement[] loggedStackTrace = freezeEvent.getException().getStackTrace(); - assertEquals(threadStackTrace.length, loggedStackTrace.length); + StackTraceElement[] threadStackTrace = thread.getStackTrace(); + StackTraceElement[] loggedStackTrace = freezeEvent.getException().getStackTrace(); + assertEquals(threadStackTrace.length, loggedStackTrace.length); - for (int i = 0; i < threadStackTrace.length; i++) { - assertEquals(threadStackTrace[i], loggedStackTrace[i]); - } + for (int i = 0; i < threadStackTrace.length; i++) { + assertEquals(threadStackTrace[i], loggedStackTrace[i]); + } } + } diff --git a/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/EventLoopMonitorThreadManualTests.java b/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/EventLoopMonitorThreadManualTests.java index 85e005e8084..e75b947c5fb 100644 --- a/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/EventLoopMonitorThreadManualTests.java +++ b/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/EventLoopMonitorThreadManualTests.java @@ -17,9 +17,10 @@ *******************************************************************************/ package org.eclipse.ui.internal.monitoring; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.management.ManagementFactory; import java.lang.management.ThreadMXBean; @@ -35,9 +36,9 @@ import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.monitoring.PreferenceConstants; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * A test that measures performance overhead of {@link EventLoopMonitorThread}. @@ -111,12 +112,12 @@ public class EventLoopMonitorThreadManualTests { */ protected static final long PN63_GENERATOR_POLY = (3L << 62) | 1; - @Before + @BeforeEach public void setUp() { MonitoringPlugin.getPreferenceStore().setValue(PreferenceConstants.MONITORING_ENABLED, false); } - @After + @AfterEach public void tearDown() { MonitoringPlugin.getPreferenceStore().setToDefault(PreferenceConstants.MONITORING_ENABLED); } @@ -163,7 +164,7 @@ protected static long doWork(long pnSeqeuence, long iterations) { @Test public void testFixedWork() throws Exception{ final Display display = Display.getDefault(); - assertNotNull("No SWT Display available.", display); + assertNotNull(display, "No SWT Display available."); final MockUiFreezeEventLogger logger = new MockUiFreezeEventLogger(); final CountDownLatch backgroundJobsDone = new CountDownLatch(1); @@ -246,13 +247,18 @@ public void testFixedWork() throws Exception{ maxRelativeIncreaseOneStackAllowed * 100)); } assertTrue( - String.format(""" - Relative overhead of monitoring surpassed threshold for - measurement %d of %d. It took %.3fs with a relative increase of %.3f%% - (allowed < %.3f%%).""", - i, NUM_UI_STACK_MEASUREMENTS, tWork[0] / 1e9, relativeDiffOneThread * 100, - maxRelativeIncreaseOneStackAllowed * 100), - relativeDiffOneThread <= maxRelativeIncreaseOneStackAllowed); + relativeDiffOneThread <= maxRelativeIncreaseOneStackAllowed, + String.format(""" + Relative overhead of monitoring surpassed threshold for \ + measurement %d of %d. It took %.3fs with a relative increase of %.3f%% \ + (allowed < %.3f%%).""", + i, + NUM_UI_STACK_MEASUREMENTS, + tWork[0] / 1e9, + relativeDiffOneThread * 100, + maxRelativeIncreaseOneStackAllowed * 100) + ); + } killMonitorThread(monitor1, display); @@ -277,13 +283,19 @@ public void testFixedWork() throws Exception{ i, NUM_ALL_STACKS_MEASUREMENTS, tWork[0] / 1e9, relativeDiffAllThreads * 100, maxRelativeIncreaseAllStacksAllowed * 100)); } - assertTrue(String.format(""" - Relative overhead of monitoring with stack traces of all threads - surpassed threshold for measurement %d of %d. It took %.3fs with a relative - increase of %.3f%% (allowed < %.3f%%).""", - i, NUM_ALL_STACKS_MEASUREMENTS, tWork[0] / 1e9, relativeDiffAllThreads * 100, - maxRelativeIncreaseAllStacksAllowed * 100), - relativeDiffAllThreads <= maxRelativeIncreaseAllStacksAllowed); + assertTrue( + relativeDiffAllThreads <= maxRelativeIncreaseAllStacksAllowed, + String.format(""" + Relative overhead of monitoring with stack traces of all threads \ + surpassed threshold for measurement %d of %d. It took %.3fs with a relative \ + increase of %.3f%% (allowed < %.3f%%).""", + i, + NUM_ALL_STACKS_MEASUREMENTS, + tWork[0] / 1e9, + relativeDiffAllThreads * 100, + maxRelativeIncreaseAllStacksAllowed * 100) + ); + } killMonitorThread(monitor2, display); @@ -376,22 +388,30 @@ public void testFixedWork() throws Exception{ threads.offer(t); // Retry. } } - - assertEquals("Did not log expected number of freeze events,", + assertEquals( NUM_UI_STACK_MEASUREMENTS + NUM_ALL_STACKS_MEASUREMENTS, - logger.getLoggedEvents().size()); - assertTrue(String.format(""" - Relative overhead of monitoring with stack traces of the UI - thread was %.3f%% (allowed < %.3f%%).""", - worstRelativeDiffOneThread * 100, - maxRelativeIncreaseOneStackAllowed * 100), - worstRelativeDiffOneThread <= maxRelativeIncreaseOneStackAllowed); - assertTrue(String.format(""" - Relative overhead of monitoring with stack traces of all - threads was %.3f%% (allowed < %.3f%%).""", - worstRelativeDiffAllThreads * 100, - maxRelativeIncreaseAllStacksAllowed * 100), - worstRelativeDiffAllThreads <= maxRelativeIncreaseAllStacksAllowed); + logger.getLoggedEvents().size(), + "Did not log expected number of freeze events." + ); + + assertTrue( + worstRelativeDiffOneThread <= maxRelativeIncreaseOneStackAllowed, + String.format(""" + Relative overhead of monitoring with stack traces of the UI \ + thread was %.3f%% (allowed < %.3f%%).""", + worstRelativeDiffOneThread * 100, + maxRelativeIncreaseOneStackAllowed * 100) + ); + + assertTrue( + worstRelativeDiffAllThreads <= maxRelativeIncreaseAllStacksAllowed, + String.format(""" + Relative overhead of monitoring with stack traces of all \ + threads was %.3f%% (allowed < %.3f%%).""", + worstRelativeDiffAllThreads * 100, + maxRelativeIncreaseAllStacksAllowed * 100) + ); + } private Thread createAndStartMonitoringThread(Display display, boolean dumpAll) throws Exception { diff --git a/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/EventLoopMonitorThreadTests.java b/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/EventLoopMonitorThreadTests.java index 63e012f4b71..eb2a0a0e6d2 100644 --- a/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/EventLoopMonitorThreadTests.java +++ b/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/EventLoopMonitorThreadTests.java @@ -17,9 +17,10 @@ *******************************************************************************/ package org.eclipse.ui.internal.monitoring; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; @@ -29,9 +30,9 @@ import org.eclipse.ui.monitoring.PreferenceConstants; import org.eclipse.ui.monitoring.StackSample; import org.eclipse.ui.monitoring.UiFreezeEvent; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * Tests for {@link EventLoopMonitorThread} class. @@ -89,7 +90,7 @@ protected void sleepForMillis(long nanoseconds) { private static ThreadControl monitorThreadControl; private static long timestamp; - @Before + @BeforeEach public void setUp() { MonitoringPlugin.getPreferenceStore().setValue(PreferenceConstants.MONITORING_ENABLED, false); logger = new MockUiFreezeEventLogger(); @@ -98,7 +99,7 @@ public void setUp() { timestamp = 1; } - @After + @AfterEach public void tearDown() throws Exception { if (monitoringThread != null) { shutdownMonitoringThread(); @@ -210,9 +211,9 @@ public void testStackDecimation() throws Exception { runForCycles(3); UiFreezeEvent event = loggedEvents.get(0); - assertNotNull("A freeze event was not automatically published", event); - assertEquals("Decimation did not resize the stack trace array properly", MIN_STACK_TRACES, - event.getStackTraceSamples().length); + assertNotNull(event, "A freeze event was not automatically published"); + assertEquals(MIN_STACK_TRACES, + event.getStackTraceSamples().length, "Decimation did not resize the stack trace array properly"); // Decimation slows down the sampling rate by a factor of 2, so test the resampling reduction. eventLength = MAX_STACK_TRACES + (MIN_MAX_STACK_TRACE_DELTA - 1) * 2; @@ -222,9 +223,9 @@ public void testStackDecimation() throws Exception { runForCycles(3); event = loggedEvents.get(1); - assertNotNull("A freeze event was not automatically published", event); - assertEquals("Decimation did not reset the sampiling rate properly", MIN_STACK_TRACES, - event.getStackTraceSamples().length); + assertNotNull(event, "A freeze event was not automatically published"); + assertEquals(MIN_STACK_TRACES, + event.getStackTraceSamples().length, "Decimation did not reset the sampiling rate properly"); // Test the resampling reduction after two decimations. eventLength = @@ -235,9 +236,9 @@ public void testStackDecimation() throws Exception { runForCycles(3); event = loggedEvents.get(2); - assertNotNull("A freeze event was not automatically published", event); - assertEquals("Decimation did not reset the sampiling rate properly", MIN_STACK_TRACES, - event.getStackTraceSamples().length); + assertNotNull(event, "A freeze event was not automatically published"); + assertEquals(MIN_STACK_TRACES, + event.getStackTraceSamples().length, "Decimation did not reset the sampiling rate properly"); } @Test @@ -260,21 +261,21 @@ public void testPublishPossibleDeadlock() throws Exception { long remaining = maxDeadlock - (timestamp - startTime); runForTime(remaining - 1); - assertTrue("No deadlock should get logged before its time", loggedEvents.isEmpty()); + assertTrue(loggedEvents.isEmpty(), "No deadlock should get logged before its time"); // March time forward to trigger the possible deadlock logging. runForCycles(4); - assertEquals("Incorrect number of events was logged", 1, loggedEvents.size()); + assertEquals(1, loggedEvents.size(), "Incorrect number of events was logged"); UiFreezeEvent event = loggedEvents.get(0); - assertTrue("Possible deadlock logging should have a valid number of stack traces", - event.getStackTraceSamples().length >= MIN_STACK_TRACES); + assertTrue(event.getStackTraceSamples().length >= MIN_STACK_TRACES, + "Possible deadlock logging should have a valid number of stack traces"); // Extending the UI freeze shouldn't log any more events. runForTime(maxDeadlock * 2); runForCycles(3); - assertEquals("No more deadlock events should get logged", 1, loggedEvents.size()); + assertEquals(1, loggedEvents.size(), "No more deadlock events should get logged"); } @Test @@ -295,7 +296,7 @@ public void testPublishNoDeadlocksWhenSleeping() throws Exception { runForTime(FORCE_DEADLOCK_LOG_TIME_MS * 2); runForCycles(3); - assertTrue("No deadlock events should get logged", loggedEvents.isEmpty()); + assertTrue(loggedEvents.isEmpty(), "No deadlock events should get logged"); } @Test @@ -310,7 +311,7 @@ public void testNoLoggingForSleep() throws Exception { sendEvent(SWT.PostExternalEventDispatch); runForCycles(3); - assertTrue("Sleeping should not trigger a freeze event", loggedEvents.isEmpty()); + assertTrue(loggedEvents.isEmpty(), "Sleeping should not trigger a freeze event"); } @Test @@ -329,15 +330,15 @@ public void testEventLogging() throws Exception { sendEvent(SWT.PostEvent); runForCycles(3); - assertEquals("Incorrect number of freeze events was logged", 1, loggedEvents.size()); + assertEquals(1, loggedEvents.size(), "Incorrect number of freeze events was logged"); UiFreezeEvent event = loggedEvents.get(0); - assertEquals("A freeze event log has an incorrect start time", eventStartTime, - event.getStartTimestamp()); - assertEquals("A freeze event's duration was incorrect", freezeDuration, - event.getTotalDuration()); - assertEquals("A freeze event didn't capture a good range of stack samples (" - + getStackSamplesTimeline(event) + ")", - expectedStackCount(freezeDuration), event.getStackTraceSamples().length); + assertEquals(eventStartTime, + event.getStartTimestamp(), "A freeze event log has an incorrect start time"); + assertEquals(freezeDuration, + event.getTotalDuration(), "A freeze event's duration was incorrect"); + assertEquals(expectedStackCount(freezeDuration), event.getStackTraceSamples().length, + "A freeze event didn't capture a good range of stack samples (" + + getStackSamplesTimeline(event) + ")"); } @Test @@ -359,15 +360,15 @@ public void testNestedEventLogging() throws Exception { sendEvent(SWT.PostEvent); runForCycles(3); - assertEquals("Incorrect number of freeze events was logged", 1, loggedEvents.size()); + assertEquals(1, loggedEvents.size(), "Incorrect number of freeze events was logged"); UiFreezeEvent event = loggedEvents.get(0); - assertEquals("A freeze event log has an incorrect start time", eventStartTime, - event.getStartTimestamp()); - assertEquals("A freeze event's duration was incorrect", freezeDuration, - event.getTotalDuration()); - assertEquals("A freeze event didn't capture a good range of stack samples (" - + getStackSamplesTimeline(event) + ")", - expectedStackCount(freezeDuration), event.getStackTraceSamples().length); + assertEquals(eventStartTime, + event.getStartTimestamp(), "A freeze event log has an incorrect start time"); + assertEquals(freezeDuration, + event.getTotalDuration(), "A freeze event's duration was incorrect"); + assertEquals(expectedStackCount(freezeDuration), event.getStackTraceSamples().length, + "A freeze event didn't capture a good range of stack samples (" + + getStackSamplesTimeline(event) + ")"); } @Test @@ -392,15 +393,15 @@ public void testDoublyNestedEventLogging() throws Exception { sendEvent(SWT.PostEvent); runForCycles(3); - assertEquals("Incorrect number of freeze events was logged", 1, loggedEvents.size()); + assertEquals(1, loggedEvents.size(), "Incorrect number of freeze events was logged"); UiFreezeEvent event = loggedEvents.get(0); - assertEquals("A freeze event log has an incorrect start time", eventStartTime, - event.getStartTimestamp()); - assertEquals("A freeze event's duration was incorrect", freezeDuration, - event.getTotalDuration()); - assertEquals("A freeze event didn't capture a good range of stack samples (" - + getStackSamplesTimeline(event) + ")", - expectedStackCount(freezeDuration), event.getStackTraceSamples().length); + assertEquals(eventStartTime, + event.getStartTimestamp(), "A freeze event log has an incorrect start time"); + assertEquals(freezeDuration, + event.getTotalDuration(), "A freeze event's duration was incorrect"); + assertEquals(expectedStackCount(freezeDuration), event.getStackTraceSamples().length, + "A freeze event didn't capture a good range of stack samples (" + + getStackSamplesTimeline(event) + ")"); } @Test @@ -427,15 +428,15 @@ public void testSeeLongEventInContinuationAfterNestedCall() throws Exception { freezeDuration = timestamp - eventResumeTime; runForCycles(3); - assertEquals("Incorrect number of freeze events was logged", 1, loggedEvents.size()); + assertEquals(1, loggedEvents.size(), "Incorrect number of freeze events was logged"); UiFreezeEvent event = loggedEvents.get(0); - assertEquals("A freeze event didn't start from the nested return point", - eventResumeTime, event.getStartTimestamp()); - assertEquals("A freeze event's duration was incorrect", freezeDuration, - event.getTotalDuration()); - assertEquals("A freeze event didn't capture a good range of stack samples (" - + getStackSamplesTimeline(event) + ")", - expectedStackCount(freezeDuration), event.getStackTraceSamples().length); + assertEquals(eventResumeTime, event.getStartTimestamp(), + "A freeze event didn't start from the nested return point"); + assertEquals(freezeDuration, + event.getTotalDuration(), "A freeze event's duration was incorrect"); + assertEquals(expectedStackCount(freezeDuration), event.getStackTraceSamples().length, + "A freeze event didn't capture a good range of stack samples (" + + getStackSamplesTimeline(event) + ")"); } @Test @@ -471,15 +472,15 @@ public void testSeeLongEventInTheMiddleOfNestedCalls() throws Exception { sendEvent(SWT.PostEvent); runForCycles(3); - assertEquals("Incorrect number of freeze events was logged", 1, loggedEvents.size()); + assertEquals(1, loggedEvents.size(), "Incorrect number of freeze events was logged"); UiFreezeEvent event = loggedEvents.get(0); - assertEquals("A freeze event didn't start from the nested return point", - eventResumeTime, event.getStartTimestamp()); - assertEquals("A freeze event's duration was incorrect", freezeDuration, - event.getTotalDuration()); - assertEquals("A freeze event didn't capture a good range of stack samples (" - + getStackSamplesTimeline(event) + ")", - expectedStackCount(freezeDuration), event.getStackTraceSamples().length); + assertEquals(eventResumeTime, event.getStartTimestamp(), + "A freeze event didn't start from the nested return point"); + assertEquals(freezeDuration, + event.getTotalDuration(), "A freeze event's duration was incorrect"); + assertEquals(expectedStackCount(freezeDuration), event.getStackTraceSamples().length, + "A freeze event didn't capture a good range of stack samples (" + + getStackSamplesTimeline(event) + ")"); } @Test @@ -514,8 +515,8 @@ public void testSeeSleepInTheMiddleOfNestedCalls() throws Exception { sendEvent(SWT.PostEvent); runForCycles(3); - assertTrue("A freeze event should not be published during an external event dispatch", - loggedEvents.isEmpty()); + assertTrue(loggedEvents.isEmpty(), + "A freeze event should not be published during an external event dispatch"); } @Test @@ -533,8 +534,8 @@ public void testConsecutiveSleeps() throws Exception { eventStartTime = timestamp; runForCycles(3); - assertTrue("A freeze event shold not be published during an external event dispatch", - loggedEvents.isEmpty()); + assertTrue(loggedEvents.isEmpty(), + "A freeze event shold not be published during an external event dispatch"); // Let a long time elapse between the last PostExternalEventDispatch and the next // PreExternalEventDispatch. @@ -545,11 +546,11 @@ public void testConsecutiveSleeps() throws Exception { sendEvent(SWT.PostEvent); runForCycles(3); - assertEquals("Incorrect number of freeze events was logged", 1, loggedEvents.size()); + assertEquals(1, loggedEvents.size(), "Incorrect number of freeze events was logged"); UiFreezeEvent event = loggedEvents.get(0); - assertEquals("A freeze event log has an incorrect start time", eventStartTime, - event.getStartTimestamp()); - assertEquals("A freeze event's duration is incorrect", eventDuration, - event.getTotalDuration()); + assertEquals(eventStartTime, + event.getStartTimestamp(), "A freeze event log has an incorrect start time"); + assertEquals(eventDuration, + event.getTotalDuration(), "A freeze event's duration is incorrect"); } } diff --git a/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/FilterHandlerTests.java b/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/FilterHandlerTests.java index 2e7ce025c2a..75c7560b1a5 100644 --- a/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/FilterHandlerTests.java +++ b/tests/org.eclipse.ui.monitoring.tests/src/org/eclipse/ui/internal/monitoring/FilterHandlerTests.java @@ -16,15 +16,16 @@ *******************************************************************************/ package org.eclipse.ui.internal.monitoring; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import org.eclipse.ui.monitoring.StackSample; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * Tests for {@link FilterHandler} class. diff --git a/tests/org.eclipse.ui.tests.harness/META-INF/MANIFEST.MF b/tests/org.eclipse.ui.tests.harness/META-INF/MANIFEST.MF index 259fee3e993..8cdb2f2c5fb 100644 --- a/tests/org.eclipse.ui.tests.harness/META-INF/MANIFEST.MF +++ b/tests/org.eclipse.ui.tests.harness/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Harness Plug-in Bundle-SymbolicName: org.eclipse.ui.tests.harness;singleton:=true -Bundle-Version: 1.10.600.qualifier +Bundle-Version: 1.10.700.qualifier Eclipse-BundleShape: dir Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, diff --git a/tests/org.eclipse.ui.tests.harness/src/org/eclipse/ui/tests/harness/util/RCPTestWorkbenchAdvisor.java b/tests/org.eclipse.ui.tests.harness/src/org/eclipse/ui/tests/harness/util/RCPTestWorkbenchAdvisor.java index 670ed8276af..5f5f19feeca 100644 --- a/tests/org.eclipse.ui.tests.harness/src/org/eclipse/ui/tests/harness/util/RCPTestWorkbenchAdvisor.java +++ b/tests/org.eclipse.ui.tests.harness/src/org/eclipse/ui/tests/harness/util/RCPTestWorkbenchAdvisor.java @@ -13,6 +13,9 @@ *******************************************************************************/ package org.eclipse.ui.tests.harness.util; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.SWTException; import org.eclipse.swt.widgets.Display; @@ -44,6 +47,10 @@ public class RCPTestWorkbenchAdvisor extends WorkbenchAdvisor { private static boolean started = false; + // CountDownLatch to wait for async/sync operations with DisplayAccess to complete + // We need to wait for 2 operations: asyncWithDisplayAccess and syncWithDisplayAccess + private static CountDownLatch displayAccessLatch = null; + public static boolean isSTARTED() { synchronized (RCPTestWorkbenchAdvisor.class) { return started; @@ -122,12 +129,13 @@ public void eventLoopIdle(final Display display) { public void preStartup() { super.preStartup(); final Display display = Display.getCurrent(); + + // Initialize the latch to wait for 2 operations with DisplayAccess + displayAccessLatch = new CountDownLatch(2); + if (display != null) { display.asyncExec(() -> { - if (isSTARTED()) - asyncDuringStartup = Boolean.FALSE; - else - asyncDuringStartup = Boolean.TRUE; + asyncDuringStartup = !isSTARTED(); }); } @@ -158,17 +166,23 @@ public void run() { DisplayAccess.accessDisplayDuringStartup(); try { display.syncExec(() -> { - synchronized (RCPTestWorkbenchAdvisor.class) { - if (callDisplayAccess) - syncWithDisplayAccess = !isSTARTED() ? Boolean.TRUE : Boolean.FALSE; - else - syncWithoutDisplayAccess = !isSTARTED() ? Boolean.TRUE : Boolean.FALSE; + if (callDisplayAccess) { + syncWithDisplayAccess = !isSTARTED(); + // Count down after the runnable executes + if (displayAccessLatch != null) { + displayAccessLatch.countDown(); + } + } else { + syncWithoutDisplayAccess = !isSTARTED(); } }); } catch (SWTException e) { // this can happen because we shut down the workbench just // as soon as we're initialized - ie: when we're trying to // run this runnable in the deferred case. + if (callDisplayAccess && displayAccessLatch != null) { + displayAccessLatch.countDown(); + } } } }; @@ -183,11 +197,14 @@ public void run() { if (callDisplayAccess) DisplayAccess.accessDisplayDuringStartup(); display.asyncExec(() -> { - synchronized (RCPTestWorkbenchAdvisor.class) { - if (callDisplayAccess) - asyncWithDisplayAccess = !isSTARTED() ? Boolean.TRUE : Boolean.FALSE; - else - asyncWithoutDisplayAccess = !isSTARTED() ? Boolean.TRUE : Boolean.FALSE; + if (callDisplayAccess) { + asyncWithDisplayAccess = !isSTARTED(); + // Count down after the runnable executes + if (displayAccessLatch != null) { + displayAccessLatch.countDown(); + } + } else { + asyncWithoutDisplayAccess = !isSTARTED(); } }); } @@ -199,6 +216,24 @@ public void run() { @Override public void postStartup() { super.postStartup(); + + // Wait for async/sync operations with DisplayAccess to complete execution + if (displayAccessLatch != null) { + try { + // Wait up to 5 seconds for operations with DisplayAccess to complete + // This ensures they execute BEFORE we mark started = true + boolean completed = displayAccessLatch.await(5, TimeUnit.SECONDS); + if (!completed) { + System.err.println("WARNING: Timeout waiting for async/sync operations with DisplayAccess"); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + System.err.println("WARNING: Interrupted while waiting for async/sync operations"); + } + } + + // Now mark as started - operations with DisplayAccess should have completed + // Operations without DisplayAccess should still be pending (deferred) synchronized (RCPTestWorkbenchAdvisor.class) { started = true; } diff --git a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/FirstClassM1Tests.java b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/FirstClassM1Tests.java index f75c295a267..4fc07e41da6 100644 --- a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/FirstClassM1Tests.java +++ b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/FirstClassM1Tests.java @@ -15,7 +15,7 @@ package org.eclipse.ui.tests.navigator; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.tests.navigator.m12.model.M1Project; @@ -51,13 +51,13 @@ public void testM1ProjectHasChildren() throws Exception { TreeItem[] rootItems = _viewer.getTree().getItems(); TreeItem p1Item = rootItems[_p1Ind]; - assertEquals("P1 tree item should be an M1Project", M1Project.class, - p1Item.getData().getClass()); + assertEquals(M1Project.class, p1Item.getData().getClass(), + "P1 tree item should be an M1Project"); _expand(rootItems); TreeItem[] p1Children = p1Item.getItems(); - assertEquals("Project should have 3 children", 3, p1Children.length); + assertEquals(3, p1Children.length, "Project should have 3 children"); } diff --git a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/GoBackForwardsTest.java b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/GoBackForwardsTest.java index 3b8dfaff2ef..10eea8ff7e5 100644 --- a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/GoBackForwardsTest.java +++ b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/GoBackForwardsTest.java @@ -15,20 +15,26 @@ import static org.eclipse.ui.tests.harness.util.UITestUtil.processEvents; import static org.eclipse.ui.tests.harness.util.UITestUtil.processEventsUntil; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; +import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.INavigationLocation; +import org.eclipse.ui.IWindowListener; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; @@ -36,16 +42,14 @@ import org.eclipse.ui.internal.NavigationHistoryAction; import org.eclipse.ui.intro.IIntroPart; import org.eclipse.ui.part.FileEditorInput; -import org.eclipse.ui.tests.harness.util.CloseTestWindowsRule; import org.eclipse.ui.tests.harness.util.EditorTestHelper; import org.eclipse.ui.tests.harness.util.FileUtil; import org.eclipse.ui.tests.harness.util.UITestUtil.Condition; import org.eclipse.ui.texteditor.AbstractTextEditor; import org.eclipse.ui.texteditor.TextSelectionNavigationLocation; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @since 3.3 @@ -64,19 +68,84 @@ public class GoBackForwardsTest { private IProject project; private IFile file; + private final List testWindows = new ArrayList<>(); + private IWindowListener windowListener; + private Set initialShells; - @Rule - public final CloseTestWindowsRule closeTestWindows = new CloseTestWindowsRule(); - - @Before + @BeforeEach public void setUp() throws CoreException, IOException { + addWindowListener(); + storeInitialShells(); + project = FileUtil.createProject(PROJECT_NAME); file = FileUtil.createFile(FILE_NAME, project); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(FILE_CONTENTS); Files.writeString(Paths.get(file.getLocation().toOSString()), stringBuilder); project.refreshLocal(IResource.DEPTH_INFINITE, null); + } + + @AfterEach + public void tearDown() { + removeWindowListener(); + processEvents(); + closeAllTestWindows(); + processEvents(); + checkForLeakedShells(); + } + private void addWindowListener() { + windowListener = new IWindowListener() { + @Override + public void windowActivated(IWorkbenchWindow window) { + } + + @Override + public void windowDeactivated(IWorkbenchWindow window) { + } + + @Override + public void windowClosed(IWorkbenchWindow window) { + testWindows.remove(window); + } + + @Override + public void windowOpened(IWorkbenchWindow window) { + testWindows.add(window); + } + }; + PlatformUI.getWorkbench().addWindowListener(windowListener); + } + + private void removeWindowListener() { + if (windowListener != null) { + PlatformUI.getWorkbench().removeWindowListener(windowListener); + } + } + + private void closeAllTestWindows() { + List testWindowsCopy = new ArrayList<>(testWindows); + for (IWorkbenchWindow testWindow : testWindowsCopy) { + testWindow.close(); + } + testWindows.clear(); + } + + private void storeInitialShells() { + this.initialShells = Set.of(PlatformUI.getWorkbench().getDisplay().getShells()); + } + + private void checkForLeakedShells() { + List leakedModalShellTitles = new ArrayList<>(); + Shell[] shells = PlatformUI.getWorkbench().getDisplay().getShells(); + for (Shell shell : shells) { + if (!shell.isDisposed() && !initialShells.contains(shell)) { + leakedModalShellTitles.add(shell.getText()); + shell.close(); + } + } + assertEquals(0, leakedModalShellTitles.size(), + "Test leaked modal shell: [" + String.join(", ", leakedModalShellTitles) + "]"); } @Test @@ -95,79 +164,75 @@ public void testNavigationHistoryNavigation() throws PartInitException { openGenericEditor(editorInput); - assertTrue("Timeout during navigation." + getStateDetails(), - processEventsUntil(genericEditorNoSelection, 1000)); + assertTrue(processEventsUntil(genericEditorNoSelection, 1000), + "Timeout during navigation." + getStateDetails()); selectInGenericEditor(editorInput); - assertTrue("Timeout during navigation." + getStateDetails(), - processEventsUntil(genericEditorSelection, 1000)); + assertTrue(processEventsUntil(genericEditorSelection, 1000), + "Timeout during navigation." + getStateDetails()); openTextEditor(editorInput); - assertTrue("Timeout during navigation." + getStateDetails(), - processEventsUntil(textEditorNoSelection, 1000)); + assertTrue(processEventsUntil(textEditorNoSelection, 1000), + "Timeout during navigation." + getStateDetails()); selectInTextEditor(editorInput); - assertTrue("Timeout during navigation." + getStateDetails(), - processEventsUntil(textEditorSelection, 1000)); + assertTrue(processEventsUntil(textEditorSelection, 1000), + "Timeout during navigation." + getStateDetails()); openGenericEditor(editorInput); - assertTrue("Timeout during navigation." + getStateDetails(), - processEventsUntil(genericEditorSelection, 1000)); + assertTrue(processEventsUntil(genericEditorSelection, 1000), + "Timeout during navigation." + getStateDetails()); openTextEditor(editorInput); - assertTrue("Timeout during navigation." + getStateDetails(), - processEventsUntil(textEditorSelection, 1000)); + assertTrue(processEventsUntil(textEditorSelection, 1000), + "Timeout during navigation." + getStateDetails()); // Navigate backward from text editor to editor goBackward(EditorTestHelper.getActiveWorkbenchWindow(), genericEditorSelection); - Assert.assertEquals( - "Failed to correctly navigate backward from text editor to java editor." + getStateDetails(), - GENERIC_EDITOR_ID, getActiveEditorId()); + assertEquals(GENERIC_EDITOR_ID, getActiveEditorId(), + "Failed to correctly navigate backward from text editor to java editor." + getStateDetails()); // Navigate backward from java editor to text editor goBackward(EditorTestHelper.getActiveWorkbenchWindow(), textEditorSelection); - Assert.assertEquals( - "Failed to correctly navigate backward from java editor to test editor." + getStateDetails(), - TEXT_EDITOR_ID, getActiveEditorId()); + assertEquals(TEXT_EDITOR_ID, getActiveEditorId(), + "Failed to correctly navigate backward from java editor to test editor." + getStateDetails()); // Navigate backward from text editor to text editor goBackward(EditorTestHelper.getActiveWorkbenchWindow(), textEditorNoSelection); - Assert.assertEquals( - "Failed to correctly navigate backward from text editor to text editor." + getStateDetails(), - TEXT_EDITOR_ID, getActiveEditorId()); + assertEquals(TEXT_EDITOR_ID, getActiveEditorId(), + "Failed to correctly navigate backward from text editor to text editor." + getStateDetails()); // Navigate backward from java editor to java editor goBackward(EditorTestHelper.getActiveWorkbenchWindow(), genericEditorSelection); goBackward(EditorTestHelper.getActiveWorkbenchWindow(), genericEditorNoSelection); - Assert.assertEquals( - "Failed to correctly navigate backward from java editor to java editor." + getStateDetails(), - GENERIC_EDITOR_ID, getActiveEditorId()); + assertEquals(GENERIC_EDITOR_ID, getActiveEditorId(), + "Failed to correctly navigate backward from java editor to java editor." + getStateDetails()); // Navigate forward from java editor to java editor goForward(EditorTestHelper.getActiveWorkbenchWindow(), genericEditorSelection); - Assert.assertEquals("Failed to correctly navigate forward from java editor to java editor." + getStateDetails(), - GENERIC_EDITOR_ID, getActiveEditorId()); + assertEquals(GENERIC_EDITOR_ID, getActiveEditorId(), + "Failed to correctly navigate forward from java editor to java editor." + getStateDetails()); // Navigate forward from text editor to text editor goForward(EditorTestHelper.getActiveWorkbenchWindow(), textEditorNoSelection); goForward(EditorTestHelper.getActiveWorkbenchWindow(), textEditorSelection); - Assert.assertEquals("Failed to correctly navigate forward from java editor to java editor." + getStateDetails(), - TEXT_EDITOR_ID, getActiveEditorId()); + assertEquals(TEXT_EDITOR_ID, getActiveEditorId(), + "Failed to correctly navigate forward from java editor to java editor." + getStateDetails()); // Navigate forward from text editor to java editor goForward(EditorTestHelper.getActiveWorkbenchWindow(), genericEditorSelection); - Assert.assertEquals("Failed to correctly navigate forward from text editor to java editor." + getStateDetails(), - GENERIC_EDITOR_ID, getActiveEditorId()); + assertEquals(GENERIC_EDITOR_ID, getActiveEditorId(), + "Failed to correctly navigate forward from text editor to java editor." + getStateDetails()); // Navigate forward from java editor to text editor goForward(EditorTestHelper.getActiveWorkbenchWindow(), textEditorSelection); - Assert.assertEquals("Failed to correctly navigate forward from java editor to text editor." + getStateDetails(), - TEXT_EDITOR_ID, getActiveEditorId()); + assertEquals(TEXT_EDITOR_ID, getActiveEditorId(), + "Failed to correctly navigate forward from java editor to text editor." + getStateDetails()); } private Condition currentNavigationHistoryLocationCondition(String editorId, boolean selection) { @@ -207,13 +272,13 @@ private void openTextEditor(IEditorInput editorInput) throws PartInitException { private void goForward(IWorkbenchWindow window, Condition condition) { NavigationHistoryAction action = new NavigationHistoryAction(window, true); action.run(); - assertTrue("Timeout during navigation.", processEventsUntil(condition, 1000)); + assertTrue(processEventsUntil(condition, 1000), "Timeout during navigation."); } private void goBackward(IWorkbenchWindow window, Condition condition) { NavigationHistoryAction action = new NavigationHistoryAction(window, false); action.run(); - assertTrue("Timeout during navigation.", processEventsUntil(condition, 1000)); + assertTrue(processEventsUntil(condition, 1000), "Timeout during navigation."); } private String getActiveEditorId() { diff --git a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/INavigatorContentServiceTests.java b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/INavigatorContentServiceTests.java index 01d98649c18..5a2b5efb856 100644 --- a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/INavigatorContentServiceTests.java +++ b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/INavigatorContentServiceTests.java @@ -14,9 +14,9 @@ *******************************************************************************/ package org.eclipse.ui.tests.navigator; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.util.Iterator; import java.util.Set; @@ -60,14 +60,14 @@ public void testFindValidExtensions() { .findRootContentProviders(ResourcesPlugin.getWorkspace() .getRoot()); - assertEquals("Ensure there is only one root content provider.", 1, - rootContentProviders.length); + assertEquals(1, rootContentProviders.length, + "Ensure there is only one root content provider."); Set projectContentExtensions = _contentService .findContentExtensionsByTriggerPoint(_project); - assertEquals("Ensure there are two content providers for an IProject.", - 2, projectContentExtensions.size()); + assertEquals(2, projectContentExtensions.size(), + "Ensure there are two content providers for an IProject."); boolean found = false; INavigatorContentExtension ext; @@ -79,21 +79,19 @@ public void testFindValidExtensions() { .getContentProvider(); Object[] projectChildren = testContentProvider .getChildren(_project); - assertEquals( - "There should be one test-type child of the project.", - 1, projectChildren.length); + assertEquals(1, projectChildren.length, + "There should be one test-type child of the project."); assertEquals("BlueParent", contentServiceLabelProvider .getText(projectChildren[0])); Object[] testRootChildren = contentServiceContentProvider .getChildren(projectChildren[0]); - assertEquals( - "There should be one test-type child of the root test-type item.", - 3, testRootChildren.length); + assertEquals(3, testRootChildren.length, + "There should be one test-type child of the root test-type item."); found = true; } } - assertTrue("The test content provider was not found.", found); + assertTrue(found, "The test content provider was not found."); } @@ -111,14 +109,14 @@ public void testDeactivateTestExtension() { .findRootContentExtensions(ResourcesPlugin.getWorkspace() .getRoot()); - assertEquals("Ensure there is only one root content provider.", 1, - rootContentProviders.size()); + assertEquals(1, rootContentProviders.size(), + "Ensure there is only one root content provider."); Set projectContentExtensions = _contentService .findContentExtensionsByTriggerPoint(_project); - assertEquals("Ensure there is one content provider for an IProject.", - 1, projectContentExtensions.size()); + assertEquals(1, projectContentExtensions.size(), + "Ensure there is one content provider for an IProject."); } @@ -135,13 +133,12 @@ public void testBindTestExtension() { new String[] { COMMON_NAVIGATOR_RESOURCE_EXT, TEST_CONTENT, TEST_CONTENT2 }, false); - assertEquals("One descriptor should have been returned.", 1, - boundDescriptors.length); + assertEquals(1, boundDescriptors.length, + "One descriptor should have been returned."); - assertEquals( - "The declarative content service should have one fewer visible extension ids than the one created programmatically.", - _contentService.getVisibleExtensionIds().length + 1, - contentServiceWithProgrammaticBindings.getVisibleExtensionIds().length); + assertEquals(_contentService.getVisibleExtensionIds().length + 1, + contentServiceWithProgrammaticBindings.getVisibleExtensionIds().length, + "The declarative content service should have one fewer visible extension ids than the one created programmatically."); INavigatorContentDescriptor[] visibleDescriptors = contentServiceWithProgrammaticBindings .getVisibleExtensions(); @@ -151,37 +148,35 @@ public void testBindTestExtension() { found = true; } } - assertTrue("The programmatically bound extension should be bound.", - found); + assertTrue(found, + "The programmatically bound extension should be bound."); Set enabledDescriptors = contentServiceWithProgrammaticBindings .findContentExtensionsByTriggerPoint(_project); - assertEquals("There should be a three extensions.", 3, - enabledDescriptors.size()); + assertEquals(3, enabledDescriptors.size(), + "There should be a three extensions."); } @Test public void testTestExtensionVisibility() { - assertTrue("The test extension should be visible.", _contentService - .getViewerDescriptor().isVisibleContentExtension( - TEST_CONTENT)); + assertTrue(_contentService.getViewerDescriptor().isVisibleContentExtension(TEST_CONTENT), + "The test extension should be visible."); } @Test public void testResourceExtensionVisibility() { - assertTrue("The test extension should be visible.", _contentService - .getViewerDescriptor().isVisibleContentExtension( - COMMON_NAVIGATOR_RESOURCE_EXT)); + assertTrue(_contentService.getViewerDescriptor().isVisibleContentExtension(COMMON_NAVIGATOR_RESOURCE_EXT), + "The test extension should be visible."); } @Test public void testVisibleExtensionIds() { String[] visibleIds = _contentService.getVisibleExtensionIds(); - assertEquals("There should be three visible extensions.", 3, - visibleIds.length); + assertEquals(3, visibleIds.length, + "There should be three visible extensions."); for (String visibleId : visibleIds) { if (!TEST_CONTENT.equals(visibleId) && !COMMON_NAVIGATOR_RESOURCE_EXT.equals(visibleId) diff --git a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/SorterTest.java b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/SorterTest.java index 8762f43048d..0388a5f25b5 100644 --- a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/SorterTest.java +++ b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/SorterTest.java @@ -15,10 +15,10 @@ *******************************************************************************/ package org.eclipse.ui.tests.navigator; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.io.ByteArrayInputStream; import java.util.Arrays; @@ -75,7 +75,7 @@ public void testSorterMissing() throws Exception { // We should not get any notification because of the way that // sorters are found - assertEquals("Status Count: " + _statusCount, 0, _statusCount); + assertEquals(0, _statusCount, "Status Count: " + _statusCount); } // bug 231855 [CommonNavigator] CommonViewerSorter does not support diff --git a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/WorkingSetTest.java b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/WorkingSetTest.java index 5c032dcfa27..4af2f8c940b 100644 --- a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/WorkingSetTest.java +++ b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/WorkingSetTest.java @@ -14,8 +14,8 @@ *******************************************************************************/ package org.eclipse.ui.tests.navigator; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IAdaptable; @@ -76,7 +76,7 @@ public void testEmptyWindowWorkingSet() throws Exception { l.propertyChange(event); TreeItem[] items = _viewer.getTree().getItems(); - assertTrue("There should be some items.", items.length > 0); + assertTrue(items.length > 0, "There should be some items."); assertEquals(null, _commonNavigator.getWorkingSetLabel()); } @@ -107,7 +107,7 @@ public void testMissingProjectsInWorkingSet() throws Exception { TreeItem[] items = _viewer.getTree().getItems(); // The bug is here where the first item is a IFile, not the enclosing // project - assertEquals("First item needs to be project", _p1, items[0].getData()); + assertEquals(_p1, items[0].getData(), "First item needs to be project"); assertEquals("ws1", _commonNavigator.getWorkingSetLabel()); } @@ -138,7 +138,7 @@ public void testTopLevelWorkingSet() throws Exception { TreeItem[] items = _viewer.getTree().getItems(); // The bug is here where the first item is a IFile, not the enclosing // project - assertEquals("First item needs to be working set", workingSet, items[0].getData()); + assertEquals(workingSet, items[0].getData(), "First item needs to be working set"); assertEquals("ws1", _commonNavigator.getWorkingSetLabel()); // bug 268250 [CommonNavigator] Project labels missing in Project @@ -181,19 +181,19 @@ public void testTopLevelChange() throws Exception { TreeItem[] items = _viewer.getTree().getItems(); - assertEquals("First item needs to be working set", workingSet, items[0].getData()); + assertEquals(workingSet, items[0].getData(), "First item needs to be working set"); extensionStateModel.setBooleanProperty(WorkingSetsContentProvider.SHOW_TOP_LEVEL_WORKING_SETS, false); refreshViewer(); items = _viewer.getTree().getItems(); - assertEquals("First item needs to be project", _p1, items[0].getData()); + assertEquals(_p1, items[0].getData(), "First item needs to be project"); extensionStateModel.setBooleanProperty(WorkingSetsContentProvider.SHOW_TOP_LEVEL_WORKING_SETS, true); refreshViewer(); items = _viewer.getTree().getItems(); - assertEquals("First item needs to be working set", workingSet, items[0].getData()); + assertEquals(workingSet, items[0].getData(), "First item needs to be working set"); // Restore active working sets activePage.setWorkingSets(activeWorkingSets); @@ -265,7 +265,7 @@ public void testWorkingSetFilter() throws Exception { break; } } - assertTrue("Working set filter is gone, oh my!", found); + assertTrue(found, "Working set filter is gone, oh my!"); } // Bug 224703 - Project explorer doesn't show recreated working set @@ -343,14 +343,14 @@ public void testOtherProjectWorkingSet() throws Exception { _viewer.expandAll(); TreeItem[] items = _viewer.getTree().getItems(); - assertEquals("Missing working set or 'other projects'", 2, items.length); + assertEquals(2, items.length, "Missing working set or 'other projects'"); - assertEquals("First item needs to be working set", workingSet, items[0].getData()); + assertEquals(workingSet, items[0].getData(), "First item needs to be working set"); assertEquals(workingSet, items[0].getData()); assertEquals(_p1, items[0].getItem(0).getData()); - assertEquals("Last item needs to be 'other project'", WorkingSetsContentProvider.OTHERS_WORKING_SET, - items[1].getData()); + assertEquals(WorkingSetsContentProvider.OTHERS_WORKING_SET, items[1].getData(), + "Last item needs to be 'other project'"); assertEquals(_p1.getWorkspace().getRoot().getProjects().length - 1, items[1].getItemCount()); // Put all projects in same working set to disable "others" @@ -361,7 +361,7 @@ public void testOtherProjectWorkingSet() throws Exception { _viewer.expandAll(); items = _viewer.getTree().getItems(); - assertEquals("Should be the single working set", 1, items.length); + assertEquals(1, items.length, "Should be the single working set"); assertEquals(workingSet, items[0].getData()); // Remove project from ws to make "other projects" reappear @@ -372,14 +372,14 @@ public void testOtherProjectWorkingSet() throws Exception { _viewer.expandAll(); items = _viewer.getTree().getItems(); - assertEquals("Missing working set or 'other projects'", 2, items.length); + assertEquals(2, items.length, "Missing working set or 'other projects'"); - assertEquals("First item needs to be working set", workingSet, items[0].getData()); + assertEquals(workingSet, items[0].getData(), "First item needs to be working set"); assertEquals(workingSet, items[0].getData()); assertEquals(_p1, items[0].getItem(0).getData()); - assertEquals("Last item needs to be 'other project'", WorkingSetsContentProvider.OTHERS_WORKING_SET, - items[1].getData()); + assertEquals(WorkingSetsContentProvider.OTHERS_WORKING_SET, items[1].getData(), + "Last item needs to be 'other project'"); assertEquals(_p1.getWorkspace().getRoot().getProjects().length - 1, items[1].getItemCount()); } diff --git a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/jst/JstPipelineTest.java b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/jst/JstPipelineTest.java index b3c6276eb85..e5b13afde96 100644 --- a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/jst/JstPipelineTest.java +++ b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/jst/JstPipelineTest.java @@ -15,9 +15,9 @@ *******************************************************************************/ package org.eclipse.ui.tests.navigator.jst; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; import java.util.function.Predicate; @@ -65,8 +65,8 @@ public void testJstPipeline() throws Exception { // Note this test will fail showing only one if the JDT stuff // is not included in the executing bundles (which it normally is) - assertEquals("There should be 3 visible extensions for the pipeline viewer.", 3, - _contentService.getVisibleExtensionIds().length); + assertEquals(3, _contentService.getVisibleExtensionIds().length, + "There should be 3 visible extensions for the pipeline viewer."); _contentService.getActivationService().activateExtensions( new String[] { COMMON_NAVIGATOR_RESOURCE_EXT, COMMON_NAVIGATOR_JAVA_EXT, TEST_CONTENT_JST }, true); @@ -78,10 +78,10 @@ public void testJstPipeline() throws Exception { TreeItem[] rootItems = _viewer.getTree().getItems(); - assertEquals("There should be " + _projectCount + " item(s).", _projectCount, rootItems.length); //$NON-NLS-1$ + assertEquals(_projectCount, rootItems.length, "There should be " + _projectCount + " item(s)."); //$NON-NLS-1$ - assertTrue("The root object should be an IJavaProject, which is IAdaptable.", //$NON-NLS-1$ - rootItems[0].getData() instanceof IAdaptable); + assertTrue(rootItems[0].getData() instanceof IAdaptable, //$NON-NLS-1$ + "The root object should be an IJavaProject, which is IAdaptable."); IProject adaptedProject = ((IAdaptable) rootItems[_projectInd].getData()).getAdapter(IProject.class); assertEquals(_project, adaptedProject); diff --git a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/FoldersAsProjectsContributionTest.java b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/FoldersAsProjectsContributionTest.java index f2ef09ce573..154f5fcca9d 100644 --- a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/FoldersAsProjectsContributionTest.java +++ b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/FoldersAsProjectsContributionTest.java @@ -13,8 +13,8 @@ ******************************************************************************/ package org.eclipse.ui.tests.navigator.resources; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import java.io.IOException; @@ -62,10 +62,10 @@ public void notAFolder() { String notAFolder = "Some string"; IMenuManager manager = menuManager(); provider(new StructuredSelection(notAFolder)).fillContextMenu(manager); - assertFalse("SelectProjectForFolderAction contributions were added on not an adaptable-to-IFolder selection", - contributionAdded(manager, SelectProjectForFolderAction.class)); - assertFalse("OpenFolderAsProjectAction contributions were added on not an adaptable-to-IFolder selection", - contributionAdded(manager, OpenFolderAsProjectAction.class)); + assertFalse(contributionAdded(manager, SelectProjectForFolderAction.class), + "SelectProjectForFolderAction contributions were added on not an adaptable-to-IFolder selection"); + assertFalse(contributionAdded(manager, OpenFolderAsProjectAction.class), + "OpenFolderAsProjectAction contributions were added on not an adaptable-to-IFolder selection"); } @Test @@ -73,10 +73,10 @@ public void noDescription() { IFolder justAFolder = ResourcesPlugin.getWorkspace().getRoot().getFolder(new Path("some/folder")); IMenuManager manager = menuManager(); provider(new StructuredSelection(justAFolder)).fillContextMenu(manager); - assertFalse("SelectProjectForFolderAction contributions were added on an IFolder without project description", - contributionAdded(manager, SelectProjectForFolderAction.class)); - assertFalse("OpenFolderAsProjectAction contributions were added on an IFolder without project description", - contributionAdded(manager, OpenFolderAsProjectAction.class)); + assertFalse(contributionAdded(manager, SelectProjectForFolderAction.class), + "SelectProjectForFolderAction contributions were added on an IFolder without project description"); + assertFalse(contributionAdded(manager, OpenFolderAsProjectAction.class), + "OpenFolderAsProjectAction contributions were added on an IFolder without project description"); } @Test @@ -103,10 +103,9 @@ public void alreadyAdded() throws IOException, CoreException { provider(new StructuredSelection( Arrays.asList(outer.getFolder(inner1.getName()), outer.getFolder(inner2.getName())))) .fillContextMenu(manager); - assertTrue( + assertTrue(contributionAdded(manager, SelectProjectForFolderAction.class), NLS.bind("A SelectProjectForFolderAction contribution was not added. Contribution List is: {0}", - contributionsList(manager)), - contributionAdded(manager, SelectProjectForFolderAction.class)); + contributionsList(manager))); } finally { clear(projects); } @@ -139,8 +138,9 @@ public void notYetImported() throws IOException, CoreException { provider(new StructuredSelection( Arrays.asList(outer.getFolder(inner1.getName()), outer.getFolder(inner2.getName())))) .fillContextMenu(manager); - assertTrue(NLS.bind("A OpenFolderAsProjectAction contribution was not added. Contribution List is: {0}", - contributionsList(manager)), contributionAdded(manager, OpenFolderAsProjectAction.class)); + assertTrue(contributionAdded(manager, OpenFolderAsProjectAction.class), + NLS.bind("A OpenFolderAsProjectAction contribution was not added. Contribution List is: {0}", + contributionsList(manager))); } finally { clear(projects); } @@ -168,12 +168,10 @@ public void ambiguity() throws CoreException, IOException { provider(new StructuredSelection( Arrays.asList(outer.getFolder(inner1.getName()), outer.getFolder(inner2.getName())))) .fillContextMenu(manager); - assertFalse( - "There were both imported and not-imported projects in selection, but SelectProjectForFolderAction contributions were added", - contributionAdded(manager, SelectProjectForFolderAction.class)); - assertFalse( - "There were both imported and not-imported projects in selection, but OpenFolderAsProjectAction contributions were added", - contributionAdded(manager, OpenFolderAsProjectAction.class)); + assertFalse(contributionAdded(manager, SelectProjectForFolderAction.class), + "There were both imported and not-imported projects in selection, but SelectProjectForFolderAction contributions were added"); + assertFalse(contributionAdded(manager, OpenFolderAsProjectAction.class), + "There were both imported and not-imported projects in selection, but OpenFolderAsProjectAction contributions were added"); } finally { clear(projects); } @@ -239,7 +237,7 @@ private void ensureFileExists(IFile description, String name) throws IOException // If project description does not exist after creation (for whatever reason), // create it explicitly with empty content Files.createFile(Paths.get(description.getLocationURI())); - assertTrue(String.format("Project description for %s does not exist", name), description.exists()); + assertTrue(description.exists(), String.format("Project description for %s does not exist", name)); } } \ No newline at end of file diff --git a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/NestedResourcesTests.java b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/NestedResourcesTests.java index 2dfd54cdcf7..f37fa08e65e 100644 --- a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/NestedResourcesTests.java +++ b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/NestedResourcesTests.java @@ -13,8 +13,8 @@ ******************************************************************************/ package org.eclipse.ui.tests.navigator.resources; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.HashSet; import java.util.Set; @@ -32,9 +32,9 @@ import org.eclipse.ui.internal.navigator.resources.nested.NestedProjectManager; import org.eclipse.ui.internal.navigator.resources.nested.NestedProjectsLabelProvider; import org.eclipse.ui.tests.harness.util.DisplayHelper; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * @since 3.5 @@ -82,28 +82,28 @@ public void testProjectHierarchy() throws Exception { testProjects.add(projectABB); // Wait for NestedProjectManager to process all resource changes - assertTrue("NestedProjectManager did not update children for projectA", - DisplayHelper.waitForCondition(Display.getDefault(), TIMEOUT, - () -> NestedProjectManager.getInstance().getDirectChildrenProjects(projectA).length == 1)); + assertTrue(DisplayHelper.waitForCondition(Display.getDefault(), TIMEOUT, + () -> NestedProjectManager.getInstance().getDirectChildrenProjects(projectA).length == 1), + "NestedProjectManager did not update children for projectA"); IProject[] childrenOfProjectA = NestedProjectManager.getInstance().getDirectChildrenProjects(projectA); - Assert.assertEquals(projectAB, childrenOfProjectA[0]); - Assert.assertNull(NestedProjectManager.getInstance().getMostDirectOpenContainer(projectA)); + Assertions.assertEquals(projectAB, childrenOfProjectA[0]); + Assertions.assertNull(NestedProjectManager.getInstance().getMostDirectOpenContainer(projectA)); // Wait for NestedProjectManager to process projectAAA - assertTrue("NestedProjectManager did not update children for folderAA", - DisplayHelper.waitForCondition(Display.getDefault(), TIMEOUT, - () -> NestedProjectManager.getInstance().getDirectChildrenProjects(folderAA).length == 1)); + assertTrue(DisplayHelper.waitForCondition(Display.getDefault(), TIMEOUT, + () -> NestedProjectManager.getInstance().getDirectChildrenProjects(folderAA).length == 1), + "NestedProjectManager did not update children for folderAA"); IProject[] childrenOfFolderAA = NestedProjectManager.getInstance().getDirectChildrenProjects(folderAA); - Assert.assertEquals("aaa", childrenOfFolderAA[0].getName()); - Assert.assertEquals(folderAA, + Assertions.assertEquals("aaa", childrenOfFolderAA[0].getName()); + Assertions.assertEquals(folderAA, NestedProjectManager.getInstance().getMostDirectOpenContainer(childrenOfFolderAA[0])); // Wait for NestedProjectManager to process both projectABA and projectABB - assertTrue("NestedProjectManager did not update children for projectAB", - DisplayHelper.waitForCondition(Display.getDefault(), TIMEOUT, - () -> NestedProjectManager.getInstance().getDirectChildrenProjects(projectAB).length == 2)); + assertTrue(DisplayHelper.waitForCondition(Display.getDefault(), TIMEOUT, + () -> NestedProjectManager.getInstance().getDirectChildrenProjects(projectAB).length == 2), + "NestedProjectManager did not update children for projectAB"); } @Test @@ -129,8 +129,8 @@ public void testDashInProject() throws Exception { testProjects.add(projectAChild); testProjects.add(projectA_A); - Assert.assertTrue(NestedProjectManager.getInstance().hasDirectChildrenProjects(projectA)); - Assert.assertEquals(projectAChild, NestedProjectManager.getInstance().getDirectChildrenProjects(projectA)[0]); + assertTrue(NestedProjectManager.getInstance().hasDirectChildrenProjects(projectA)); + assertEquals(projectAChild, NestedProjectManager.getInstance().getDirectChildrenProjects(projectA)[0]); } private class NestedProjectsLabelProviderAccessor extends NestedProjectsLabelProvider { @@ -206,7 +206,7 @@ public void testProblemDecoration() throws Exception { () -> IMarker.SEVERITY_ERROR == labelProvider.getHighestProblemSeverity(parentProject))); } - @After + @AfterEach public void deleteProjects() throws Exception { IProgressMonitor monitor = new NullProgressMonitor(); for (IProject testProject : testProjects) { diff --git a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/PathComparatorTest.java b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/PathComparatorTest.java index c927e97fcaa..225fa5f6fbe 100644 --- a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/PathComparatorTest.java +++ b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/PathComparatorTest.java @@ -13,8 +13,8 @@ ******************************************************************************/ package org.eclipse.ui.tests.navigator.resources; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.util.Comparator; @@ -38,9 +38,9 @@ private static void assertConsistentWithEquals(IPath p1, IPath p2) { private static void assertLessThan(IPath p1, IPath p2) { int compare = COMPARATOR.compare(p1, p2); - assertTrue(PathComparator.class.getName() + ".compare() returned " + compare + assertTrue(compare < 0, PathComparator.class.getName() + ".compare() returned " + compare + " expected less than zero for paths '" + p1 + "' and '" - + p2 + "'", compare < 0); + + p2 + "'"); } @Test diff --git a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/ResourceMgmtActionProviderTests.java b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/ResourceMgmtActionProviderTests.java index d4090995865..35809ea38e6 100644 --- a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/ResourceMgmtActionProviderTests.java +++ b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/ResourceMgmtActionProviderTests.java @@ -10,8 +10,8 @@ *******************************************************************************/ package org.eclipse.ui.tests.navigator.resources; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import org.eclipse.core.resources.ICommand; import org.eclipse.core.resources.IFolder; @@ -188,8 +188,8 @@ private void checkMenuHasCorrectContributions(boolean... actions) { for (String thisAction : new String[] { "org.eclipse.ui.BuildAction", "org.eclipse.ui.RefreshAction", "org.eclipse.ui.OpenResourceAction", "org.eclipse.ui.CloseResourceAction", "org.eclipse.ui.CloseUnrelatedProjectsAction" }) { - assertTrue(String.format("Unexpected menu membership for %s (%b)", thisAction, !actions[index]), - actions[index] == menuHasContribution(thisAction)); + assertTrue(actions[index] == menuHasContribution(thisAction), + String.format("Unexpected menu membership for %s (%b)", thisAction, !actions[index])); index++; } } diff --git a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/activities/DynamicTest.java b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/activities/DynamicTest.java index e39e3314405..632e3bab03a 100644 --- a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/activities/DynamicTest.java +++ b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/activities/DynamicTest.java @@ -23,6 +23,7 @@ import java.nio.charset.StandardCharsets; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.internal.registry.ExtensionRegistry; import org.eclipse.core.runtime.ContributorFactoryOSGi; @@ -412,14 +413,15 @@ public void testDynamicRegistry() throws NotDefinedException { assertFalse(category.isDefined()); // set to true when the activity/category in question have had an event // fired - final boolean[] registryChanged = new boolean[] { false, false }; + final AtomicBoolean activityChanged = new AtomicBoolean(false); + final AtomicBoolean categoryChanged = new AtomicBoolean(false); activity.addActivityListener(activityEvent -> { System.err.println("activityChanged"); - registryChanged[0] = true; + activityChanged.set(true); }); category.addCategoryListener(categoryEvent -> { System.err.println("categoryChanged"); - registryChanged[1] = true; + categoryChanged.set(true); }); @@ -442,10 +444,10 @@ public void testDynamicRegistry() throws NotDefinedException { // spin the event loop and ensure that the changes come down the pipe. // 20 seconds should be more than enough DisplayHelper.waitForCondition(PlatformUI.getWorkbench().getDisplay(), 20000, - () -> registryChanged[0] && registryChanged[1]); + () -> activityChanged.get() && categoryChanged.get()); - assertTrue("Activity Listener not called", registryChanged[0]); - assertTrue("Category Listener not called", registryChanged[1]); + assertTrue("Activity Listener not called", activityChanged.get()); + assertTrue("Category Listener not called", categoryChanged.get()); assertTrue(activity.isDefined()); Set patternBindings = activity.getActivityPatternBindings(); diff --git a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/decorators/DecoratorAdaptableTests.java b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/decorators/DecoratorAdaptableTests.java index ec10a7a93ce..b9e5faad119 100644 --- a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/decorators/DecoratorAdaptableTests.java +++ b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/decorators/DecoratorAdaptableTests.java @@ -20,6 +20,7 @@ import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.jobs.Job; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.internal.WorkbenchPlugin; import org.eclipse.ui.internal.decorators.DecorationResult; @@ -44,6 +45,21 @@ private String getDecorationTextFor(Object object) { return result.decorateWithText("Default label"); } + /** + * Waits for all decorator-related jobs to complete. + * This ensures that decorator enablement changes have been fully processed + * before tests check decoration results. + */ + private void waitForDecoratorJobs() { + try { + Job.getJobManager().join(DecoratorManager.FAMILY_DECORATE, null); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + // Also process any pending UI events + UITestUtil.processEvents(); + } + private void assertDecorated(String testSubName, String[] expectedSuffixes, Object[] elements, boolean shouldHaveMatches) { for (Object object : elements) { @@ -65,9 +81,9 @@ public void doSetUp() throws Exception { PlatformUI.getWorkbench().getDecoratorManager().setEnabled(TestResourceDecoratorContributor.ID, true); PlatformUI.getWorkbench().getDecoratorManager().setEnabled(TestResourceMappingDecoratorContributor.ID, true); - // Process all pending UI events to ensure decorator enablement has completed - // This prevents race conditions where decorators may not be fully registered yet - UITestUtil.processEvents(); + // Wait for all decorator jobs to complete after enabling decorators + // This prevents race conditions where decorators may not be fully initialized yet + waitForDecoratorJobs(); } @After @@ -77,8 +93,8 @@ public void doTearDown() throws Exception { PlatformUI.getWorkbench().getDecoratorManager().setEnabled(TestResourceDecoratorContributor.ID, false); PlatformUI.getWorkbench().getDecoratorManager().setEnabled(TestResourceMappingDecoratorContributor.ID, false); - // Process all pending UI events to ensure clean state for next test - UITestUtil.processEvents(); + // Wait for all decorator jobs to complete to ensure clean state for next test + waitForDecoratorJobs(); } /** diff --git a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/dialogs/ResourceInitialSelectionTest.java b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/dialogs/ResourceInitialSelectionTest.java index 88e456b3085..62b6416e60f 100644 --- a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/dialogs/ResourceInitialSelectionTest.java +++ b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/dialogs/ResourceInitialSelectionTest.java @@ -82,6 +82,9 @@ public void testSingleSelectionAndNoInitialSelectionWithInitialPattern() { dialog.open(); dialog.refresh(); + // Wait for background refresh jobs to complete + waitForDialogRefresh(); + List selected = getSelectedItems(dialog); assertFalse("One file should be selected by default", selected.isEmpty()); @@ -100,6 +103,9 @@ public void testSingleSelectionAndOneInitialSelectionWithInitialPattern() { dialog.open(); dialog.refresh(); + // Wait for background refresh jobs to complete + waitForDialogRefresh(); + List selected = getSelectedItems(dialog); assertEquals("One file should be selected by default", asList(FILES.get("foo.txt")), selected); @@ -119,6 +125,9 @@ public void testSingleSelectionAndOneInitialNonExistingSelectionWithInitialPatte dialog.open(); dialog.refresh(); + // Don't wait for full refresh - this test checks that invalid initial + // selections don't cause a selection before dialog is fully loaded + List selected = getSelectedItems(dialog); assertTrue("No file should be selected by default", selected.isEmpty()); @@ -136,6 +145,9 @@ public void testSingleSelectionAndOneInitialSelectionWithoutInitialPattern() { dialog.open(); dialog.refresh(); + // Wait for background refresh jobs to complete + waitForDialogRefresh(); + List selected = getSelectedItems(dialog); assertTrue("No file should be selected by default", selected.isEmpty()); @@ -155,6 +167,9 @@ public void testSingleSelectionAndOneFilteredSelection() { dialog.open(); dialog.refresh(); + // Don't wait for full refresh - this test checks that filtered initial + // selections don't cause a selection before dialog is fully loaded + List selected = getSelectedItems(dialog); assertTrue("No file should be selected by default", selected.isEmpty()); @@ -174,6 +189,9 @@ public void testSingleSelectionAndTwoInitialSelectionsWithInitialPattern() { dialog.open(); dialog.refresh(); + // Wait for background refresh jobs to complete + waitForDialogRefresh(); + List selected = getSelectedItems(dialog); assertEquals("The first file should be selected by default", asList(FILES.get("foo.txt")), selected); @@ -192,6 +210,9 @@ public void testMultiSelectionAndNoInitialSelectionWithInitialPattern() { dialog.open(); dialog.refresh(); + // Wait for background refresh jobs to complete + waitForDialogRefresh(); + List selected = getSelectedItems(dialog); assertFalse("One file should be selected by default", selected.isEmpty()); @@ -211,6 +232,9 @@ public void testMultiSelectionAndOneInitialSelectionWithInitialPattern() { dialog.open(); dialog.refresh(); + // Wait for background refresh jobs to complete + waitForDialogRefresh(); + List selected = getSelectedItems(dialog); assertEquals("One file should be selected by default", asList(FILES.get("foo.txt")), selected); @@ -228,6 +252,9 @@ public void testMultiSelectionAndOneInitialSelectionWithoutInitialPattern() { dialog.open(); dialog.refresh(); + // Wait for background refresh jobs to complete + waitForDialogRefresh(); + List selected = getSelectedItems(dialog); assertTrue("No file should be selected by default", selected.isEmpty()); @@ -247,6 +274,9 @@ public void testMultiSelectionAndTwoInitialNonExistingSelectionWithInitialPatter dialog.open(); dialog.refresh(); + // Don't wait for full refresh - this test checks that invalid initial + // selections don't cause a selection before dialog is fully loaded + List selected = getSelectedItems(dialog); assertTrue("No file should be selected by default", selected.isEmpty()); @@ -266,6 +296,9 @@ public void testMultiSelectionAndSomeInitialNonExistingSelectionWithInitialPatte dialog.open(); dialog.refresh(); + // Wait for background refresh jobs to complete + waitForDialogRefresh(); + List selected = getSelectedItems(dialog); Set expectedSelection = new HashSet<>(asList(FILES.get("bar.txt"), FILES.get("foofoo"))); boolean allInitialElementsAreSelected = expectedSelection.equals(new HashSet<>(selected)); @@ -288,6 +321,9 @@ public void testMultiSelectionAndTwoInitialSelectionsWithInitialPattern() { dialog.open(); dialog.refresh(); + // Wait for background refresh jobs to complete + waitForDialogRefresh(); + List selected = getSelectedItems(dialog); boolean initialElementsAreSelected = selected.containsAll(initialSelection) && initialSelection.containsAll(selected); @@ -310,6 +346,9 @@ public void testMultiSelectionAndTwoInitialFilteredSelections() { dialog.open(); dialog.refresh(); + // Wait for background refresh jobs to complete + waitForDialogRefresh(); + List selected = getSelectedItems(dialog); List expectedSelection = asList(FILES.get("foo.txt"), FILES.get("bar.txt")); boolean initialElementsAreSelected = selected.containsAll(expectedSelection) @@ -408,6 +447,47 @@ private void processUIEvents() { } } + /** + * Wait for dialog refresh jobs to complete and process UI events. + * This ensures background jobs finish before assertions are made. + */ + private void waitForDialogRefresh() { + Display display = PlatformUI.getWorkbench().getDisplay(); + + // The dialog performs async operations (FilterHistoryJob → FilterJob → + // RefreshCacheJob → RefreshJob) to filter and populate the table after refresh() + // We need to wait for the table to be populated before checking selection state + + // First wait for table to have items (up to 2 seconds) + DisplayHelper.waitForCondition(display, 2000, () -> { + processUIEvents(); + try { + Table table = (Table) ((Composite) ((Composite) ((Composite) dialog.getShell().getChildren()[0]) + .getChildren()[0]).getChildren()[0]).getChildren()[3]; + return table.getItemCount() > 0; + } catch (Exception e) { + return false; + } + }); + + // Then wait additional time for selection to be applied + // The selection is set asynchronously after table population completes + // Previous fix used only 3 × 50ms = 150ms which was insufficient on slow systems + // Increased to handle slower machines while minimizing delay on fast ones + for (int i = 0; i < 5; i++) { + processUIEvents(); + try { + Thread.sleep(50); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + } + + // Final event loop processing + processUIEvents(); + } + /** * Delete project with retry mechanism to handle cases where background jobs * are still using the project resources. diff --git a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/dialogs/UIDialogs.java b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/dialogs/UIDialogs.java index 125362dd0e0..64a2689f274 100644 --- a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/dialogs/UIDialogs.java +++ b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/dialogs/UIDialogs.java @@ -95,25 +95,6 @@ public void testCopyMoveResource() { @Test @Ignore("CustomizePerspectiveDialog not implemented") public void testEditActionSetsDialog() { -// Dialog dialog; -// Object persp = null; -// //Test perspective: use current perspective of test case -// try { /* -// * fixme: should try to get current perspective, or default; -// * currently only -// */ -// WorkbenchWindow window = (WorkbenchWindow) getWorkbench().getActiveWorkbenchWindow(); -// persp = new Perspective((PerspectiveDescriptor) getWorkbench() -// .getPerspectiveRegistry().getPerspectives()[0], -// (WorkbenchPage) window.getActivePage()); -// dialog = window.createCustomizePerspectiveDialog(persp); -// } catch (WorkbenchException e) { -// dialog = null; -// } -// DialogCheck.assertDialog(dialog); -// if (persp != null) { -// persp.dispose(); -// } } @Test @@ -184,14 +165,6 @@ public void testSavePerspective() { @Test @Ignore("PerspectiveRegistry.getCustomPersp not implemented") public void testLoadNotExistingPerspective() { -// final String fakePerspectivID = "fakeperspetive"; -// PerspectiveRegistry reg = (PerspectiveRegistry) WorkbenchPlugin -// .getDefault().getPerspectiveRegistry(); -// try { -// reg.getCustomPersp(fakePerspectivID); -// } catch (WorkbenchException e) { -// assertTrue(e.getStatus().getMessage().indexOf(fakePerspectivID) != -1); -// } } @Test diff --git a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/progress/ProgressContantsTest.java b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/progress/ProgressContantsTest.java index 45d30180476..b18785a9681 100644 --- a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/progress/ProgressContantsTest.java +++ b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/progress/ProgressContantsTest.java @@ -223,6 +223,8 @@ public void testKeepOneProperty() throws Exception { errorJob.schedule(); processEventsUntil(() -> findProgressInfoItem(errorJob) != null, 3000); } + // Wait for KEEPONE cleanup to stabilize at exactly 1 item + processEventsUntil(() -> countBelongingProgressItems(DummyFamilyJob.class) == 1, 3000); assertEquals("Only one finished job should be kept in view", 1, countBelongingProgressItems(DummyFamilyJob.class)); @@ -242,16 +244,20 @@ public void testKeepOneProperty() throws Exception { job.schedule(); } // ensure all jobs are started before ending all at the same time - processEventsUntil(null, 500); + processEventsUntil(() -> jobs.stream().allMatch(job -> job.inProgress), 3000); for (DummyJob job : jobs) { job.shouldFinish = true; } joinJobs(jobs, 10, TimeUnit.SECONDS); + // Process events to ensure job completion events are handled + processEvents(); { DummyJob errorJob = new DummyJob("Last Job", new Status(IStatus.ERROR, TestPlugin.PLUGIN_ID, "error")); errorJob.schedule(); processEventsUntil(() -> findProgressInfoItem(errorJob) != null, 3000); } + // Wait for KEEPONE cleanup to stabilize at exactly 1 item + processEventsUntil(() -> countBelongingProgressItems(DummyFamilyJob.class) == 1, 5000); assertEquals("Only one finished job should be kept in view", 1, countBelongingProgressItems(DummyFamilyJob.class)); diff --git a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/progress/ProgressViewTests.java b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/progress/ProgressViewTests.java index 200bb32ea6a..520da5fb475 100644 --- a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/progress/ProgressViewTests.java +++ b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/progress/ProgressViewTests.java @@ -25,7 +25,6 @@ import java.util.Collections; import java.util.concurrent.TimeUnit; -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; @@ -152,36 +151,49 @@ public void testItemOrder() throws Exception { // allJobs.add(keptJob); try { + // Set all jobs to not finish immediately so they stay running for comparison + for (DummyJob job : jobsToSchedule) { + job.shouldFinish = false; + } + + // Close and reopen the progress view to get a fresh comparator with empty lastIndexes + hideProgressView(); + openProgressView(); + + // Schedule all jobs in random order rapidly to minimize throttled updates between schedules ArrayList shuffledJobs = new ArrayList<>(jobsToSchedule); Collections.shuffle(shuffledJobs); StringBuilder scheduleOrder = new StringBuilder("Jobs schedule order: "); - progressView.getViewer().refresh(); // order will only hold on the first time. - Thread.sleep(200); // wait till throttled update ran. - Job dummyJob = new Job("dummy throttled caller") { - @Override - protected IStatus run(IProgressMonitor monitor) { - return Status.OK_STATUS; - } - }; - dummyJob.schedule(); // trigger throttled update to clear ProgressViewerComparator.lastIndexes - // now hope the loop is executed before next throttled update (could fail if VM - // is busy otherwise): for (DummyJob job : shuffledJobs) { - job.shouldFinish = false; - job.schedule(); // if the schedule updates the progress View (throttled) the sort order is - // affected + job.schedule(); scheduleOrder.append(job.getName()).append(", "); } TestPlugin.getDefault().getLog() .log(new Status(IStatus.OK, TestPlugin.PLUGIN_ID, scheduleOrder.toString())); + // Wait for all jobs to be running for (DummyJob job : allJobs) { processEventsUntil(() -> job.inProgress, TimeUnit.SECONDS.toMillis(3)); } - progressView.getViewer().refresh(); + + // Wait for the progress view to be updated with all jobs + processEventsUntil(() -> progressView.getViewer().getProgressInfoItems().length == allJobs.size(), + TimeUnit.SECONDS.toMillis(5)); + + // The ProgressViewerComparator uses lastIndexes for stable sorting. After throttled updates + // during job scheduling, lastIndexes may contain jobs in schedule order rather than priority order. + // Close and reopen the view again to reset the comparator's state, then do a single refresh + // to sort all jobs by priority from a clean state. + hideProgressView(); + openProgressView(); + + // Wait for the view to be populated again processEventsUntil(() -> progressView.getViewer().getProgressInfoItems().length == allJobs.size(), TimeUnit.SECONDS.toMillis(5)); + // Give time for any pending updates + processEventsUntil(() -> false, 500); + ProgressInfoItem[] progressInfoItems = progressView.getViewer().getProgressInfoItems(); assertEquals("Not all jobs visible in progress view", allJobs.size(), progressInfoItems.length); Object[] expected = allJobs.toArray(); diff --git a/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/workbench/texteditor/tests/TextEditorPluginTest.java b/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/workbench/texteditor/tests/TextEditorPluginTest.java index 7c756fefb97..67c81bee7b9 100644 --- a/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/workbench/texteditor/tests/TextEditorPluginTest.java +++ b/tests/org.eclipse.ui.workbench.texteditor.tests/src/org/eclipse/ui/workbench/texteditor/tests/TextEditorPluginTest.java @@ -21,9 +21,7 @@ import java.util.Random; import org.junit.FixMethodOrder; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TestName; import org.junit.runners.MethodSorters; import org.eclipse.ui.internal.texteditor.HistoryTracker; @@ -36,9 +34,6 @@ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TextEditorPluginTest { - @Rule - public TestName testName = new TestName(); - Random rand = new Random(55); //pseudo-random for repeatability @Test