diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/Designer.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/Designer.java index 1c9777920a..b4705ac693 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/Designer.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/Designer.java @@ -11,6 +11,7 @@ import java.util.Objects; import java.util.stream.Collectors; import net.sourceforge.pmd.PMDVersion; +import net.sourceforge.pmd.util.fxdesigner.app.DesignerRoot; import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil; import javafx.application.Application; @@ -23,7 +24,7 @@ import javafx.stage.Stage; /** - * Main class for the designer. + * Main class for the designer, launched only if {@link DesignerStarter} detected JavaFX support. * * @author Clément Fournier * @since 6.0.0 @@ -45,13 +46,12 @@ public class Designer extends Application { @Override public void start(Stage stage) throws IOException { - boolean developerMode = parseParameters(getParameters()); + boolean isDeveloperMode = parseParameters(getParameters()); - FXMLLoader loader - = new FXMLLoader(DesignerUtil.getFxml("designer.fxml")); + FXMLLoader loader = new FXMLLoader(DesignerUtil.getFxml("designer.fxml")); - DesignerRoot owner = new DesignerRoot(stage, developerMode); + DesignerRoot owner = new DesignerRoot(stage, isDeveloperMode); MainDesignerController mainController = new MainDesignerController(owner); NodeInfoPanelController nodeInfoPanelController = new NodeInfoPanelController(mainController); diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/MainDesignerController.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/MainDesignerController.java index a9ff10cfe0..e6dd37281a 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/MainDesignerController.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/MainDesignerController.java @@ -23,14 +23,14 @@ import org.reactfx.value.Val; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; +import net.sourceforge.pmd.util.fxdesigner.app.DesignerRoot; import net.sourceforge.pmd.util.fxdesigner.model.XPathEvaluationException; import net.sourceforge.pmd.util.fxdesigner.popups.EventLogController; -import net.sourceforge.pmd.util.fxdesigner.util.AbstractController; -import net.sourceforge.pmd.util.fxdesigner.util.ApplicationComponent; -import net.sourceforge.pmd.util.fxdesigner.util.CompositeSelectionSource; +import net.sourceforge.pmd.util.fxdesigner.app.AbstractController; +import net.sourceforge.pmd.util.fxdesigner.app.CompositeSelectionSource; import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil; import net.sourceforge.pmd.util.fxdesigner.util.LimitedSizeStack; -import net.sourceforge.pmd.util.fxdesigner.util.NodeSelectionSource; +import net.sourceforge.pmd.util.fxdesigner.app.NodeSelectionSource; import net.sourceforge.pmd.util.fxdesigner.util.SoftReferenceCache; import net.sourceforge.pmd.util.fxdesigner.util.TextAwareNodeWrapper; import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsPersistenceUtil; @@ -67,12 +67,7 @@ import javafx.stage.FileChooser; * @since 6.0.0 */ @SuppressWarnings("PMD.UnusedPrivateField") -public class MainDesignerController extends AbstractController implements CompositeSelectionSource, ApplicationComponent { - - /** - * Callback to the owner. - */ - private final DesignerRoot designerRoot; +public class MainDesignerController extends AbstractController> implements CompositeSelectionSource { /* Menu bar */ @@ -115,16 +110,11 @@ public class MainDesignerController extends AbstractController implements Compos public MainDesignerController(DesignerRoot owner) { - this.designerRoot = owner; + super(owner, null); eventLogController = new SoftReferenceCache<>(() -> new EventLogController(this)); } - @Override - public DesignerRoot getDesignerRoot() { - return designerRoot; - } - @Override protected void beforeParentInit() { @@ -142,7 +132,7 @@ public class MainDesignerController extends AbstractController implements Compos openRecentMenu.setOnShowing(e -> updateRecentFilesMenu()); fileMenu.setOnShowing(e -> onFileMenuShowing()); - setupAuxclasspathMenuItem.setOnAction(e -> sourceEditorController.showAuxclasspathSetupPopup(designerRoot)); + setupAuxclasspathMenuItem.setOnAction(e -> sourceEditorController.showAuxclasspathSetupPopup()); openEventLogMenuItem.setOnAction(e -> eventLogController.getValue().showPopup()); openEventLogMenuItem.textProperty().bind( @@ -163,12 +153,12 @@ public class MainDesignerController extends AbstractController implements Compos // the xpath panel is forwarded to the treeView, which // forwards back an event, etc. getSelectionEvents().thenIgnoreFor(Duration.ofMillis(20)) - .subscribe(n -> CompositeSelectionSource.super.select(n)); + .subscribe(n -> CompositeSelectionSource.super.bubbleDown(n)); } @Override - public ObservableSet getComponents() { + public ObservableSet getSubSelectionSources() { return FXCollections.observableSet(nodeInfoPanelController, sourceEditorController, xpathPanelController); } @@ -298,7 +288,7 @@ public class MainDesignerController extends AbstractController implements Compos private void onOpenFileClicked() { FileChooser chooser = new FileChooser(); chooser.setTitle("Load source from file"); - File file = chooser.showOpenDialog(designerRoot.getMainStage()); + File file = chooser.showOpenDialog(getMainStage()); loadSourceFromFile(file); } @@ -396,13 +386,13 @@ public class MainDesignerController extends AbstractController implements Compos @PersistentProperty public boolean isMaximized() { - return designerRoot.getMainStage().isMaximized(); + return getMainStage().isMaximized(); } public void setMaximized(boolean b) { - designerRoot.getMainStage().setMaximized(!b); // trigger change listener anyway - designerRoot.getMainStage().setMaximized(b); + getMainStage().setMaximized(!b); // trigger change listener anyway + getMainStage().setMaximized(b); } @@ -420,7 +410,7 @@ public class MainDesignerController extends AbstractController implements Compos @Override - public List getChildren() { + public List> getChildren() { return Arrays.asList(xpathPanelController, sourceEditorController, nodeInfoPanelController); } diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/NodeInfoPanelController.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/NodeInfoPanelController.java index 4a22aed56b..ac2b33ae73 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/NodeInfoPanelController.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/NodeInfoPanelController.java @@ -30,8 +30,8 @@ import net.sourceforge.pmd.lang.symboltable.NameOccurrence; import net.sourceforge.pmd.lang.symboltable.Scope; import net.sourceforge.pmd.lang.symboltable.ScopedNode; import net.sourceforge.pmd.util.fxdesigner.model.MetricResult; -import net.sourceforge.pmd.util.fxdesigner.util.AbstractController; -import net.sourceforge.pmd.util.fxdesigner.util.NodeSelectionSource; +import net.sourceforge.pmd.util.fxdesigner.app.AbstractController; +import net.sourceforge.pmd.util.fxdesigner.app.NodeSelectionSource; import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsPersistenceUtil.PersistentProperty; import net.sourceforge.pmd.util.fxdesigner.util.controls.ScopeHierarchyTreeCell; import net.sourceforge.pmd.util.fxdesigner.util.controls.ScopeHierarchyTreeItem; @@ -57,9 +57,8 @@ import javafx.scene.control.TreeView; * @since 6.0.0 */ @SuppressWarnings("PMD.UnusedPrivateField") -public class NodeInfoPanelController extends AbstractController implements NodeSelectionSource { +public class NodeInfoPanelController extends AbstractController implements NodeSelectionSource { - private final MainDesignerController parent; /** List of attribute names that are ignored if {@link #isHideCommonAttributes()} is true. */ private static final List IGNORABLE_ATTRIBUTES = @@ -85,15 +84,10 @@ public class NodeInfoPanelController extends AbstractController implements NodeS private Node selectedNode; public NodeInfoPanelController(MainDesignerController mainController) { - parent = mainController; + super(mainController); } - @Override - public DesignerRoot getDesignerRoot() { - return parent.getDesignerRoot(); - } - @Override protected void beforeParentInit() { diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/SourceEditorController.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/SourceEditorController.java index 7e2e2508ca..c4c8891d2d 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/SourceEditorController.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/SourceEditorController.java @@ -32,10 +32,10 @@ import net.sourceforge.pmd.util.ClasspathClassLoader; import net.sourceforge.pmd.util.fxdesigner.model.ASTManager; import net.sourceforge.pmd.util.fxdesigner.model.ParseAbortedException; import net.sourceforge.pmd.util.fxdesigner.popups.AuxclasspathSetupController; -import net.sourceforge.pmd.util.fxdesigner.util.AbstractController; -import net.sourceforge.pmd.util.fxdesigner.util.CompositeSelectionSource; +import net.sourceforge.pmd.util.fxdesigner.app.AbstractController; +import net.sourceforge.pmd.util.fxdesigner.app.CompositeSelectionSource; import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil; -import net.sourceforge.pmd.util.fxdesigner.util.NodeSelectionSource; +import net.sourceforge.pmd.util.fxdesigner.app.NodeSelectionSource; import net.sourceforge.pmd.util.fxdesigner.util.TextAwareNodeWrapper; import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsPersistenceUtil.PersistentProperty; import net.sourceforge.pmd.util.fxdesigner.util.codearea.AvailableSyntaxHighlighters; @@ -62,7 +62,7 @@ import javafx.scene.control.ToggleGroup; * @author Clément Fournier * @since 6.0.0 */ -public class SourceEditorController extends AbstractController implements CompositeSelectionSource { +public class SourceEditorController extends AbstractController implements CompositeSelectionSource { private static final Duration AST_REFRESH_DELAY = Duration.ofMillis(100); @@ -81,8 +81,6 @@ public class SourceEditorController extends AbstractController implements Compos private final ASTManager astManager; - private final MainDesignerController parent; - private final Var currentFocusNode = Var.newSimpleVar(null); private final Var> auxclasspathFiles = Var.newSimpleVar(emptyList()); @@ -99,18 +97,12 @@ public class SourceEditorController extends AbstractController implements Compos public SourceEditorController(MainDesignerController mainController) { - parent = mainController; + super(mainController); astManager = new ASTManager(mainController.getDesignerRoot()); } - @Override - public DesignerRoot getDesignerRoot() { - return parent.getDesignerRoot(); - } - - @Override protected void beforeParentInit() { @@ -200,7 +192,7 @@ public class SourceEditorController extends AbstractController implements Compos @Override - public ObservableSet getComponents() { + public ObservableSet getSubSelectionSources() { return FXCollections.observableSet(astTreeView, focusNodeParentageCrumbBar); } @@ -230,10 +222,9 @@ public class SourceEditorController extends AbstractController implements Compos } - public void showAuxclasspathSetupPopup(DesignerRoot root) { - new AuxclasspathSetupController(root).show(root.getMainStage(), - auxclasspathFiles.getValue(), - auxclasspathFiles::setValue); + public void showAuxclasspathSetupPopup() { + new AuxclasspathSetupController(getDesignerRoot()) + .show(getMainStage(), auxclasspathFiles.getValue(), auxclasspathFiles::setValue); } private void setUpToDateCompilationUnit(Node node) { diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/XPathPanelController.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/XPathPanelController.java index 12b06ee9b7..5b14cfc860 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/XPathPanelController.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/XPathPanelController.java @@ -27,14 +27,14 @@ import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.rule.XPathRule; import net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery; -import net.sourceforge.pmd.util.fxdesigner.model.LogEntry.Category; +import net.sourceforge.pmd.util.fxdesigner.app.LogEntry.Category; import net.sourceforge.pmd.util.fxdesigner.model.ObservableXPathRuleBuilder; import net.sourceforge.pmd.util.fxdesigner.model.XPathEvaluationException; import net.sourceforge.pmd.util.fxdesigner.model.XPathEvaluator; import net.sourceforge.pmd.util.fxdesigner.popups.ExportXPathWizardController; -import net.sourceforge.pmd.util.fxdesigner.util.AbstractController; +import net.sourceforge.pmd.util.fxdesigner.app.AbstractController; import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil; -import net.sourceforge.pmd.util.fxdesigner.util.NodeSelectionSource; +import net.sourceforge.pmd.util.fxdesigner.app.NodeSelectionSource; import net.sourceforge.pmd.util.fxdesigner.util.TextAwareNodeWrapper; import net.sourceforge.pmd.util.fxdesigner.util.autocomplete.CompletionResultSource; import net.sourceforge.pmd.util.fxdesigner.util.autocomplete.XPathAutocompleteProvider; @@ -75,10 +75,9 @@ import javafx.stage.StageStyle; * @see ExportXPathWizardController * @since 6.0.0 */ -public class XPathPanelController extends AbstractController implements NodeSelectionSource { +public class XPathPanelController extends AbstractController implements NodeSelectionSource { private static final Duration XPATH_REFRESH_DELAY = Duration.ofMillis(100); - private final MainDesignerController parent; private final XPathEvaluator xpathEvaluator = new XPathEvaluator(); private final ObservableXPathRuleBuilder ruleBuilder = new ObservableXPathRuleBuilder(); @@ -103,16 +102,11 @@ public class XPathPanelController extends AbstractController implements NodeSele public XPathPanelController(MainDesignerController mainController) { - parent = mainController; + super(mainController); getRuleBuilder().setClazz(XPathRule.class); } - @Override - public DesignerRoot getDesignerRoot() { - return parent.getDesignerRoot(); - } - @Override protected void beforeParentInit() { xpathExpressionArea.setSyntaxHighlighter(new XPathSyntaxHighlighter()); diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/AbstractController.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/AbstractController.java similarity index 51% rename from pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/AbstractController.java rename to pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/AbstractController.java index b7143b744c..08fa047abb 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/AbstractController.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/AbstractController.java @@ -2,7 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.util.fxdesigner.util; +package net.sourceforge.pmd.util.fxdesigner.app; import java.net.URL; import java.util.Collections; @@ -16,24 +16,62 @@ import javafx.fxml.Initializable; /** - * Make the initialization cycle of JavaFX clearer. Children controller - * are initialized before their parent, but sometimes it should only + * Base class for controllers of the app. The main window of the app is split + * into regions corresponding to some area of functionality. Each has its own + * FXML file that can be found in the fxml resource directory. Each also has + * its own independent controller. Since the FXML regions are nested like a + * tree (the JavaFX scene graph), it's natural to link the controllers in a + * tree too. + * + *

For now controllers mostly communicate by sending messages to their parent + * and letting it forward the message to the rest of the app. TODO I'm more and more + * convinced we should avoid that and stop having the controllers hold a reference + * to their parent. They should only communicate by exposing properties their parent + * binds to, but they shouldn't know about their parent. + * + *

This class mainly to make the initialization cycle of JavaFX clearer. Children controllers + * are initialized before their parent, but sometimes they should only * perform some actions after its parent has been initialized, e.g. binding * properties that depend on a restored setting or stuff. This is part * of the reason why {@link Platform#runLater(Runnable)} can sometimes * be enough to solve initialization problems. * - * This only works if all controllers in the tree extend this class. + *

This only works if all controllers in the initialization sequence of an + * FXML file extend this class. + * + * + * @param Type of the parent controller * * @author Clément Fournier * @since 7.0.0 */ -public abstract class AbstractController implements Initializable, SettingsOwner, ApplicationComponent { +public abstract class AbstractController> implements Initializable, SettingsOwner, ApplicationComponent { + + protected final T parent; + private final DesignerRoot designerRoot; + + + protected AbstractController(DesignerRoot root, T parent) { + this.parent = parent; + this.designerRoot = root; + } + + + protected AbstractController(T parent) { + this(parent.getDesignerRoot(), parent); + } + + + @Override + public DesignerRoot getDesignerRoot() { + return designerRoot; + } + @Override public final void initialize(URL url, ResourceBundle resourceBundle) { beforeParentInit(); - for (AbstractController child : getChildren()) { + for (AbstractController child : getChildren()) { child.afterParentInit(); } afterChildrenInit(); @@ -76,7 +114,7 @@ public abstract class AbstractController implements Initializable, SettingsOwner } - protected List getChildren() { + protected List> getChildren() { return Collections.emptyList(); } } diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/ApplicationComponent.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/ApplicationComponent.java new file mode 100644 index 0000000000..0eb91e1ee0 --- /dev/null +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/ApplicationComponent.java @@ -0,0 +1,130 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.fxdesigner.app; + +import java.util.function.Supplier; + +import net.sourceforge.pmd.util.fxdesigner.SourceEditorController; +import net.sourceforge.pmd.util.fxdesigner.app.LogEntry.Category; +import net.sourceforge.pmd.util.fxdesigner.app.NodeSelectionSource.NodeSelectionEvent; +import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsOwner; +import net.sourceforge.pmd.util.fxdesigner.util.controls.AstTreeView; + +import javafx.scene.control.Control; +import javafx.stage.Stage; + + +/** + * Some part of the application, e.g. a controller. Components in an instance of the app are all linked + * to the same {@link DesignerRoot}, which hosts utilities globally available to the app, e.g. the logger. + * + *

Components that are not controllers, e.g. {@link Control}s, should be injected with the designer + * root at initialization time, eg what {@link SourceEditorController} does with {@link AstTreeView}. + * + *

Some more specific cross-cutting structures for the internals of the app are the {@link SettingsOwner} + * tree, which is more or less identical to the {@link AbstractController} tree. {@link NodeSelectionSource}s + * form yet another similar tree of related components. + * + * @author Clément Fournier + */ +public interface ApplicationComponent { + + + DesignerRoot getDesignerRoot(); + + + /** + * A debug name for this component, used in developer mode to e.g. trace events + * handling paths. + */ + default String getDebugName() { + return getClass().getSimpleName(); + } + + + /** + * Gets the logger of the application. Events pushed to the logger + * are filtered then forwarded to the Event Log control. + * + * @return The logger + */ + default EventLogger getLogger() { + return getDesignerRoot().getLogger(); + } + + + /** + * Gets the main stage of the application. + */ + default Stage getMainStage() { + return getDesignerRoot().getMainStage(); + } + + + /** + * If true, some more events are pushed to the event log, and + * console streams are open. This is enabled by the -v or --verbose + * option on command line for now. + */ + default boolean isDeveloperMode() { + return getDesignerRoot().isDeveloperMode(); + } + + + /** + * Notify the logger of an exception that somewhere in PMD logic. Exceptions raised + * by the app logic are considered internal and should be forwarded to the logger + * using {@link #logInternalException(Throwable)}. If we're not in developer mode + * they will be ignored. + */ + default void logUserException(Throwable throwable, Category category) { + getLogger().logEvent(LogEntry.createUserExceptionEntry(throwable, category)); + } + + + /** + * Notify the logger that XPath parsing succeeded and that the last recent failure may be thrown away. + * Only logged in developer mode. + */ + default void raiseParsableXPathFlag() { + getLogger().logEvent(LogEntry.createUserFlagEntry(Category.XPATH_OK)); + } + + + /** + * Notify the logger that source code parsing succeeded and that the last recent failure may be thrown away. + * Only logged in developer mode. + */ + default void raiseParsableSourceFlag() { + getLogger().logEvent(LogEntry.createUserFlagEntry(Category.PARSE_OK)); + } + + // Internal log handlers + + + /** Logs an exception that occurred somewhere in the app logic. */ + default void logInternalException(Throwable throwable) { + if (isDeveloperMode()) { + getLogger().logEvent(LogEntry.createInternalExceptionEntry(throwable)); + } + } + + + /** Logs an exception that occurred somewhere in the app logic. */ + default void logInternalDebugInfo(Supplier shortMessage, Supplier details) { + if (isDeveloperMode()) { + getLogger().logEvent(LogEntry.createInternalDebugEntry(shortMessage.get(), details.get())); + } + } + + + /** Logs a tracing event pushed by a {@link NodeSelectionSource}. */ + default void logSelectionEventTrace(NodeSelectionEvent event, Supplier details) { + if (isDeveloperMode()) { + getLogger().logEvent(LogEntry.createNodeSelectionEventTraceEntry(event, details.get())); + } + } + +} diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/CompositeSelectionSource.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/CompositeSelectionSource.java similarity index 50% rename from pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/CompositeSelectionSource.java rename to pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/CompositeSelectionSource.java index df5db73a05..56fd0c7ce0 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/CompositeSelectionSource.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/CompositeSelectionSource.java @@ -2,7 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.util.fxdesigner.util; +package net.sourceforge.pmd.util.fxdesigner.app; import org.reactfx.EventStream; import org.reactfx.EventStreams; @@ -13,17 +13,20 @@ import javafx.collections.ObservableSet; /** + * A {@link NodeSelectionSource} that merges the events of several sub-components. Such a source + * can also handle events itself via {@link #setFocusNode(Node)}. + * * @author Clément Fournier */ public interface CompositeSelectionSource extends NodeSelectionSource { - - ObservableSet getComponents(); + /** Returns the sources to forward to when bubbling down, and from which to merge events when bubbling up. */ + ObservableSet getSubSelectionSources(); @Override default EventStream getSelectionEvents() { - return EventStreams.merge(getComponents(), NodeSelectionSource::getSelectionEvents); + return EventStreams.merge(getSubSelectionSources(), NodeSelectionSource::getSelectionEvents); } @@ -35,12 +38,12 @@ public interface CompositeSelectionSource extends NodeSelectionSource { @Override - default void select(NodeSelectionEvent selectionEvent) { - NodeSelectionSource.super.select(selectionEvent); + default void bubbleDown(NodeSelectionEvent selectionEvent) { + NodeSelectionSource.super.bubbleDown(selectionEvent); - for (NodeSelectionSource source : getComponents()) { + for (NodeSelectionSource source : getSubSelectionSources()) { logSelectionEventTrace(selectionEvent, () -> getDebugName() + " forwards to " + source.getDebugName()); - source.select(selectionEvent); + source.bubbleDown(selectionEvent); } } } diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/DesignerRoot.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/DesignerRoot.java similarity index 73% rename from pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/DesignerRoot.java rename to pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/DesignerRoot.java index 85ca0eb22d..61b94a6e5e 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/DesignerRoot.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/DesignerRoot.java @@ -2,9 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.util.fxdesigner; - -import net.sourceforge.pmd.util.fxdesigner.model.EventLogger; +package net.sourceforge.pmd.util.fxdesigner.app; import javafx.stage.Stage; @@ -19,13 +17,14 @@ public final class DesignerRoot { private final Stage mainStage; - private final EventLogger logger = new EventLogger(this); + private final EventLogger logger; private final boolean developerMode; public DesignerRoot(Stage mainStage, boolean developerMode) { this.mainStage = mainStage; this.developerMode = developerMode; + this.logger = new EventLogger(this); } @@ -49,6 +48,11 @@ public final class DesignerRoot { } + /** + * If true, some more events are pushed to the event log, and + * console streams are open. This is enabled by the -v or --verbose + * option on command line for now. + */ public boolean isDeveloperMode() { return developerMode; } diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/EventLogger.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/EventLogger.java similarity index 80% rename from pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/EventLogger.java rename to pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/EventLogger.java index 4b434c72e5..93a1580162 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/EventLogger.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/EventLogger.java @@ -2,13 +2,13 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.util.fxdesigner.model; +package net.sourceforge.pmd.util.fxdesigner.app; -import static net.sourceforge.pmd.util.fxdesigner.model.LogEntry.Category.PARSE_EXCEPTION; -import static net.sourceforge.pmd.util.fxdesigner.model.LogEntry.Category.PARSE_OK; -import static net.sourceforge.pmd.util.fxdesigner.model.LogEntry.Category.SELECTION_EVENT_TRACING; -import static net.sourceforge.pmd.util.fxdesigner.model.LogEntry.Category.XPATH_EVALUATION_EXCEPTION; -import static net.sourceforge.pmd.util.fxdesigner.model.LogEntry.Category.XPATH_OK; +import static net.sourceforge.pmd.util.fxdesigner.app.LogEntry.Category.PARSE_EXCEPTION; +import static net.sourceforge.pmd.util.fxdesigner.app.LogEntry.Category.PARSE_OK; +import static net.sourceforge.pmd.util.fxdesigner.app.LogEntry.Category.SELECTION_EVENT_TRACING; +import static net.sourceforge.pmd.util.fxdesigner.app.LogEntry.Category.XPATH_EVALUATION_EXCEPTION; +import static net.sourceforge.pmd.util.fxdesigner.app.LogEntry.Category.XPATH_OK; import static net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil.countNotMatching; import static net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil.reduceEntangledIfPossible; @@ -23,12 +23,13 @@ import org.reactfx.collection.LiveArrayList; import org.reactfx.collection.LiveList; import org.reactfx.value.Val; -import net.sourceforge.pmd.util.fxdesigner.DesignerRoot; -import net.sourceforge.pmd.util.fxdesigner.model.LogEntry.Category; -import net.sourceforge.pmd.util.fxdesigner.model.LogEntry.LogEntryWithData; -import net.sourceforge.pmd.util.fxdesigner.util.ApplicationComponent; +import net.sourceforge.pmd.util.fxdesigner.app.DesignerRoot; +import net.sourceforge.pmd.util.fxdesigner.app.LogEntry; +import net.sourceforge.pmd.util.fxdesigner.app.LogEntry.Category; +import net.sourceforge.pmd.util.fxdesigner.app.LogEntry.LogEntryWithData; +import net.sourceforge.pmd.util.fxdesigner.app.ApplicationComponent; import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil; -import net.sourceforge.pmd.util.fxdesigner.util.NodeSelectionSource.NodeSelectionEvent; +import net.sourceforge.pmd.util.fxdesigner.app.NodeSelectionSource.NodeSelectionEvent; /** @@ -51,7 +52,7 @@ public class EventLogger implements ApplicationComponent { public EventLogger(DesignerRoot designerRoot) { - this.designerRoot = designerRoot; + this.designerRoot = designerRoot; // we have to be careful with initialization order here EventStream> eventTraces = reduceEntangledIfPossible(filterOnCategory(latestEvent, false, SELECTION_EVENT_TRACING).map(t -> (LogEntryWithData) t), diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/LogEntry.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/LogEntry.java similarity index 95% rename from pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/LogEntry.java rename to pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/LogEntry.java index 278cac5e0a..cc399e7bf2 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/LogEntry.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/LogEntry.java @@ -2,17 +2,16 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.util.fxdesigner.model; +package net.sourceforge.pmd.util.fxdesigner.app; -import static net.sourceforge.pmd.util.fxdesigner.model.LogEntry.Category.CategoryType.FLAG; +import static net.sourceforge.pmd.util.fxdesigner.app.LogEntry.Category.CategoryType.FLAG; -import java.time.Instant; import java.util.Date; import org.apache.commons.lang3.exception.ExceptionUtils; import org.reactfx.value.Var; -import net.sourceforge.pmd.util.fxdesigner.util.NodeSelectionSource.NodeSelectionEvent; +import net.sourceforge.pmd.util.fxdesigner.app.NodeSelectionSource.NodeSelectionEvent; /** diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/NodeSelectionSource.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/NodeSelectionSource.java similarity index 53% rename from pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/NodeSelectionSource.java rename to pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/NodeSelectionSource.java index 4361ee7e4d..8ec615df95 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/NodeSelectionSource.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/NodeSelectionSource.java @@ -2,7 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.util.fxdesigner.util; +package net.sourceforge.pmd.util.fxdesigner.app; import java.util.Objects; @@ -10,28 +10,42 @@ import org.reactfx.EventStream; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.util.fxdesigner.MainDesignerController; +import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsOwner; import net.sourceforge.pmd.util.fxdesigner.util.controls.AstTreeView; import net.sourceforge.pmd.util.fxdesigner.util.controls.NodeParentageCrumbBar; /** - * A control or controller that has the ability to push node selection events. - * When a node is selected in the control (e.g. {@link AstTreeView}, {@link NodeParentageCrumbBar}, etc), - * the whole UI is synchronized to the node. Selection events are merged iteratively into - * a global stream for the whole app. Events from that stream are handled by {@link MainDesignerController}. + * A control or controller that somehow displays nodes in a form that the user can select. + * When a node is selected by the user (e.g. {@link AstTreeView}, {@link NodeParentageCrumbBar}, etc), + * the whole UI is synchronized to reflect information about the node. This includes scrolling + * the TreeView, the editor, etc. To achieve that uniformly, node selection events are merged + * into a global stream for the whole app. Events from that stream are handled by {@link MainDesignerController}. + * + *

Node selection sources form a tree parallel to {@link AbstractController} and {@link SettingsOwner}. + * This interface implements behaviour for leaves of the tree. Inner nodes are handled by + * {@link CompositeSelectionSource}. * * @author Clément Fournier */ public interface NodeSelectionSource extends ApplicationComponent { /** - * Returns a stream of nodes that pushes an event every time - * this control records a *user* change in selection. + * Returns a stream of events that should push an event each time + * this source or one of its sub components records a change in node + * selection. */ EventStream getSelectionEvents(); - default void select(NodeSelectionEvent selectionEvent) { + /** + * Bubbles a selection event down the tree. First, {@link #setFocusNode(Node)} is called to + * handle the event (if the event didn't originate from here). If this is not a leaf of the tree, + * then the event is forwarded to the children nodes as well. + * + * @param selectionEvent Event to handle + */ + default void bubbleDown(NodeSelectionEvent selectionEvent) { if (alwaysHandleSelection() || selectionEvent.getOrigin() != this) { logSelectionEventTrace(selectionEvent, () -> "\t" + this.getDebugName() + " is handling event"); setFocusNode(selectionEvent.getSelection()); @@ -39,14 +53,24 @@ public interface NodeSelectionSource extends ApplicationComponent { } + /** + * Updates the UI to react to a change in focus node. This is called whenever some selection source + * in the tree records a change. The event is not forwarded to its origin unless {@link #alwaysHandleSelection()} + * is overridden to return true. + */ void setFocusNode(Node node); + /** Whether to also handle events which originated from this controller. */ default boolean alwaysHandleSelection() { return false; } + /** + * An event fired when the user selects a node somewhere in the UI + * and bubbled up to the {@link MainDesignerController}. + */ final class NodeSelectionEvent { private final Node selection; diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/package-info.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/package-info.java new file mode 100644 index 0000000000..1ad5fbe310 --- /dev/null +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/app/package-info.java @@ -0,0 +1,8 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +/** + * Interfaces and base classes that structure an support the whole app. + */ +package net.sourceforge.pmd.util.fxdesigner.app; \ No newline at end of file diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/ASTManager.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/ASTManager.java index 0c6b8fba5d..9c20b74595 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/ASTManager.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/ASTManager.java @@ -15,13 +15,14 @@ import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.LanguageVersionHandler; import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.util.fxdesigner.DesignerRoot; -import net.sourceforge.pmd.util.fxdesigner.model.LogEntry.Category; -import net.sourceforge.pmd.util.fxdesigner.util.ApplicationComponent; +import net.sourceforge.pmd.util.fxdesigner.SourceEditorController; +import net.sourceforge.pmd.util.fxdesigner.app.DesignerRoot; +import net.sourceforge.pmd.util.fxdesigner.app.LogEntry.Category; +import net.sourceforge.pmd.util.fxdesigner.app.ApplicationComponent; /** - * Main class of the model. Manages a compilation unit. + * Manages a compilation unit for {@link SourceEditorController}. * * @author Clément Fournier * @since 6.0.0 diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/MetricResult.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/MetricResult.java index 34b86828e1..7ac9baf03a 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/MetricResult.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/MetricResult.java @@ -5,7 +5,6 @@ package net.sourceforge.pmd.util.fxdesigner.model; import java.util.AbstractMap.SimpleEntry; -import java.util.Map.Entry; import net.sourceforge.pmd.lang.metrics.MetricKey; @@ -23,11 +22,6 @@ public class MetricResult { } - MetricResult(Entry, ? extends Double> entry) { - simpleEntry = new SimpleEntry<>(entry); - } - - public MetricKey getKey() { return simpleEntry.getKey(); } diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/ObservableRuleBuilder.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/ObservableRuleBuilder.java index 9f7d3f0f01..1f61e4ac4a 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/ObservableRuleBuilder.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/ObservableRuleBuilder.java @@ -15,7 +15,6 @@ import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.rules.RuleBuilder; -import net.sourceforge.pmd.util.fxdesigner.util.PropertyDescriptorSpec; import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsOwner; import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsPersistenceUtil.PersistentProperty; import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsPersistenceUtil.PersistentSequence; diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/PropertyDescriptorSpec.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/PropertyDescriptorSpec.java similarity index 99% rename from pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/PropertyDescriptorSpec.java rename to pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/PropertyDescriptorSpec.java index 4170667907..73eb92efb7 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/PropertyDescriptorSpec.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/PropertyDescriptorSpec.java @@ -2,7 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.util.fxdesigner.util; +package net.sourceforge.pmd.util.fxdesigner.model; import java.util.HashMap; diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/XPathEvaluator.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/XPathEvaluator.java index 338b1b939d..63c1138a98 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/XPathEvaluator.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/model/XPathEvaluator.java @@ -19,7 +19,6 @@ import net.sourceforge.pmd.RuleSets; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.rule.XPathRule; -import net.sourceforge.pmd.util.fxdesigner.util.PropertyDescriptorSpec; /** diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/package-info.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/package-info.java new file mode 100644 index 0000000000..8059768093 --- /dev/null +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/package-info.java @@ -0,0 +1,10 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +/** + * PMD's rule designer. A good starting point to learn about the global structure of the app + * is {@link net.sourceforge.pmd.util.fxdesigner.app.ApplicationComponent}, and + * {@link net.sourceforge.pmd.util.fxdesigner.app.AbstractController}. + */ +package net.sourceforge.pmd.util.fxdesigner; diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/AuxclasspathSetupController.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/AuxclasspathSetupController.java index b1db2b5f8f..63f2df0c5c 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/AuxclasspathSetupController.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/AuxclasspathSetupController.java @@ -15,7 +15,7 @@ import java.util.function.Consumer; import org.reactfx.collection.LiveList; import org.reactfx.value.Val; -import net.sourceforge.pmd.util.fxdesigner.DesignerRoot; +import net.sourceforge.pmd.util.fxdesigner.app.DesignerRoot; import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil; import javafx.beans.binding.Bindings; diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/EditPropertyDialogController.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/EditPropertyDialogController.java index 8637b9221f..8d1047bb2a 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/EditPropertyDialogController.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/EditPropertyDialogController.java @@ -22,7 +22,7 @@ import net.sourceforge.pmd.properties.PropertyTypeId; import net.sourceforge.pmd.properties.ValueParser; import net.sourceforge.pmd.properties.ValueParserConstants; import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil; -import net.sourceforge.pmd.util.fxdesigner.util.PropertyDescriptorSpec; +import net.sourceforge.pmd.util.fxdesigner.model.PropertyDescriptorSpec; import net.sourceforge.pmd.util.fxdesigner.util.controls.PropertyTableView; import javafx.application.Platform; diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/EventLogController.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/EventLogController.java index a7b9e1381c..a985c90ccc 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/EventLogController.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/EventLogController.java @@ -19,11 +19,11 @@ import org.reactfx.value.Val; import org.reactfx.value.Var; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.util.fxdesigner.DesignerRoot; import net.sourceforge.pmd.util.fxdesigner.MainDesignerController; -import net.sourceforge.pmd.util.fxdesigner.model.LogEntry; -import net.sourceforge.pmd.util.fxdesigner.model.LogEntry.Category; -import net.sourceforge.pmd.util.fxdesigner.util.AbstractController; +import net.sourceforge.pmd.util.fxdesigner.app.EventLogger; +import net.sourceforge.pmd.util.fxdesigner.app.LogEntry; +import net.sourceforge.pmd.util.fxdesigner.app.LogEntry.Category; +import net.sourceforge.pmd.util.fxdesigner.app.AbstractController; import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil; import javafx.beans.property.SimpleObjectProperty; @@ -47,20 +47,17 @@ import javafx.stage.Stage; /** - * A presenter over the {@link net.sourceforge.pmd.util.fxdesigner.model.EventLogger}. + * A presenter over the {@link EventLogger}. * There's not necessarily one in the app, it can be garbage collected and recreated. * Each of these necessarily has a live UI component though. * * @author Clément Fournier * @since 6.0.0 */ -public final class EventLogController extends AbstractController { +public final class EventLogController extends AbstractController { private static final PseudoClass NEW_ENTRY = PseudoClass.getPseudoClass("new-entry"); - private final DesignerRoot designerRoot; - private final MainDesignerController mediator; - @FXML private TableView eventLogTableView; @FXML @@ -82,18 +79,12 @@ public final class EventLogController extends AbstractController { public EventLogController(MainDesignerController mediator) { - this.designerRoot = mediator.getDesignerRoot(); - this.mediator = mediator; + super(mediator); // the FXML fields are injected and initialize is called in createStage - this.myPopupStage = createStage(designerRoot.getMainStage()); + this.myPopupStage = createStage(getMainStage()); } - @Override - public DesignerRoot getDesignerRoot() { - return designerRoot; - } - // this is only called each time a popup is created @Override @@ -193,18 +184,18 @@ public final class EventLogController extends AbstractController { .successionEnds(Duration.ofMillis(100)) .subscribe(b -> { if (b) { - mediator.handleSelectedNodeInError(selectedErrorNodes.getValue()); + parent.handleSelectedNodeInError(selectedErrorNodes.getValue()); } else { - mediator.resetSelectedErrorNodes(); + parent.resetSelectedErrorNodes(); } }) ); binding = binding.and( - selectedErrorNodes.values().subscribe(mediator::handleSelectedNodeInError) + selectedErrorNodes.values().subscribe(parent::handleSelectedNodeInError) ); - SortedList logEntries = new SortedList<>(designerRoot.getLogger().getLog(), Comparator.reverseOrder()); + SortedList logEntries = new SortedList<>(getLogger().getLog(), Comparator.reverseOrder()); eventLogTableView.itemsProperty().setValue(logEntries); binding = binding.and( () -> eventLogTableView.itemsProperty().setValue(FXCollections.emptyObservableList()) @@ -228,7 +219,7 @@ public final class EventLogController extends AbstractController { entry.setExamined(true); if (entry.getCategory().isUserException()) { - DesignerUtil.stackTraceToXPath(entry.getDetails()).map(mediator::runXPathQuery).ifPresent(selectedErrorNodes::setValue); + DesignerUtil.stackTraceToXPath(entry.getDetails()).map(parent::runXPathQuery).ifPresent(selectedErrorNodes::setValue); } } @@ -254,7 +245,7 @@ public final class EventLogController extends AbstractController { private Val titleProperty() { - return designerRoot.getLogger().numNewLogEntriesProperty().map(i -> "Exception log (" + (i > 0 ? i : "no") + " new)"); + return parent.getLogger().numNewLogEntriesProperty().map(i -> "Exception log (" + (i > 0 ? i : "no") + " new)"); } diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/ApplicationComponent.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/ApplicationComponent.java deleted file mode 100644 index dbd2ce5cfa..0000000000 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/ApplicationComponent.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util.fxdesigner.util; - -import java.util.function.Supplier; - -import net.sourceforge.pmd.util.fxdesigner.DesignerRoot; -import net.sourceforge.pmd.util.fxdesigner.model.EventLogger; -import net.sourceforge.pmd.util.fxdesigner.model.LogEntry; -import net.sourceforge.pmd.util.fxdesigner.model.LogEntry.Category; -import net.sourceforge.pmd.util.fxdesigner.util.NodeSelectionSource.NodeSelectionEvent; - - -/** - * Some part of the application, linked to the {@link DesignerRoot}. - * - * @author Clément Fournier - */ -public interface ApplicationComponent { - - - DesignerRoot getDesignerRoot(); - - - default String getDebugName() { - return getClass().getSimpleName(); - } - - - default EventLogger getLogger() { - return getDesignerRoot().getLogger(); - } - - - default boolean isDeveloperMode() { - return getDesignerRoot().isDeveloperMode(); - } - - - default void logUserException(Throwable throwable, Category category) { - getLogger().logEvent(LogEntry.createUserExceptionEntry(throwable, category)); - } - - - default void raiseParsableXPathFlag() { - getLogger().logEvent(LogEntry.createUserFlagEntry(Category.XPATH_OK)); - } - - - default void raiseParsableSourceFlag() { - getLogger().logEvent(LogEntry.createUserFlagEntry(Category.PARSE_OK)); - } - - // Internal log handlers - - - default void logInternalException(Throwable throwable) { - if (isDeveloperMode()) { - getLogger().logEvent(LogEntry.createInternalExceptionEntry(throwable)); - } - } - - - default void logInternalDebugInfo(Supplier shortMessage, Supplier details) { - if (isDeveloperMode()) { - getLogger().logEvent(LogEntry.createInternalDebugEntry(shortMessage.get(), details.get())); - } - } - - - default void logSelectionEventTrace(NodeSelectionEvent event, Supplier details) { - if (isDeveloperMode()) { - getLogger().logEvent(LogEntry.createNodeSelectionEventTraceEntry(event, details.get())); - } - } - -} diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/controls/AstTreeView.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/controls/AstTreeView.java index 99a2f2b84d..e9b16262df 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/controls/AstTreeView.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/controls/AstTreeView.java @@ -18,8 +18,8 @@ import org.reactfx.SuspendableEventStream; import org.reactfx.value.Var; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.util.fxdesigner.DesignerRoot; -import net.sourceforge.pmd.util.fxdesigner.util.NodeSelectionSource; +import net.sourceforge.pmd.util.fxdesigner.app.DesignerRoot; +import net.sourceforge.pmd.util.fxdesigner.app.NodeSelectionSource; import javafx.scene.control.SelectionModel; import javafx.scene.control.TreeItem; diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/controls/NodeParentageCrumbBar.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/controls/NodeParentageCrumbBar.java index 224c8c42a5..10f26dd89c 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/controls/NodeParentageCrumbBar.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/controls/NodeParentageCrumbBar.java @@ -17,8 +17,8 @@ import org.reactfx.EventStream; import org.reactfx.value.Val; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.util.fxdesigner.DesignerRoot; -import net.sourceforge.pmd.util.fxdesigner.util.NodeSelectionSource; +import net.sourceforge.pmd.util.fxdesigner.app.DesignerRoot; +import net.sourceforge.pmd.util.fxdesigner.app.NodeSelectionSource; import javafx.application.Platform; import javafx.css.PseudoClass; diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/controls/PropertyTableView.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/controls/PropertyTableView.java index 669df9bb50..81c6d36c08 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/controls/PropertyTableView.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/controls/PropertyTableView.java @@ -13,7 +13,7 @@ import org.reactfx.value.Var; import net.sourceforge.pmd.properties.PropertyTypeId; import net.sourceforge.pmd.util.fxdesigner.popups.EditPropertyDialogController; import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil; -import net.sourceforge.pmd.util.fxdesigner.util.PropertyDescriptorSpec; +import net.sourceforge.pmd.util.fxdesigner.model.PropertyDescriptorSpec; import net.sourceforge.pmd.util.fxdesigner.util.SoftReferenceCache; import javafx.application.Platform;