package control; import imp.*; import graph.*; import algorithmen.*; import javafx.fxml.*; import javafx.scene.control.*; import javafx.event.*; import javafx.scene.input.MouseEvent; import javafx.scene.layout.*; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.text.*; import javafx.geometry.Pos; import javafx.scene.image.Image; import javafx.stage.*; // Dateiöffnen / Speichern-Dialog import javafx.application.Platform; import javafx.scene.input.Clipboard; import javafx.scene.input.ClipboardContent; import java.io.File; import java.net.URI; import java.net.URL; import java.net.URLDecoder; import java.nio.file.*; import java.util.Collections; import java.util.stream.Stream; import java.util.Iterator; import java.util.List; import java.util.ArrayList; import java.util.regex.Pattern; import java.lang.reflect.InvocationTargetException; import javafx.collections.ObservableList; /** * Die Klasse SimulationTabMitController stellt einen Tab inclusive ihres Controllers * zur Simulation eines Algorithmus dar. Der Algorithmus kann ausgewählt und schrittweise * durchgeführt werden. * * @author Thomas Schaller * @version 12.02.2025 (v7.4) * v7.4: Unterbrechen eines Algorithmus neu geregelt. * v7.1: Fehler bei Aktualisierung des Hilfefensters behoben, Splitpane statt HBox * v7.0: Mechanismus geändert, so dass die init-Methode des Algorithmus beim Wechesel eines Algorithmus * aufgerufen wird, um die für diesen Algorithmus passenden Anzeigeeinstellungen zu setzen. * v6.9: Hilfefenster ist in Simulationsfenster integriert */ public class SimulationTabMitController extends TabMitController implements Hilfe { @FXML private ComboBox cbAlgorithmen; @FXML private Slider sSpeed; @FXML private Button bStep; @FXML private Button bStart; @FXML private Button bBreak; @FXML private Button bReset; private GraphAlgo aktAlgo = null; private ArrayList algoNamen; private Hilfe hilfe; public SimulationTabMitController(Graph graph, GraphOptions options) { this.graph = graph; this.options = options; } public void initialize() { this.algoNamen = new ArrayList(); File verzeichnis = new File("algorithmen"); if(verzeichnis != null && verzeichnis.isDirectory()) { String[] entries = verzeichnis.list(); for (String name : entries) { if (name.startsWith("GraphAlgo_") && name.endsWith(".class")){ try{ Class c = Class.forName("algorithmen."+name.split(Pattern.quote("."))[0]); GraphAlgo a = ((GraphAlgo)(c).getDeclaredConstructor().newInstance()); int i = 0; while(i < cbAlgorithmen.getItems().size() && cbAlgorithmen.getItems().get(i).compareTo(a.getBezeichnung())<0) i++; //System.out.println("Algorithmus: "+a.getBezeichnung()+" geladen."); cbAlgorithmen.getItems().add(i, a.getBezeichnung()); algoNamen.add(i, "algorithmen."+name.split(Pattern.quote("."))[0]); } catch(ExceptionInInitializerError e) {} catch(LinkageError e){} catch(ClassNotFoundException e) {} catch(NoSuchMethodException e) {} catch(InstantiationException e) {} catch(IllegalAccessException e) {} catch(InvocationTargetException e) {} } } // end of for } verzeichnis = new File( "eigeneAlgorithmen" ); if(verzeichnis != null && verzeichnis.isDirectory()) { String[] entries = verzeichnis.list(); for (String name : entries) { if (name.startsWith("GraphAlgo_") && name.endsWith(".class")){ try{ Class c = Class.forName("eigeneAlgorithmen."+name.split(Pattern.quote("."))[0]); GraphAlgo a = ((GraphAlgo)(c).getDeclaredConstructor().newInstance()); int i = 0; while(i < cbAlgorithmen.getItems().size() && cbAlgorithmen.getItems().get(i).compareTo(a.getBezeichnung())<0) i++; //System.out.println("Algorithmus: "+a.getBezeichnung()+" geladen."); cbAlgorithmen.getItems().add(i, a.getBezeichnung()); algoNamen.add(i, "eigeneAlgorithmen."+name.split(Pattern.quote("."))[0]); } catch(ExceptionInInitializerError e) {} catch(LinkageError e){} catch(ClassNotFoundException e) {} catch(NoSuchMethodException e) {} catch(InstantiationException e) {} catch(IllegalAccessException e) {} catch(InvocationTargetException e) {} } } // end of for } cbAlgorithmen.getSelectionModel().selectedItemProperty().addListener((options, oldValue, newValue) -> { changeAlgorithm(); }); viewer.setGraph(graph,options); this.hilfe = null; this.aktAlgo = null; super.initialize(); sSpeed.valueProperty().addListener(e -> { if (aktAlgo != null) aktAlgo.setSpeed(910-(int) (sSpeed.getValue()));}); bStart.managedProperty().bind(bStart.visibleProperty()); bBreak.managedProperty().bind(bBreak.visibleProperty()); bBreak.setVisible(false); //------------- Hilfefunktion loescheAlles(); zustaende = new ArrayList>(); aktuell = null; reviewAllowed = false; tvAblauf.getSelectionModel().selectedIndexProperty().addListener((obs,oldValue, newValue)->showState()); } public void showHilfe(boolean b) { if(b) { lAblauf.setVisible(true); tvAblauf.setVisible(true); bClipboard.setVisible(true); hilfe = this; if(aktAlgo != null ) { aktAlgo.setGUIElemente(viewer,hilfe); if(aktAlgo.isAlive()) hilfe.append("Unvollständiger Ablauf"); } } else { lAblauf.setVisible(false); tvAblauf.setVisible(false); bClipboard.setVisible(false); if(aktAlgo != null && aktAlgo.isAlive()) aktAlgo.setGUIElemente(viewer, null); hilfe = null; loescheAlles(); zustaende = new ArrayList>(); aktuell = null; reviewAllowed = false; } } public void setGraph(Graph graph, GraphOptions options) { super.setGraph(graph,options); mReset(null); } public void changeAlgorithm() { if(aktAlgo != null && aktAlgo.isAlive() && !aktAlgo.isInterrupted()) aktAlgo.interrupt(); graph.initialisiereAlleKnoten(); graph.initialisiereAlleKanten(); bStep.setDisable(false); bStart.setDisable(false); bStart.setVisible(true); bBreak.setVisible(false); if (hilfe != null) hilfe.loescheAlles(); this.aktAlgo = null; if(cbAlgorithmen.getSelectionModel().getSelectedIndex() >= 0) { try{ ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader(); MyClassLoader classLoader = new MyClassLoader(parentClassLoader); Class c = classLoader.loadClass(algoNamen.get(cbAlgorithmen.getSelectionModel().getSelectedIndex())); aktAlgo = ((GraphAlgo)(c).getDeclaredConstructor().newInstance()); aktAlgo.setStartKnoten(viewer.getSelectedKnoten()); aktAlgo.setGUIElemente(viewer, hilfe); aktAlgo.setSpeed(910-(int) (sSpeed.getValue())); aktAlgo.init(); } catch( Exception e) { System.out.println(e); } } update(); } @FXML void mReset(ActionEvent event) { changeAlgorithm(); } @FXML void mStep(ActionEvent event) { if (aktAlgo == null) return; if (aktAlgo.getState() == Thread.State.NEW ) { aktAlgo.setStartKnoten(viewer.getSelectedKnoten()); aktAlgo.start(); } else { if(aktAlgo.isAlive()) { aktAlgo.setSpeed(910-(int) (sSpeed.getValue())); aktAlgo.setWaitforclick(false); } else { bStep.setDisable(true); bStart.setDisable(true); bBreak.setDisable(true); } // end of if-else } // end of if-else try{ Thread.sleep(100); } catch(Exception e) {} if (!aktAlgo.isAlive()) { bStep.setDisable(true); bStart.setDisable(true); bBreak.setDisable(true); } } @FXML void mStart(ActionEvent event) { if (aktAlgo == null) return; if (aktAlgo.getState() == Thread.State.NEW ) { aktAlgo.setStartKnoten(viewer.getSelectedKnoten()); aktAlgo.setStepping(false); aktAlgo.start(); } else { if(aktAlgo.isAlive()) { aktAlgo.setSpeed(910-(int) (sSpeed.getValue())); aktAlgo.setStepping(false); aktAlgo.setWaitforclick(false); } } // end of if-else bStep.setDisable(true); bStart.setVisible(false); bBreak.setVisible(true); bBreak.setDisable(false); } public void mBreak(ActionEvent event) { if(aktAlgo != null && aktAlgo.isAlive()) { aktAlgo.setStepping(true); bStart.setVisible(true); bBreak.setVisible(false); bStep.setDisable(false); } } // --------- Hilfefenster -------------------------------------------- @FXML private TreeView tvAblauf; @FXML private Label lAblauf; @FXML private Button bClipboard; private List> stufen; private List> zustaende; private TreeItem last; private GraphPlotter gp; private List aktuell; private boolean reviewAllowed; public void setGraphPlotter(GraphPlotter gp) { this.gp = gp; } public void loescheAlles() { Platform.runLater(new Runnable() { @Override public void run() { stufen = new ArrayList>(); zustaende = new ArrayList>(); TreeItem root = new TreeItem("Algorithmus"); root.setExpanded(true); last = root; tvAblauf.setRoot(root); tvAblauf.setShowRoot(false); stufen.add(root); } }); } public void append(String text) { List status = gp.getGraph().getStatus(); Platform.runLater(new Runnable() { @Override public void run() { last = new TreeItem(text); stufen.get(stufen.size()-1).getChildren().add(last); zustaende.add(status); } }); } public void indentMore() { Platform.runLater(new Runnable() { @Override public void run() { if(stufen.size() == 1) { // Hauptknoten TreeItem parent = stufen.get(0); List children = parent.getChildren(); for(int i=children.size()-1; i >= 0; i--) { TreeItem t = children.get(i); if(t.isExpanded()) { t.setExpanded(false); break; } } } stufen.add(last); last.setExpanded(true); last.expandedProperty().addListener((b, o, n) -> showState()); } }); } public void indentLess() { Platform.runLater(new Runnable() { @Override public void run() { if(stufen.size() > 1) stufen.remove(stufen.size()-1); } }); } public void setReviewAllowed(boolean a) { this.reviewAllowed = a; if(!reviewAllowed) tvAblauf.getSelectionModel().clearSelection(); } public void showState() { Platform.runLater(new Runnable() { @Override public void run() { if(reviewAllowed && tvAblauf.getSelectionModel().getSelectedIndex()>=0) { TreeItem s = tvAblauf.getSelectionModel().getSelectedItem(); if(!s.isExpanded()) { // suche das letzte Kind while(s.getChildren().size()>0){ List c = s.getChildren(); s = c.get(c.size()-1); } } gp.getGraph().setStatus(zustaende.get(calculateIndex(tvAblauf.getRoot(), s ,0)-1)); gp.updateImage(); } } }); } private int calculateIndex(TreeItem t, TreeItem search, int nr) { if(t == search) return nr; nr++; List children = t.getChildren(); for(TreeItem c : children) { int i = calculateIndex(c, search, nr); if(i>0) return i; nr = -i; } return -nr; } @FXML void bCopyClicked(ActionEvent event) { final Clipboard clipboard = Clipboard.getSystemClipboard(); final ClipboardContent content = new ClipboardContent(); String s = ""; for(Object c : tvAblauf.getRoot().getChildren()) { if(c instanceof TreeItem) { s += generateClipboardContent((TreeItem) c, ""); } } content.putString(s); clipboard.setContent(content); } private String generateClipboardContent(TreeItem t, String tab) { String s = tab+t.getValue(); for(Object c : t.getChildren()) { if(c instanceof TreeItem) { s += generateClipboardContent((TreeItem) c, tab+" "); } } return s; } }