Test fixes for recent TextLayoutGraphics change

This commit is contained in:
dragonmacher 2021-07-14 17:52:35 -04:00
parent 928bc5508a
commit b970e40aff
5 changed files with 60 additions and 56 deletions

View file

@ -25,6 +25,7 @@ import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import docking.ActionContext; import docking.ActionContext;
import docking.ComponentProvider; import docking.ComponentProvider;
@ -346,12 +347,7 @@ public class CodeBrowserClipboardProvider extends ByteCopier
return createStringTransferable(g.getBuffer().toString()); return createStringTransferable(g.getBuffer().toString());
} }
catch (Exception e) { catch (Exception e) {
String msg = e.getMessage(); String message = "Copy failed: " + ExceptionUtils.getMessage(e);
if (msg == null) {
msg = e.toString();
}
String message = "Copy failed: " + msg;
Msg.error(this, message, e); Msg.error(this, message, e);
tool.setStatusInfo(message, true); tool.setStatusInfo(message, true);
} }

View file

@ -18,6 +18,8 @@ package ghidra.app.plugin.core.functiongraph;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.datatransfer.Transferable; import java.awt.datatransfer.Transferable;
import org.apache.commons.lang3.exception.ExceptionUtils;
import docking.ActionContext; import docking.ActionContext;
import docking.widgets.fieldpanel.Layout; import docking.widgets.fieldpanel.Layout;
import docking.widgets.fieldpanel.internal.EmptyLayoutBackgroundColorManager; import docking.widgets.fieldpanel.internal.EmptyLayoutBackgroundColorManager;
@ -32,6 +34,7 @@ import ghidra.app.plugin.core.functiongraph.mvc.FGData;
import ghidra.app.util.viewer.listingpanel.ListingModel; import ghidra.app.util.viewer.listingpanel.ListingModel;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.util.Msg;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class FGClipboardProvider extends CodeBrowserClipboardProvider { public class FGClipboardProvider extends CodeBrowserClipboardProvider {
@ -82,11 +85,9 @@ public class FGClipboardProvider extends CodeBrowserClipboardProvider {
return createStringTransferable(g.getBuffer().toString()); return createStringTransferable(g.getBuffer().toString());
} }
catch (Exception e) { catch (Exception e) {
String msg = e.getMessage(); String message = "Copy failed: " + ExceptionUtils.getMessage(e);
if (msg == null) { Msg.error(this, message, e);
msg = e.toString(); tool.setStatusInfo(message, true);
}
tool.setStatusInfo("Copy failed: " + msg, true);
} }
return null; return null;

View file

@ -105,7 +105,7 @@ public class TextLayoutGraphics extends Graphics2D {
@Override @Override
public void setFont(Font font) { public void setFont(Font font) {
lastFont = font; lastFont = font;
fontMetrics = getFontMetrics(font); fontMetrics = createFontMetrics(font);
} }
/** /**
@ -117,73 +117,79 @@ public class TextLayoutGraphics extends Graphics2D {
return; return;
} }
TextInfo[] sortedTextInfos = new TextInfo[textInfos.size()]; sortDataAndAssignRows();
textInfos.toArray(sortedTextInfos);
//Sort the text by y position, then by x position // render the text into a string
Arrays.sort(sortedTextInfos, pointComparator);
//Group the text into rows based on font height and y position
//TODO - Ideally, it would be nice if there was a good way to group text that
// varied in height in a nice way
int lastPos = sortedTextInfos[0].point.y;
int curRow = 0;
for (int i = 0; i < sortedTextInfos.length; i++) {
if (sortedTextInfos[i].point.y != lastPos) {
curRow++;
lastPos = sortedTextInfos[i].point.y;
}
sortedTextInfos[i].row = curRow;
}
//Sort the text by row, then by x position
Arrays.sort(sortedTextInfos, rowComparator);
//Render the text into a string
int lastRow = 0; int lastRow = 0;
int lastXPos = 0; //The X co-ordinate of the end of the last string int currentX = 0; //The x coordinate of the end of the last string
for (TextInfo sortedTextInfo : sortedTextInfos) { for (TextInfo info : textInfos) {
//Insert newlines as appropriate // insert newlines as appropriate
for (int j = lastRow; j < sortedTextInfo.row; j++) { for (int i = lastRow; i < info.row; i++) {
buffer.append('\n'); buffer.append('\n');
} }
//If we started a new row, reset the X position // if we started a new row, reset the x position
if (lastRow != sortedTextInfo.row) { if (lastRow != info.row) {
lastXPos = 0; currentX = 0;
} }
lastRow = sortedTextInfo.row; lastRow = info.row;
//Insert spaces to account for distance past last field in row // insert spaces to account for distance past last field in row
FontMetrics metrics = sortedTextInfo.fontMetrics; FontMetrics metrics = info.fontMetrics;
int spaceWidth = metrics.charWidth(' '); int spaceWidth = metrics.charWidth(' ');
if (spaceWidth == 0) { if (spaceWidth == 0) {
// some environments report 0 for some fonts // some environments report 0 for some fonts
spaceWidth = 4; spaceWidth = 4;
} }
int fillSpaces = float spaceBetween = info.point.x - currentX;
Math.round((float) (sortedTextInfo.point.x - lastXPos) / (float) spaceWidth); int fillSpaces = Math.round(spaceBetween / spaceWidth);
//Account for the case where there's a very small amount of space between fields
if (fillSpaces == 0 && sortedTextInfo.point.x > lastXPos) { // account for the case where there's a very small amount of space between fields
if (fillSpaces == 0 && info.point.x > currentX) {
fillSpaces = 1; fillSpaces = 1;
} }
for (int j = 0; j < fillSpaces; j++) { for (int i = 0; i < fillSpaces; i++) {
buffer.append(' '); buffer.append(' ');
} }
lastXPos = sortedTextInfo.point.x + metrics.stringWidth(sortedTextInfo.text); int stringWidth = metrics.stringWidth(info.text);
currentX = info.point.x + stringWidth;
//Append the text // append the text
buffer.append(sortedTextInfo.text); buffer.append(info.text);
} }
buffer.append('\n'); buffer.append('\n');
textInfos.clear(); textInfos.clear();
} }
private void sortDataAndAssignRows() {
// sort the text by y position, then by x position
textInfos.sort(pointComparator);
// Group the text into rows based on font height and y position
//TODO - Ideally, it would be nice if there was a good way to group text that
// varied in height in a nice way
int lastPos = textInfos.get(0).point.y;
int row = 0;
for (TextInfo info : textInfos) {
if (info.point.y != lastPos) {
row++;
lastPos = info.point.y;
}
info.row = row;
}
// sort the text by row, then by x position
textInfos.sort(rowComparator);
}
public String getBuffer() { public String getBuffer() {
return buffer.toString(); return buffer.toString();
} }

View file

@ -759,6 +759,7 @@ public class HTMLUtilities {
// //
// Use the label's builtin handling of HTML text via the HTMLEditorKit // Use the label's builtin handling of HTML text via the HTMLEditorKit
// //
Swing.assertSwingThread("This method must be called on the Swing thread");
JLabel label = new JLabel(text) { JLabel label = new JLabel(text) {
@Override @Override
public void paint(Graphics g) { public void paint(Graphics g) {

View file

@ -15,8 +15,8 @@
*/ */
package ghidra.util; package ghidra.util;
import static ghidra.util.HTMLUtilities.HTML; import static ghidra.util.HTMLUtilities.*;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import java.awt.Color; import java.awt.Color;
@ -122,7 +122,7 @@ public class HTMLUtilitiesTest {
@Test @Test
public void testFromHTML() { public void testFromHTML() {
String s = "<HTML><b>Bold</b>, <i>italics</i>, <font size='3'>sized font!</font>"; String s = "<HTML><b>Bold</b>, <i>italics</i>, <font size='3'>sized font!</font>";
String text = HTMLUtilities.fromHTML(s); String text = Swing.runNow(() -> HTMLUtilities.fromHTML(s));
assertEquals("Bold, italics, sized font!", text); assertEquals("Bold, italics, sized font!", text);
} }