Skip to content

Commit

Permalink
Merge pull request #53 from DEIS-Tools/feature/project-search
Browse files Browse the repository at this point in the history
Feature: search through project with ctrl + f
  • Loading branch information
sillydan1 authored Dec 3, 2022
2 parents 13aed79 + b9c188c commit fba26c3
Show file tree
Hide file tree
Showing 15 changed files with 408 additions and 77 deletions.
8 changes: 3 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mainClassName = 'HUPPAAL'

allprojects {
group = 'dk.cs.aau.huppaal'
version = '1.3.1'
version = '1.4.0'
}

def getGitCommitSha = { ->
Expand Down Expand Up @@ -146,16 +146,14 @@ dependencies {
implementation group: 'org.kordamp.ikonli', name: 'ikonli-javafx', version: '12.3.1'
implementation group: 'com.google.code.gson', name: 'gson', version: '2.10'
implementation group: 'com.google.guava', name: 'guava', version: '31.1-jre'
implementation group: 'org.hildan.fxgson', name: 'fx-gson', version: '4.0.1'
implementation group: 'org.fxmisc.richtext', name: 'richtextfx', version: '0.10.9'
implementation group: 'org.hildan.fxgson', name: 'fx-gson', version: '4.1.0'
implementation group: 'org.fxmisc.richtext', name: 'richtextfx', version: '0.11.0'

implementation group: 'org.openjfx', name: 'javafx', version: '19'
implementation group: 'org.openjfx', name: 'javafx-graphics', version: '19'
implementation group: 'org.openjfx', name: 'javafx-controls', version: '19'
implementation group: 'org.openjfx', name: 'javafx-base', version: '19'

implementation group: 'org.fxmisc.richtext', name: 'richtextfx', version: '0.10.9'

//Junit
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.9.0'
testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.9.0'
Expand Down
51 changes: 49 additions & 2 deletions src/main/java/dk/cs/aau/huppaal/HUPPAAL.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import dk.cs.aau.huppaal.code_analysis.CodeAnalysis;
import dk.cs.aau.huppaal.controllers.CanvasController;
import dk.cs.aau.huppaal.controllers.HUPPAALController;
import dk.cs.aau.huppaal.logging.Log;
import dk.cs.aau.huppaal.presentations.BackgroundThreadPresentation;
import dk.cs.aau.huppaal.presentations.HUPPAALPresentation;
import dk.cs.aau.huppaal.presentations.UndoRedoHistoryPresentation;
import dk.cs.aau.huppaal.presentations.PresentationFxmlLoader;
import dk.cs.aau.huppaal.utility.keyboard.Keybind;
import dk.cs.aau.huppaal.utility.keyboard.KeyboardTracker;
import com.google.common.io.Files;
Expand All @@ -23,26 +25,27 @@
import javafx.scene.image.Image;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.text.Font;
import javafx.stage.Modality;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import jiconfont.icons.google_material_design_icons.GoogleMaterialDesignIcons;
import jiconfont.javafx.IconFontFX;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.prefs.Preferences;
import java.util.stream.Collectors;

public class HUPPAAL extends Application {

Expand All @@ -55,6 +58,9 @@ public class HUPPAAL extends Application {
private static HUPPAALPresentation presentation;
public static SimpleStringProperty projectDirectory = new SimpleStringProperty();
private Stage debugStage;
public Stage searchStage;
public static Runnable toggleSearchModal;
private HBox searchBox;

{
try {
Expand Down Expand Up @@ -144,6 +150,18 @@ private void forceCreateFolder(final String directoryPath) throws IOException {
FileUtils.forceMkdir(directory);
}

@Override
public void init() {
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
try {
Log.addError(t.getName(), e.getMessage());
} catch(Throwable throwable) {
throwable.printStackTrace();
}
e.printStackTrace();
});
}

@Override
public void start(final Stage stage) throws Exception {
// Load or create new project
Expand Down Expand Up @@ -240,6 +258,35 @@ public void start(final Stage stage) throws Exception {
}
}));

toggleSearchModal = () -> {
try {
if(searchStage == null) {
searchStage = new Stage();
searchBox = new HBox();
searchStage.initStyle(StageStyle.UNDECORATED);
searchStage.setScene(new Scene(PresentationFxmlLoader.loadSetRootGetElement("ProjectSearchPresentation.fxml", searchBox),
screen.getBounds().getWidth() * 0.4,
screen.getBounds().getHeight() * 0.6));
searchStage.initModality(Modality.WINDOW_MODAL);
searchStage.initOwner(scene.getWindow());
searchStage.addEventHandler(KeyEvent.KEY_PRESSED, (t) -> {
if(t.getCode()==KeyCode.ESCAPE && searchStage.isShowing())
searchStage.close();
});
}
if(searchStage.isShowing())
searchStage.close();
else {
searchStage.show();
searchBox.requestFocus();
}
} catch (Exception e) {
e.printStackTrace();
searchStage = null;
Log.addError(e.getMessage());
}
};

stage.setOnCloseRequest(event -> {
UPPAALDriverManager.getInstance().stopEngines();

Expand Down
9 changes: 8 additions & 1 deletion src/main/java/dk/cs/aau/huppaal/abstractions/Edge.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import dk.cs.aau.huppaal.controllers.HUPPAALController;
import dk.cs.aau.huppaal.presentations.JorkPresentation;
import dk.cs.aau.huppaal.utility.colors.Color;
import dk.cs.aau.huppaal.utility.helpers.ArrayUtils;
import dk.cs.aau.huppaal.utility.helpers.Circular;
import dk.cs.aau.huppaal.utility.serialize.Serializable;
import com.google.gson.JsonArray;
Expand Down Expand Up @@ -576,10 +577,16 @@ public String generateNearString() {
return "[%s](edge:%s/%s)".formatted(generateFromToString(), parent.getName(), uuid.toString());
}

private String generateFromToString() {
public String generateFromToString() {
return "%s -> %s".formatted(getSourceName(), getTargetName());
}

public String generatePeakyString() {
return "%s -> %s (%s) [%s]".formatted(getSourceName(), getTargetName(),
ArrayUtils.substringIgnoreLen(getGuard(), 0, 25),
ArrayUtils.substringIgnoreLen(getUpdate(), 0,25));
}

private String getSourceName() {
if(getSourceLocation() != null)
return getSourceLocation().getId();
Expand Down
8 changes: 3 additions & 5 deletions src/main/java/dk/cs/aau/huppaal/abstractions/Location.java
Original file line number Diff line number Diff line change
Expand Up @@ -269,11 +269,9 @@ public DoubleProperty invariantYProperty() {
}

public String getMostDescriptiveIdentifier() {
if(!Strings.isNullOrEmpty(getNickname())) {
return getNickname();
} else {
return getId();
}
if(!Strings.isNullOrEmpty(getNickname()))
return getNickname() + " ( "+getId()+" )";
return getId();
}

public Reachability getReachability() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ protected void interpolate(final double frac) {
public FontIcon runConfigurationExecuteButtonIcon;
public LogTabPresentation infoLog, warnLog, errLog;
public Tab infoLogTab, warnLogTab, errLogTab;
public MenuItem menuBarViewSearch;
private double tabPanePreviousY = 0;
private boolean shouldISkipOpeningTheMessagesContainer = true;

Expand Down Expand Up @@ -324,7 +325,7 @@ private void initializeLogTabNotifications() {
}
});
tabPane.getSelectionModel().selectedItemProperty().addListener((e,o,n) -> {
if(n == null)
if(n == null || n.getGraphic() == null)
return;
((FontIcon) n.getGraphic()).setIconColor(javafx.scene.paint.Color.WHITE);
});
Expand Down Expand Up @@ -620,6 +621,9 @@ private void initializeMenuBar() {
menuBarViewQueryPanel.getGraphic().opacityProperty().bind(new When(isOpen).then(1).otherwise(0));
});

menuBarViewSearch.setAccelerator(new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN));
menuBarViewSearch.setOnAction(event -> HUPPAAL.toggleSearchModal.run());

menuBarHelpHelp.setOnAction(event -> HUPPAAL.showHelp());

menuBarEditBalance.setAccelerator(new KeyCodeCombination(KeyCode.B, KeyCombination.SHORTCUT_DOWN));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package dk.cs.aau.huppaal.controllers;

import com.jfoenix.controls.JFXTextField;
import dk.cs.aau.huppaal.HUPPAAL;
import dk.cs.aau.huppaal.abstractions.Component;
import dk.cs.aau.huppaal.abstractions.Edge;
import dk.cs.aau.huppaal.abstractions.Location;
import dk.cs.aau.huppaal.presentations.ProjectSearchResultPresentation;
import javafx.application.Platform;
import javafx.fxml.Initializable;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.util.Pair;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.regex.Pattern;

public class ProjectSearchController implements Initializable {
public HBox root;
public JFXTextField searchTextField;
public VBox resultsBox;

@Override
public void initialize(URL location, ResourceBundle resources) {
initializeFocus();
initializeSearchTextField();
}

private void initializeFocus() {
root.focusedProperty().addListener((e,o,n) -> {
if(n) {
searchTextField.requestFocus();
searchTextField.selectAll();
}
});
}

private void initializeSearchTextField() {
searchTextField.textProperty().addListener((obs, oldValue, newValue) -> {
int maxSearchSize = 100;
var newLabels = new ArrayList<ProjectSearchResultPresentation>();
Pattern searchTerm;
try {
searchTerm = Pattern.compile(newValue, Pattern.CASE_INSENSITIVE);
} catch (Exception e) {
searchTerm = Pattern.compile(newValue, Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
}

var components = getComponentNames(searchTerm);
for(var c : components) {
if(newLabels.size() < maxSearchSize)
newLabels.add(new ProjectSearchResultPresentation(c).withClickEffect(this::closeStage));
}

var locations = getLocations(searchTerm);
for (var l : locations) {
if(newLabels.size() < maxSearchSize)
newLabels.add(new ProjectSearchResultPresentation(l.getKey(), l.getValue()).withClickEffect(this::closeStage));
}

var edges = getEdges(searchTerm);
for (var e : edges) {
if(newLabels.size() < maxSearchSize)
newLabels.add(new ProjectSearchResultPresentation(e.getKey(), e.getValue()).withClickEffect(this::closeStage));
}

Platform.runLater(() -> {
resultsBox.getChildren().clear();
resultsBox.getChildren().addAll(newLabels);
});
});

searchTextField.setOnAction(e -> {
if(resultsBox.getChildren() != null && resultsBox.getChildren().size() > 0)
((ProjectSearchResultPresentation) resultsBox.getChildren().get(0)).click();
});
}

private void closeStage() {
HUPPAAL.toggleSearchModal.run();
}

private List<Component> getComponentNames(Pattern searchVal) {
return HUPPAAL.getProject().getComponents().stream()
.filter(c -> searchVal.matcher(c.getName()).find())
.toList();
}

private List<Pair<Component,Location>> getLocations(Pattern searchVal) {
return HUPPAAL.getProject().getComponents().stream()
.map(c -> c.getLocations().stream()
.filter(l ->
searchVal.matcher(l.getId()).find() ||
searchVal.matcher(l.getNickname()).find())
.map(l -> new Pair<>(c,l))
.toList())
.flatMap(List::stream)
.toList();
}

private List<Pair<Component, Edge>> getEdges(Pattern searchVal) {
return HUPPAAL.getProject().getComponents().stream()
.map(c -> c.getEdges().stream()
.filter(e -> searchVal.matcher(e.getUpdate()).find() ||
searchVal.matcher(e.getGuard()).find() ||
searchVal.matcher(e.getSelect()).find() ||
searchVal.matcher(e.getSync()).find() ||
matchesEdgeSourceOrTarget(e, searchVal))
.map(e -> new Pair<>(c,e))
.toList())
.flatMap(List::stream)
.toList();
}

private boolean matchesEdgeSourceOrTarget(Edge e, Pattern searchVal) {
return (e.getSourceLocation() != null && searchVal.matcher(e.getSourceLocation().getId()).find()) ||
(e.getTargetLocation() != null && searchVal.matcher(e.getTargetLocation().getId()).find()) ||
(e.getSourceJork() != null && searchVal.matcher(e.getSourceJork().getId()).find()) ||
(e.getTargetJork() != null && searchVal.matcher(e.getTargetJork().getId()).find()) ||
(e.getSourceSubComponent() != null && searchVal.matcher(e.getSourceSubComponent().getIdentifier()).find()) ||
(e.getTargetSubComponent() != null && searchVal.matcher(e.getTargetSubComponent().getIdentifier()).find());
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dk.cs.aau.huppaal.presentations;

import dk.cs.aau.huppaal.controllers.CanvasController;
import dk.cs.aau.huppaal.logging.Log;
import dk.cs.aau.huppaal.utility.UndoRedoStack;
import dk.cs.aau.huppaal.utility.helpers.CanvasDragHelper;
import dk.cs.aau.huppaal.utility.helpers.MouseTrackable;
Expand Down Expand Up @@ -71,6 +72,18 @@ public CanvasPresentation() {
*/
CanvasDragHelper.makeDraggable(this, mouseEvent -> mouseEvent.getButton().equals(MouseButton.SECONDARY));
setOnScroll(e -> {
var dx = getTranslateX() + e.getDeltaX();
var dy = getTranslateY() + e.getDeltaY();
if(e.isShiftDown()) { // shift enables you to scroll with one wheel to the side
dx = getTranslateX() + e.getDeltaY();
dy = getTranslateY() + e.getDeltaX();
}
setTranslateX(dx);
setTranslateY(dy);
});
// support trackpads
setOnZoom(e -> ZoomHelper.zoom(e.getZoomFactor()));
} catch (final IOException ioe) {
throw new IllegalStateException(ioe);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@
import dk.cs.aau.huppaal.presentations.logging.Hyperlink;
import dk.cs.aau.huppaal.presentations.logging.HyperlinkTextArea;
import dk.cs.aau.huppaal.presentations.logging.TextStyle;
import dk.cs.aau.huppaal.presentations.util.PresentationFxmlLoader;
import dk.cs.aau.huppaal.utility.helpers.SelectHelper;
import javafx.application.Platform;
import javafx.beans.NamedArg;
import javafx.beans.value.ChangeListener;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.HBox;
import org.fxmisc.flowless.VirtualizedScrollPane;
Expand Down
Loading

0 comments on commit fba26c3

Please sign in to comment.