Skip to content

Dialog.shortenText performs badly with huge inputs #3545

@FlorianKroiss

Description

@FlorianKroiss

Let's make sure issue is not already fixed in latest builds first.

Steps to reproduce

  1. Make sure the Progress view open
  2. Start a Job that produces an enormous error message, e.g.,
final Job j = new Job("test") {

    @Override
    protected IStatus run(final IProgressMonitor monitor) {
        return Status.error("There was an Error\n".repeat(2000000));
    }
};
j.schedule();
  1. The application freezes, because Dialog.shortenText is trying to reduce this large error message down to a string which can be displayed.

Excerpt from main-Thread Stack:

OS.DrawText(long, char[], int, RECT, int) line: not available [native method]	
GC.textExtentInPixels(String, int) line: 5832	
GC.textExtent(String) line: 5773	
Dialog.shortenText(String, Control) line: 361	
ProgressInfoItem.updateText(String, Link) line: 812	
ProgressInfoItem.setLinkText(Job, String, int) line: 741	
ProgressInfoItem.refresh() line: 528	
ProgressInfoItem.createChildren() line: 271	
ProgressInfoItem.<init>(Composite, int, JobTreeElement) line: 197	
DetailedProgressViewer.createNewItem(JobTreeElement) line: 220	
DetailedProgressViewer.reorderControls(Object[]) line: 481	
DetailedProgressViewer.updateItems(Set<JobTreeElement>) line: 189	
DetailedProgressViewer.add(JobTreeElement...) line: 173	
DetailedProgressViewer.internalRefresh(Object) line: 367	
DetailedProgressViewer(StructuredViewer).internalRefresh(Object, boolean) line: 1249	
DetailedProgressViewer(StructuredViewer).lambda$3(Object, boolean) line: 1485	
Lambda.run() line: not available	
DetailedProgressViewer(StructuredViewer).preservingSelection(Runnable, boolean) line: 1391	
DetailedProgressViewer(StructuredViewer).preservingSelection(Runnable) line: 1352	
DetailedProgressViewer(StructuredViewer).refresh(Object, boolean) line: 1485	
ProgressViewerContentProvider.refresh(JobTreeElement...) line: 75	
ProgressViewUpdater.update() line: 299
[...]

Possible fixes for Dialog.shortenText:

  • Add a hard limit to the length of the input String at which point we don't even try to shorten the string
  • Perform some kind of binary-search when trying to determine start and end instead of moving each limit by 1 in each iteration of the for loop.

Relevant code:

public static String shortenText(String textValue, Control control) {
if (textValue == null) {
return null;
}
GC gc = new GC(control);
int maxWidth = control.getBounds().width - 5;
int maxExtent = gc.textExtent(textValue).x;
if (maxExtent < maxWidth) {
gc.dispose();
return textValue;
}
int length = textValue.length();
int charsToClip = Math.round(0.95f*length * (1 - ((float)maxWidth/maxExtent)));
int pivot = length / 2;
int start = pivot - (charsToClip/2);
int end = pivot + (charsToClip/2) + 1;
while (start >= 0 && end < length) {
String s1 = textValue.substring(0, start);
String s2 = textValue.substring(end, length);
String s = s1 + ELLIPSIS + s2;
int l = gc.textExtent(s).x;
if (l < maxWidth) {
gc.dispose();
return s;
}
start--;
end++;
}
gc.dispose();
return textValue;

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions