@Override
				protected void updateItem(CategorizedTransformer item, boolean isEmpty) {
					super.updateItem(item, isEmpty);

					if (item == null || isEmpty) {
						setText(null);
						setGraphic(null);
					} else {
						// TODO: If we add "CompositeTransformer" to our system (a transformer that wraps several others in a specific order)
						//  then this logic will need to be updated to "unroll" those wrapped transformers.
						int index = getIndex();
						List<? extends Class<? extends ClassTransformer>> transformerClasses = transformerOrder.stream()
								.map(t -> t.transformer().transformer().getClass())
								.toList();
						ClassTransformer transformer = item.transformer().transformer();
						List<ClassTransformer> missingPredecessors = Unchecked.cast(transformer.recommendedPredecessors().stream()
								.filter(pre -> {
									int i = transformerClasses.indexOf(pre);
									return i < 0 || i > index;
								})
								.map(pre -> {
									try {
										if (JvmClassTransformer.class.isAssignableFrom(pre))
											return transformationManager.newJvmTransformer(Unchecked.cast(pre));
									} catch (TransformationException e) {
										logger.error("Failed to initialize instance of {}", pre, e);
									}
									return null;
								})
								.filter(Objects::nonNull)
								.toList());
						List<ClassTransformer> missingSuccessors = Unchecked.cast(transformer.recommendedSuccessors().stream()
								.filter(post -> {
									int i = transformerClasses.indexOf(post);
									return i < 0 || i < index;
								})
								.map(post -> {
									try {
										if (JvmClassTransformer.class.isAssignableFrom(post))
											return transformationManager.newJvmTransformer(Unchecked.cast(post));
									} catch (TransformationException e) {
										logger.error("Failed to initialize instance of {}", post, e);
									}
									return null;
								})
								.filter(Objects::nonNull)
								.toList());

						Label name = new Label(item.transformer().name(), new FontIconView(item.category().icon));
						BorderPane wrapper = new BorderPane();
						VBox missing = new VBox(name);
						missing.setPadding(new Insets(10));
						missing.setSpacing(10);
						missing.setAlignment(Pos.CENTER_LEFT);
						if (!missingPredecessors.isEmpty()) {
							String missingTransformers = Lang.get("deobf.order.pre") + ":\n - " + missingPredecessors.stream().map(ClassTransformer::name).collect(Collectors.joining("\n - "));
							Label missingLabel = new Label(missingTransformers);
							missingLabel.setPadding(new Insets(0, 0, 0, 20));
							missingLabel.getStyleClass().add(Styles.TEXT_SUBTLE);
							missing.getChildren().add(missingLabel);
						}
						if (!missingSuccessors.isEmpty()) {
							String missingTransformers = Lang.get("deobf.order.suc") + ":\n - " + missingSuccessors.stream().map(ClassTransformer::name).collect(Collectors.joining("\n - "));
							Label missingLabel = new Label(missingTransformers);
							missingLabel.setPadding(new Insets(0, 0, 0, 20));
							missingLabel.getStyleClass().add(Styles.TEXT_SUBTLE);
							missing.getChildren().add(missingLabel);
						}
						wrapper.setBottom(missing);
						setGraphic(wrapper);
					}
				}
Pane for previewing deobfuscation transformers.

@author Matt Coley
recaf-ui/src/main/java/software/coley/recaf/ui/window/DeobfuscationWindow.java