protected GhidraTable initializeMatchesTable() {
		oneToManyTableModel = getMatchesTableModel();
		oneToManyTableModel.addTableModelListener(e -> {
			if (matchesTable == null) {
				return; // we've been disposed
			}

			if (pendingMatchSelection != null) {
				setSelectedMatch(pendingMatchSelection);
			}
		});

		tablePanel = new MatchThreadedTablePanel(oneToManyTableModel);
		final GhidraTable table = tablePanel.getTable();

		matchSelectionListener = new ListSelectionListener() {
			@Override
			@SuppressWarnings("unchecked")
			// it's our model, it must be our type
			public void valueChanged(ListSelectionEvent e) {
				if (e.getValueIsAdjusting()) {
					return;
				}

				// we get out the model here in case it has been wrapped by one of the filters
				RowObjectTableModel<VTMatch> model =
					(RowObjectTableModel<VTMatch>) table.getModel();
				int selectedRow = table.getSelectedRow();
				VTMatch match =
					(table.getSelectedRowCount() == 1) ? model.getRowObject(selectedRow) : null;
				if (!SystemUtilities.isEqual(latestMatch, match) && match != null) {
					latestMatch = match;
					subToolManager.setMatch(match);
				}
				notifyContextChanged();
			}
		};
		ListSelectionModel selectionModel = table.getSelectionModel();
		selectionModel.addListSelectionListener(matchSelectionListener);

		// setup the renderers
		TableColumnModel columnModel = table.getColumnModel();

		int statusColumnIndex = oneToManyTableModel.getColumnIndex(StatusTableColumn.class);
		TableColumn statusColumn = columnModel.getColumn(statusColumnIndex);
		statusColumn.setCellRenderer(new MatchStatusRenderer());

		// override the default behavior so we see our columns in their preferred size
		Dimension size = table.getPreferredScrollableViewportSize();
		Dimension preferredSize = table.getPreferredSize();

		// ...account for the scroll bar width
		JScrollBar scrollBar = new JScrollBar(Adjustable.VERTICAL);
		Dimension scrollBarSize = scrollBar.getMinimumSize();
		size.width = preferredSize.width + scrollBarSize.width;
		table.setPreferredScrollableViewportSize(size);

		return table;
	}
The docking window that provides a table of the other tool's function matches
for the function containing the current cursor location in this tool's
listing.
Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/onetomany/VTMatchOneToManyTableProvider.java