private GhidraTable createMarkupItemTable() {
		tablePanel = new MarkupItemThreadedTablePanel(createTableModel());
		final GhidraTable table = tablePanel.getTable();
		table.setActionsEnabled(true);

		table.addFocusListener(new FocusAdapter() {
			@Override
			public void focusGained(FocusEvent e) {
				iconTimer.restart();
			}
		});

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

				try {
					// Need the following flag to prevent selection changing when selecting
					// in the markup table, if another of the same markup type exists with
					// the same destination address.
					processingMarkupItemSelected = true;

					ListingCodeComparisonPanel dualListingPanel =
						functionComparisonPanel.getDualListingPanel();
					VTMarkupItem markupItem = null;
					if (table.getSelectedRowCount() == 1) {
						// we get out the model here in case it has been wrapped by one of the filters
						RowObjectTableModel<VTMarkupItem> model =
							(RowObjectTableModel<VTMarkupItem>) table.getModel();
						int selectedRow = table.getSelectedRow();
						markupItem = model.getRowObject(selectedRow);
					}
					else {
						// No markup item selected or multiple selected.
						if (dualListingPanel != null) {
							dualListingPanel.updateListings(); // refresh the dual listing's background markup colors.
						}
						controller.setSelectedMarkupItem(null); // Refresh the subTools markup backgrounds and location.
						return;
					}

					notifyContextChanged();

					if (dualListingPanel != null) {
						// Don't set source or destination if the location change was initiated by the dual listing.
						if (!processingSourceLocationChange &&
							!processingDestinationLocationChange) {
							dualListingPanel.setLocation(LEFT, dualListingPanel.getProgram(LEFT),
								markupItem.getSourceLocation());
							dualListingPanel.setLocation(RIGHT, dualListingPanel.getProgram(RIGHT),
								markupItem.getDestinationLocation());
						}
						else {
							// Only adjust the side of the dual listing panel that didn't initiate this.
							ProgramLocation sourceLocation = markupItem.getSourceLocation();
							if (processingDestinationLocationChange && sourceLocation != null) {
								dualListingPanel.setLocation(LEFT,
									dualListingPanel.getProgram(LEFT), sourceLocation);
							}

							ProgramLocation destinationLocation =
								markupItem.getDestinationLocation();
							if (processingSourceLocationChange && destinationLocation != null) {
								dualListingPanel.setLocation(RIGHT,
									dualListingPanel.getProgram(RIGHT), destinationLocation);
							}
						}
						dualListingPanel.updateListings(); // refresh the dual listing's background markup colors.
					}
					controller.setSelectedMarkupItem(markupItem); // Refresh the subTools markup backgrounds and location.
				}
				finally {
					processingMarkupItemSelected = false;
				}
			}
		};
		ListSelectionModel selectionModel = table.getSelectionModel();
		selectionModel.addListSelectionListener(markupItemSelectionListener);

		TableColumnModel columnModel = table.getColumnModel();

		int columnIndex =
			markupItemsTableModel.getColumnIndex(AppliedDestinationAddressTableColumn.class);
		TableColumn column = columnModel.getColumn(columnIndex);
		column.setCellEditor(new AddressInputDialog(controller));

		// 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);
		scrollBar.getAccessibleContext().setAccessibleName("Markup Item Table");
		Dimension scrollBarSize = scrollBar.getMinimumSize();
		size.width = preferredSize.width + scrollBarSize.width;
		table.setPreferredScrollableViewportSize(size);
		table.getAccessibleContext().setAccessibleName("Markup Item");
		return table;
	}
Creates a new markup items table provider for displaying markup items, and code comparison
views such as a dual listing for the currently selected version tracking match.
@param controller the version tracking controller for this provider
Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/markuptable/VTMarkupItemsTableProvider.java