mirror of
https://codeberg.org/qg-info-unterricht/zpg-graphentester.git
synced 2026-03-24 20:48:26 +01:00
435 lines
15 KiB
Java
435 lines
15 KiB
Java
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<String> 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<String> algoNamen;
|
|
private Hilfe hilfe;
|
|
|
|
public SimulationTabMitController(Graph graph, GraphOptions options) {
|
|
this.graph = graph;
|
|
this.options = options;
|
|
|
|
}
|
|
|
|
public void initialize() {
|
|
this.algoNamen = new ArrayList<String>();
|
|
|
|
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<List<String>>();
|
|
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<List<String>>();
|
|
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<String> tvAblauf;
|
|
|
|
@FXML
|
|
private Label lAblauf;
|
|
|
|
@FXML
|
|
private Button bClipboard;
|
|
|
|
private List<TreeItem<String>> stufen;
|
|
private List<List<String>> zustaende;
|
|
private TreeItem<String> last;
|
|
private GraphPlotter gp;
|
|
private List<String> 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<TreeItem<String>>();
|
|
zustaende = new ArrayList<List<String>>();
|
|
TreeItem<String> root = new TreeItem<String>("Algorithmus");
|
|
root.setExpanded(true);
|
|
last = root;
|
|
tvAblauf.setRoot(root);
|
|
tvAblauf.setShowRoot(false);
|
|
stufen.add(root);
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
public void append(String text) {
|
|
List<String> status = gp.getGraph().getStatus();
|
|
Platform.runLater(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
last = new TreeItem<String>(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<TreeItem> 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<TreeItem> 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<TreeItem> 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;
|
|
}
|
|
|
|
}
|