Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions topcat/src/main/uk/ac/starlink/topcat/CustomLabelUI.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package uk.ac.starlink.topcat;

import java.awt.FontMetrics;
import java.awt.Rectangle;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.plaf.basic.BasicLabelUI;

/**
* An implementation of the (Basic)LabelUI for overriding JLabel formatting in
* the cells of JTables.
*
* This is used to change the location of the ellipsis when a string is
* rendered in a cell that cannot fit. By default, the ellipsis is always at
* the end of the string, but this class instead places the ellipsis in the
* middle of the string. See
*
* https://docs.oracle.com/javase/8/docs/api/javax/swing/plaf/basic/BasicLabelUI.html
*
* @author Fergus Baker
* @since 03 Feb 2026
*/
public class CustomLabelUI extends BasicLabelUI {
private static final String ELLIPSES = "...";
private static final int ELLIPSES_LEN = ELLIPSES.length();
private String displayedText;

/**
* Implicit constructor, called by Swing with a particular component in
* order to have something for drawing labels to the screen.
*/
public static CustomLabelUI createUI(JComponent c) {
return new CustomLabelUI();
}

/**
* Returns the text displayed in the label.
*
* @return String
*/
public String getText() {
return displayedText;
}

private int findTruncationSplit(int maxWidth, FontMetrics fontMetrics,
String text) {
int textLength = text.length();
for (int i = 1; i <= textLength; i++) {
int subTextWidth = fontMetrics.stringWidth(
text.substring( textLength - i )
);
if (subTextWidth > maxWidth) {
return textLength - i + 1;
}
}
return 0;
}

@Override
protected String layoutCL(JLabel label, FontMetrics fontMetrics,
String text, Icon icon, Rectangle viewR,
Rectangle iconR, Rectangle textR) {
/* Draw the text with the usual layout for a compound label. */
displayedText = super.layoutCL(label, fontMetrics, text, icon, viewR,
iconR, textR);

/* Sometimes the font metrics is null if the text is being displayed
* before the UI is ready. In such a case, there is nothing that this
* class needs to do. */
if (fontMetrics == null) {
return displayedText;
}

int displayedLength = displayedText.length();

/* Check if a truncation occurred, and if the text is long enough. If
* the text is too short, there is no point in truncating differently.
* */;
if (!displayedText.equals(text) && displayedLength > 2 * ELLIPSES_LEN) {
int splitLength = (displayedLength + ELLIPSES_LEN) / 2 - ELLIPSES_LEN;
String beforeEllipses = displayedText.substring(0, splitLength);
/* Determine the maximum width (in pixels) that the remaining text
* should fit into. */
int displayedTextWidth = fontMetrics.stringWidth(displayedText);
int maxWidth = (
displayedTextWidth
- fontMetrics.stringWidth(ELLIPSES)
- fontMetrics.stringWidth(beforeEllipses)
);

int splitIndex = findTruncationSplit(
maxWidth, fontMetrics, text
);

displayedText = (
beforeEllipses + ELLIPSES + text.substring(splitIndex)
);
}

return displayedText;
}
}
5 changes: 5 additions & 0 deletions topcat/src/main/uk/ac/starlink/topcat/Driver.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import org.astrogrid.samp.ErrInfo;
import org.astrogrid.samp.JSamp;
import org.astrogrid.samp.Response;
Expand All @@ -35,6 +36,7 @@
import uk.ac.starlink.table.jdbc.TextModelsAuthenticator;
import uk.ac.starlink.task.InvokeUtils;
import uk.ac.starlink.topcat.interop.TopcatCommunicator;
import uk.ac.starlink.topcat.CustomLabelUI;
import uk.ac.starlink.ttools.Stilts;
import uk.ac.starlink.util.gui.ErrorDialog;
import uk.ac.starlink.util.DataSource;
Expand Down Expand Up @@ -126,6 +128,9 @@ private static void runMain( String[] args )
// never mind
cmdname = null;
}
/* Register custom LabelUI for drawing cells in JTable. This has to
* happen before any of the UI is initialised. */
UIManager.put("LabelUI", CustomLabelUI.class.getName());
Loader.tweakGuiForMac();
Loader.setHttpAgent( TopcatUtils.getHttpUserAgent() );
Loader.setDefaultProperty( "java.awt.Window.locationByPlatform",
Expand Down