diff --git a/pmd-ui/pom.xml b/pmd-ui/pom.xml index 047796f660..8dea8dd2cc 100644 --- a/pmd-ui/pom.xml +++ b/pmd-ui/pom.xml @@ -66,6 +66,20 @@ commons-beanutils-core 1.8.3 + + + + org.kordamp.ikonli + ikonli-javafx + 2.3.0 + + + org.kordamp.ikonli + ikonli-fontawesome-pack + 2.3.0 + + + net.sourceforge.pmd pmd-apex diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/AuxClassPathController.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/AuxClassPathController.java deleted file mode 100644 index 059dc3b21a..0000000000 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/AuxClassPathController.java +++ /dev/null @@ -1,143 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - - -package net.sourceforge.pmd.util.fxdesigner; - -import java.io.File; -import java.net.URL; -import java.util.List; -import java.util.ResourceBundle; -import java.util.function.Consumer; - -import org.reactfx.value.Var; - -import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsOwner; - -import javafx.collections.FXCollections; -import javafx.fxml.FXML; -import javafx.fxml.Initializable; -import javafx.scene.control.Button; -import javafx.scene.control.ListView; -import javafx.stage.FileChooser; - -public class AuxClassPathController implements Initializable, SettingsOwner { - - private final DesignerRoot designerRoot; - - private final Var onCancel = Var.newSimpleVar(() -> {}); - private final Var>> onApply = Var.newSimpleVar(l -> {}); - - - @FXML - private Button removeFileButton; - @FXML - private Button selectFilesButton; - @FXML - private ListView fileListView = new ListView<>(); - @FXML - private Button moveItemUpButton; - @FXML - private Button moveItemDownButton; - @FXML - private Button setClassPathButton; - @FXML - private Button cancelButton; - - - public AuxClassPathController(DesignerRoot designerRoot) { - this.designerRoot = designerRoot; - } - - @Override - public void initialize(URL location, ResourceBundle resources) { - - - removeFileButton.disableProperty().bind(fileListView.getSelectionModel().selectedItemProperty().isNull()); - moveItemUpButton.disableProperty().bind(fileListView.getSelectionModel().selectedItemProperty().isNull()); - moveItemDownButton.disableProperty().bind(fileListView.getSelectionModel().selectedItemProperty().isNull()); - - - - selectFilesButton.setOnAction(e -> onSelectFileClicked()); - removeFileButton.setOnAction(e -> onRemoveFileClicked()); - setClassPathButton.setOnAction(e -> onApply.ifPresent(f -> f.accept(fileListView.getItems()))); - moveItemUpButton.setOnAction(e -> moveUp()); - moveItemDownButton.setOnAction(e -> moveDown()); - cancelButton.setOnAction(e -> onCancel.ifPresent(Runnable::run)); - - } - - - private void onSelectFileClicked() { - FileChooser chooser = new FileChooser(); - chooser.setTitle("Select Files"); - chooser.getExtensionFilters().addAll( - new FileChooser.ExtensionFilter("Java JARs", "*.jar"), - new FileChooser.ExtensionFilter("Java WARs", "*.war"), - new FileChooser.ExtensionFilter("Java EARs", "*.ear"), - new FileChooser.ExtensionFilter("Java class files", "*.class") - ); - List files = chooser.showOpenMultipleDialog(designerRoot.getMainStage()); - fileListView.getItems().addAll(files); - } - - - private void onRemoveFileClicked() { - File f = fileListView.getSelectionModel().getSelectedItem(); - fileListView.getItems().remove(f); - } - - - public void setAuxclasspathFiles(List lst) { - fileListView.setItems(FXCollections.observableArrayList(lst)); - } - - - public void setOnCancel(Runnable run) { - onCancel.setValue(run); - } - - - public void setOnApply(Consumer> onApply) { - this.onApply.setValue(onApply); - } - - - private void moveUp() { - moveItem(-1); - } - - - private void moveDown() { - moveItem(1); - } - - - public void moveItem(int direction) { - // Checking selected item - if (fileListView.getSelectionModel().getSelectedItem() == null) { - return; - } - - // Calculate new index using move direction - int newIndex = fileListView.getSelectionModel().getSelectedIndex() + direction; - - if (newIndex < 0 || newIndex >= fileListView.getItems().size()) { - return; - } - - File selected = fileListView.getSelectionModel().getSelectedItem(); - - // Removing removable element - fileListView.getItems().remove(selected); - // Insert it in new position - fileListView.getItems().add(newIndex, selected); - //Restore Selection - fileListView.scrollTo(newIndex); - fileListView.getSelectionModel().select(newIndex); - - } - -} 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 8d5e4a14cf..2d5a631ec5 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 @@ -164,13 +164,7 @@ public class MainDesignerController implements Initializable, SettingsOwner { } }); - setupAuxclasspathMenuItem.setOnAction(e -> { - try { - sourceEditorController.showAuxClassPathController(designerRoot); - } catch (Exception e1) { - e1.printStackTrace(); - } - }); + setupAuxclasspathMenuItem.setOnAction(e -> sourceEditorController.showAuxclasspathSetupPopup(designerRoot)); 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 86c434c448..8b69853754 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 @@ -30,7 +30,7 @@ import net.sourceforge.pmd.lang.ast.Node; 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.util.DesignerUtil; +import net.sourceforge.pmd.util.fxdesigner.popups.AuxclasspathSetupController; 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.codearea.AvailableSyntaxHighlighters; @@ -41,16 +41,11 @@ import net.sourceforge.pmd.util.fxdesigner.util.controls.ASTTreeItem; import net.sourceforge.pmd.util.fxdesigner.util.controls.TreeViewWrapper; import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; -import javafx.scene.Parent; -import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.control.SelectionModel; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeView; -import javafx.stage.Modality; -import javafx.stage.Stage; /** @@ -148,42 +143,10 @@ public class SourceEditorController implements Initializable, SettingsOwner { } - public void showAuxClassPathController(DesignerRoot root) { - AuxClassPathController auxClassPathController = new AuxClassPathController(root); - - FXMLLoader fxmlLoader = new FXMLLoader(DesignerUtil.getFxml("auxclasspath-setup-popup.fxml")); - - fxmlLoader.setControllerFactory(type -> { - if (type == AuxClassPathController.class) { - return auxClassPathController; - } else { - throw new IllegalStateException("Wrong controller!"); - } - }); - try { - Parent root1 = fxmlLoader.load(); - - auxClassPathController.setAuxclasspathFiles(auxclasspathFiles.getValue()); - - Stage stage = new Stage(); - stage.initOwner(root.getMainStage()); - stage.initModality(Modality.WINDOW_MODAL); - stage.setScene(new Scene(root1)); - stage.show(); - - auxClassPathController.setOnApply(files -> { - stage.close(); - auxclasspathFiles.setValue(files); - }); - - auxClassPathController.setOnCancel(stage::close); - - - } catch (IOException e) { - e.printStackTrace(); - } - - + public void showAuxclasspathSetupPopup(DesignerRoot root) { + new AuxclasspathSetupController(root).show(root.getMainStage(), + auxclasspathFiles.getValue(), + auxclasspathFiles::setValue); } 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 f9959b4062..8fbc7eb324 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 @@ -28,6 +28,7 @@ import net.sourceforge.pmd.util.fxdesigner.model.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.DesignerUtil; import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsOwner; import net.sourceforge.pmd.util.fxdesigner.util.beans.SettingsPersistenceUtil.PersistentProperty; 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 new file mode 100644 index 0000000000..91ddba00e9 --- /dev/null +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/AuxclasspathSetupController.java @@ -0,0 +1,176 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + + +package net.sourceforge.pmd.util.fxdesigner.popups; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.List; +import java.util.ResourceBundle; +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.util.DesignerUtil; + +import javafx.beans.binding.Bindings; +import javafx.beans.binding.BooleanBinding; +import javafx.beans.binding.IntegerBinding; +import javafx.collections.FXCollections; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.fxml.Initializable; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.ListView; +import javafx.stage.FileChooser; +import javafx.stage.Modality; +import javafx.stage.Stage; + + +public class AuxclasspathSetupController implements Initializable { + + private final DesignerRoot designerRoot; + + @FXML + private Button removeFileButton; + @FXML + private Button selectFilesButton; + @FXML + private ListView fileListView = new ListView<>(); + @FXML + private Button moveItemUpButton; + @FXML + private Button moveItemDownButton; + @FXML + private Button setClassPathButton; + @FXML + private Button cancelButton; + + + public AuxclasspathSetupController(DesignerRoot designerRoot) { + this.designerRoot = designerRoot; + } + + @Override + public void initialize(URL location, ResourceBundle resources) { + + BooleanBinding noSelection = fileListView.getSelectionModel().selectedItemProperty().isNull(); + + removeFileButton.disableProperty().bind(noSelection); + + moveItemUpButton.disableProperty().bind(noSelection.or(fileListView.getSelectionModel().selectedIndexProperty().isEqualTo(0))); + + + // we can't just map the val because we need an ObservableNumberValue + IntegerBinding lastIndexBinding = Bindings.createIntegerBinding(() -> fileListView.getItems().size() - 1, + Val.wrap(fileListView.itemsProperty()).flatMap(LiveList::sizeOf)); + + moveItemDownButton.disableProperty().bind(noSelection.or(fileListView.getSelectionModel().selectedIndexProperty().isEqualTo(lastIndexBinding))); + + fileListView.setCellFactory(DesignerUtil.simpleListCellFactory(File::getName, File::getAbsolutePath)); + + selectFilesButton.setOnAction(e -> onSelectFileClicked()); + removeFileButton.setOnAction(e -> onRemoveFileClicked()); + moveItemUpButton.setOnAction(e -> moveUp()); + moveItemDownButton.setOnAction(e -> moveDown()); + + } + + + private void onSelectFileClicked() { + FileChooser chooser = new FileChooser(); + chooser.setTitle("Add files to the auxilliary classpath"); + chooser.getExtensionFilters().addAll( + new FileChooser.ExtensionFilter("Java archives", "*.jar", "*.war", "*.ear"), + new FileChooser.ExtensionFilter("Java class files", "*.class") + ); + List files = chooser.showOpenMultipleDialog(designerRoot.getMainStage()); + fileListView.getItems().addAll(files); + } + + + private void onRemoveFileClicked() { + File f = fileListView.getSelectionModel().getSelectedItem(); + fileListView.getItems().remove(f); + } + + + private void moveUp() { + moveItem(-1); + } + + + private void moveDown() { + moveItem(1); + } + + + private void moveItem(int direction) { + // Checking selected item + if (fileListView.getSelectionModel().getSelectedItem() == null) { + return; + } + + // Calculate new index using move direction + int newIndex = fileListView.getSelectionModel().getSelectedIndex() + direction; + + if (newIndex < 0 || newIndex >= fileListView.getItems().size()) { + return; + } + + File selected = fileListView.getSelectionModel().getSelectedItem(); + + // Removing removable element + fileListView.getItems().remove(selected); + // Insert it in new position + fileListView.getItems().add(newIndex, selected); + //Restore Selection + fileListView.scrollTo(newIndex); + fileListView.getSelectionModel().select(newIndex); + + } + + + /** Displays the popup. */ + public void show(Stage parentStage, List currentItems, Consumer> onApply) { + + FXMLLoader fxmlLoader = new FXMLLoader(DesignerUtil.getFxml("auxclasspath-setup-popup.fxml")); + + fxmlLoader.setControllerFactory(type -> { + if (type == AuxclasspathSetupController.class) { + return this; + } else { + throw new IllegalStateException("Wrong controller!"); + } + }); + + Stage stage = new Stage(); + try { + stage.setScene(new Scene(fxmlLoader.load())); + } catch (IOException e) { + e.printStackTrace(); + return; + } + + fileListView.setItems(FXCollections.observableArrayList(currentItems)); + + stage.setTitle("Auxilliary classpath setup"); + stage.initOwner(parentStage); + stage.initModality(Modality.WINDOW_MODAL); + + setClassPathButton.setOnAction(e -> { + stage.close(); + onApply.accept(fileListView.getItems()); + }); + + cancelButton.setOnAction(e -> stage.close()); + + stage.show(); + } +} diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/EditPropertyDialogController.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/EditPropertyDialogController.java similarity index 99% rename from pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/EditPropertyDialogController.java rename to pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/EditPropertyDialogController.java index 05f37a9d1a..ae025478f4 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/EditPropertyDialogController.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/EditPropertyDialogController.java @@ -2,7 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.util.fxdesigner; +package net.sourceforge.pmd.util.fxdesigner.popups; import static net.sourceforge.pmd.properties.MultiValuePropertyDescriptor.DEFAULT_DELIMITER; import static net.sourceforge.pmd.properties.MultiValuePropertyDescriptor.DEFAULT_NUMERIC_DELIMITER; diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/ExportXPathWizardController.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/ExportXPathWizardController.java similarity index 99% rename from pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/ExportXPathWizardController.java rename to pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/ExportXPathWizardController.java index 51570ac3f6..b3327eca58 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/ExportXPathWizardController.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/popups/ExportXPathWizardController.java @@ -2,7 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.util.fxdesigner; +package net.sourceforge.pmd.util.fxdesigner.popups; import java.net.URL; import java.util.Map; diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/DesignerUtil.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/DesignerUtil.java index ee234a62ae..9d2395e107 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/DesignerUtil.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/DesignerUtil.java @@ -30,6 +30,10 @@ import net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery; import javafx.beans.property.Property; import javafx.beans.value.ObservableValue; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.control.Tooltip; +import javafx.util.Callback; import javafx.util.StringConverter; @@ -85,6 +89,25 @@ public final class DesignerUtil { } + public static Callback, ListCell> simpleListCellFactory(Function converter, Function toolTipMaker) { + return collection -> new ListCell() { + @Override + protected void updateItem(T item, boolean empty) { + super.updateItem(item, empty); + + if (empty || item == null) { + setText(null); + setGraphic(null); + Tooltip.uninstall(this, getTooltip()); + } else { + setText(converter.apply(item)); + Tooltip.install(this, new Tooltip(toolTipMaker.apply(item))); + } + } + }; + } + + public static StringConverter stringConverter(Function toString, Function fromString) { return new StringConverter() { @Override 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 79a2e4d608..3a03537398 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 @@ -12,7 +12,7 @@ import java.util.function.Consumer; import org.reactfx.value.Var; import net.sourceforge.pmd.properties.PropertyTypeId; -import net.sourceforge.pmd.util.fxdesigner.EditPropertyDialogController; +import net.sourceforge.pmd.util.fxdesigner.popups.EditPropertyDialogController; import net.sourceforge.pmd.util.fxdesigner.util.DesignerUtil; import net.sourceforge.pmd.util.fxdesigner.util.PropertyDescriptorSpec; diff --git a/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/css/designer.css b/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/css/designer.css index 0bff0a645e..602b8f7519 100644 --- a/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/css/designer.css +++ b/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/css/designer.css @@ -124,6 +124,11 @@ -fx-border-radius: 3; } +.button.icon-button { + -fx-pref-width: 20; + -fx-pref-height: 20; +} + .tool-bar .choice-box { -fx-background-color: derive(-fx-base, 10%); -fx-border-color: derive(-fx-base, -20%); diff --git a/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/fxml/auxclasspath-setup-popup.fxml b/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/fxml/auxclasspath-setup-popup.fxml index f66299513c..c3a773f04e 100644 --- a/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/fxml/auxclasspath-setup-popup.fxml +++ b/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/fxml/auxclasspath-setup-popup.fxml @@ -3,71 +3,96 @@ - - + + - - - - - - - - - - - - - - - - - - - - - + + - - - - + + + + + + + + + + + + + + + + + +