package control; import imp.*; import graph.*; import javafx.fxml.*; import javafx.scene.control.*; import javafx.event.*; import javafx.scene.input.MouseEvent; import javafx.scene.input.ContextMenuEvent; import javafx.scene.layout.*; import javafx.scene.Node; import javafx.scene.text.*; import javafx.geometry.Pos; import javafx.collections.FXCollections; import javafx.scene.control.Alert.AlertType; import java.util.List; import java.util.ArrayList; import java.util.Collections; import java.util.Optional; import javafx.collections.ObservableList; /** * Die Klasse UnterTabMitController stellt einen Tab inclusive ihres Controllers * zur händischen Erforschung eines Algorithmus. Es wird immer ein einzelner Knoten * oder eine Kante fokussiert. * * @author Thomas Schaller * @version 24.06.2021 (v6.9) * v6.9: Context-Menü für die ToDo-Liste: Knoten löschen */ public class UnterTabMitController extends TabMitController { @FXML private VBox infoBox; @FXML private Button wertButton; @FXML private Button besuchtButton; @FXML private Label knotenname; @FXML private Label knotenwert; @FXML private Label knotenMarkiert; @FXML private Label knotenBesucht; @FXML private GridPane farben; @FXML Button bStatus; @FXML Button bGehezu; @FXML Button bAnfang; @FXML Button bEnde; @FXML Button bSortieren; @FXML private CheckBox cbFarbeAutomatisch; @FXML private ListView lvAuswahl; private List auswahl; private List sicherung; public UnterTabMitController(Graph graph, GraphOptions options) { this.graph = graph; this.options = options; } public void initialize() { if(graph.getAnzahlKnoten()==0) { getTabPane().getTabs().remove(this); return; } buildAuswahl(); this.bAnfang.managedProperty().bind(bAnfang.visibleProperty()); this.bEnde.managedProperty().bind(bEnde.visibleProperty()); this.bSortieren.managedProperty().bind(bSortieren.visibleProperty()); viewer.setGraph(graph,options); viewer.setHvalue(0.5); viewer.setVvalue(0.5); //auswahl = viewer.getGraph().getAlleKnoten(); for(int x = 0; x< 4; x++) { for(int y = 0; y <3; y++) { Label l = new Label(); l.setPrefSize(20,20); l.setMaxSize(200, 200); if(options.farbenKnoten.length > y*4+x) { l.setStyle("-fx-background-color:#"+options.farbenKnoten[y*4+x]); l.setAlignment(Pos.CENTER); l.setFont(Font.font("System", FontWeight.BOLD, 12)); } else l.setStyle("-fx-background-color:#FFFFFF"); l.setOnMouseClicked(e -> knotenFarbe(e)); farben.add(l, x, y); } } fillLvAuswahl(); lvAuswahl.getSelectionModel().selectedItemProperty().addListener( (obs, oldValue, newValue) -> showAuswahl()); cbFarbeAutomatisch.selectedProperty().addListener((o, oldValue, newValue) -> { Knoten k = viewer.getSelectedKnoten(); if (k!=null) { k.setFarbeAutomatisch(newValue); viewer.updateImage(); updateInfofeld(); } }); super.initialize(); } public void setGraph(Graph graph, GraphOptions options) { if(graph.getAnzahlKnoten()==0) { getTabPane().getTabs().remove(this); return; } options.fokusArt = this.options.fokusArt; options.auswahl = this.options.auswahl; options.bildAnzeigen = false; if(options.fokusArt == 0 && this.options.parent!= null) options.parent = graph.getKnoten(0); if(options.fokusArt == 1 && this.options.parent!= null) options.parent = graph.getKante(0,1); this.graph = graph; this.options = options; viewer.setRestrictTo(null); buildAuswahl(); super.setGraph(graph,options); } public void buildAuswahl() { auswahl = new ArrayList(); if(options.auswahl == 0) { // Alle Knoten/Kanten gewählt if(options.fokusArt == 0) // Knoten auswahl = new ArrayList(graph.getAlleKnoten()); else auswahl = new ArrayList(graph.getAlleKanten()); } else { if(options.auswahl == 1) { // Nachbarn auswahl = new ArrayList(graph.getNachbarknoten(((Knoten) (options.parent)))); } else { // single auswahl.add(options.parent); } } if(auswahl.size() == 0) getTabPane().getTabs().remove(this); } public void update() { super.update(); updateInfofeld(); fillLvAuswahl(); } private void fillLvAuswahl() { if(auswahl.size()==0 ) { getTabPane().getTabs().remove(this); } else { ObservableList items = FXCollections.observableArrayList (); for(GraphElement ge : auswahl) { if(ge instanceof Knoten) { Knoten k = (Knoten) ge; String beschreibung=""; if(options.showVertexInfo && !k.getInfotext().isEmpty()) beschreibung = k.getInfotext(); else beschreibung = "Knoten"+ graph.getNummer(k); if(options.showVertexValue) { if(k.getDoubleWert() == k.getIntWert()) beschreibung += " ("+k.getIntWert()+")"; else beschreibung += " ("+k.getDoubleWert()+")"; } items.add(beschreibung); } if(ge instanceof Kante) { Kante k = (Kante) ge; if(options.showEdgeWeights) { if(k.getGewicht() == (int) k.getGewicht()) items.add("Kante ("+((int)k.getGewicht())+")"); else items.add("Kante ("+k.getGewicht()+")"); } else items.add("Kante Nr."+graph.getNummer(k)); } } lvAuswahl.setItems(items); showAuswahl(); } } private void showAuswahl() { if(lvAuswahl.getSelectionModel().getSelectedIndex()==-1) { if(auswahl.contains(viewer.getRestrictTo())) { lvAuswahl.getSelectionModel().select(auswahl.indexOf(viewer.getRestrictTo())); } else { lvAuswahl.getSelectionModel().selectFirst(); } } viewer.setRestrictTo(auswahl.get(lvAuswahl.getSelectionModel().getSelectedIndex())); updateInfofeld(); } public void setAuswahl(List auswahl) { this.auswahl = auswahl; fillLvAuswahl(); } @FXML void bAnfang(ActionEvent event) { if(lvAuswahl.getSelectionModel().getSelectedIndex() > 0) { lvAuswahl.getSelectionModel().selectFirst(); showAuswahl(); } } @FXML void bBesucht(ActionEvent event) { Knoten k = viewer.getSelectedKnoten(); if (k!=null) { k.setBesucht(!k.isBesucht()); viewer.updateImage(); updateInfofeld(); }else { Kante ka = viewer.getSelectedKante(); if(ka!=null) { ka.setGeloescht(!ka.isGeloescht()); viewer.updateImage(); updateInfofeld(); } } } @FXML void bEnde(ActionEvent event) { if(lvAuswahl.getSelectionModel().getSelectedIndex() < lvAuswahl.getItems().size()-1) { lvAuswahl.getSelectionModel().selectLast(); showAuswahl(); } } @FXML void knotenFarbe(MouseEvent event) { Node source = (Node) event.getSource(); Integer colIndex = farben.getColumnIndex(source); Integer rowIndex = farben.getRowIndex(source); Knoten k = viewer.getSelectedKnoten(); if (k!=null) { k.setFarbe(rowIndex*4+colIndex); ObservableList ln = farben.getChildren(); for(Node n : ln) { if(n instanceof Label) if(n == source){ ((Label) n).setText("X"); } else ((Label) n).setText(" "); } viewer.updateImage(); updateInfofeld(); } } @FXML void bMarkieren(ActionEvent event) { Knoten k = viewer.getSelectedKnoten(); if (k!=null) { k.setMarkiert(!k.isMarkiert()); viewer.updateImage(); updateInfofeld(); } else { Kante ka = viewer.getSelectedKante(); if(ka!=null) { ka.setMarkiert(!ka.isMarkiert()); viewer.updateImage(); updateInfofeld(); } } } public void updateInfofeld() { GraphElement f = viewer.getRestrictTo(); if( f instanceof Knoten) { this.setText(viewer.getGraph().getKnoteninfo((Knoten) f, false)); } Knoten k = viewer.getSelectedKnoten(); Kante ka = viewer.getSelectedKante(); if(k!=null) { infoBox.setVisible(true); knotenname.setText("Knoten: "+viewer.getGraph().getNummer(k)); knotenwert.setText("Wert: "+k.getDoubleWert()); knotenMarkiert.setText(k.isMarkiert() ? "markiert" : "unmarkiert"); knotenBesucht.setText(k.isBesucht() ? "besucht" : "nicht besucht"); besuchtButton.setText("Besuchen"); wertButton.setVisible(true); farben.setVisible(true); bGehezu.setVisible(k != viewer.getRestrictTo()); bAnfang.setVisible(k != viewer.getRestrictTo()); bEnde.setVisible(k != viewer.getRestrictTo()); bSortieren.setVisible((options.showEdgeWeights && auswahl.get(0) instanceof Kante) || (options.showVertexValue && auswahl.get(0) instanceof Knoten)); cbFarbeAutomatisch.setSelected(k.isFarbeAutomatisch()); ObservableList ln = farben.getChildren(); for(Node n : ln) { if(n instanceof Label){ Integer colIndex = farben.getColumnIndex(n); Integer rowIndex = farben.getRowIndex(n); if(rowIndex*4+colIndex == k.getFarbe()){ ((Label) n).setText("X"); } else ((Label) n).setText(" "); } } } else { if(ka != null) { infoBox.setVisible(true); knotenname.setText("Kante:"); knotenwert.setText("Gewicht: "+ka.getGewicht()); knotenMarkiert.setText(ka.isMarkiert() ? "markiert" : "unmarkiert"); knotenBesucht.setText(ka.isGeloescht() ? "gelöscht" : "nicht gelöscht"); besuchtButton.setText("Löschen"); wertButton.setVisible(false); farben.setVisible(false); } else infoBox.setVisible(false); } } @FXML void graphClicked(MouseEvent event) { viewer.mouseClicked(event); updateInfofeld(); if(viewer.getSelectedKnoten() != null && event.isSecondaryButtonDown()) { // Contextmenu ContextMenu contextMenu = new ContextMenu(); CheckMenuItem item1 = new CheckMenuItem("Markiert"); item1.setSelected(viewer.getSelectedKnoten().isMarkiert()); item1.setOnAction((e) -> this.bMarkieren(e)); CheckMenuItem item2 = new CheckMenuItem("Besucht"); item2.setOnAction((e) -> this.bBesucht(e)); item2.setSelected(viewer.getSelectedKnoten().isBesucht()); MenuItem item3 = new MenuItem("Wert ändern"); item3.setOnAction((e) -> this.bWertAendern(e)); MenuItem item5 = new MenuItem("Füge am Anfang der ToDo-Liste hinzu"); item5.setOnAction((e) -> this.bHinzufuegenAnfang(e)); MenuItem item6 = new MenuItem("Füge am Ende der ToDo-Liste hinzu"); item6.setOnAction((e) -> this.bHinzufuegenEnde(e)); MenuItem item7 = new MenuItem("Loesche aus Liste"); item7.setOnAction((e) -> this.bLoeschenAusListe(e)); SeparatorMenuItem sep = new SeparatorMenuItem(); SeparatorMenuItem sep2 = new SeparatorMenuItem(); MenuItem item4 = new MenuItem("Gehe zu ..."); item4.setOnAction((e) -> this.bGeheZu(e)); // Add MenuItem to ContextMenu contextMenu.getItems().addAll(item3, item1, item2, sep, item5, item6, item7, sep2, item4); contextMenu.show(viewer, event.getScreenX(), event.getScreenY()); } if(viewer.getSelectedKante() != null && event.isSecondaryButtonDown()) { // Contextmenu ContextMenu contextMenu = new ContextMenu(); CheckMenuItem item1 = new CheckMenuItem("Markiert"); item1.setSelected(viewer.getSelectedKante().isMarkiert()); item1.setOnAction((e) -> this.bMarkieren(e)); CheckMenuItem item2 = new CheckMenuItem("Gelöscht"); item2.setSelected(viewer.getSelectedKante().isGeloescht()); item2.setOnAction((e) -> this.bBesucht(e)); SeparatorMenuItem sep = new SeparatorMenuItem(); MenuItem item4 = new MenuItem("Gehe zu ..."); item4.setOnAction((e) -> this.bGeheZu(e)); // Add MenuItem to ContextMenu contextMenu.getItems().addAll( item1, item2, sep, item4); contextMenu.show(viewer, event.getScreenX(), event.getScreenY()); } } @FXML void bHinzufuegenAnfang(ActionEvent event) { Knoten k = viewer.getSelectedKnoten(); if(k!=null) { auswahl.add(0,k); fillLvAuswahl(); } } @FXML void bHinzufuegenEnde(ActionEvent event) { Knoten k = viewer.getSelectedKnoten(); if(k!=null) { auswahl.add(k); fillLvAuswahl(); } } @FXML void bLoeschenAusListe(ActionEvent event) { Knoten k = viewer.getSelectedKnoten(); if(k!=null && auswahl.contains(k)) { auswahl.remove(k); fillLvAuswahl(); } } @FXML void toDoContextMenu(ContextMenuEvent event) { if(lvAuswahl.getSelectionModel().getSelectedIndex() >= 0) { Alert alert = new Alert(AlertType.NONE, "Soll der Knoten aus der ToDo-Liste gelöscht werden?", ButtonType.OK, ButtonType.CANCEL); alert.setTitle("ToDo-Liste"); Optional result = alert.showAndWait(); if (result.get() == ButtonType.OK) { auswahl.remove(lvAuswahl.getSelectionModel().getSelectedIndex()); fillLvAuswahl(); } } } @FXML void bNaechster(ActionEvent event) { if(lvAuswahl.getSelectionModel().isSelected(auswahl.size()-1)) lvAuswahl.getSelectionModel().selectFirst(); else lvAuswahl.getSelectionModel().selectNext(); showAuswahl(); } // @FXML // void bListeAnpassen(ActionEvent event) { // buildAuswahl(); // fillLvAuswahl(); // } // @FXML // void bNeuerTab(ActionEvent event) { // GraphOptions neu = options.copy(); // neu.parent = viewer.getRestrictTo(); // if(neu.parent == null) neu.parent = viewer.getSelectedKnoten(); // neu.bildAnzeigen = false; // tabOeffnen(neu); // } @FXML void bSort(ActionEvent event) { Collections.sort(auswahl); fillLvAuswahl(); } @FXML void bVoheriger(ActionEvent event) { if(lvAuswahl.getSelectionModel().isSelected(0)) lvAuswahl.getSelectionModel().selectLast(); else lvAuswahl.getSelectionModel().selectPrevious(); showAuswahl(); } @FXML void bWertAendern(ActionEvent event) { Knoten k = viewer.getSelectedKnoten(); if (k!=null) { TextInputDialog dialog = new TextInputDialog(""+k.getDoubleWert()); dialog.setTitle("Wert ändern"); dialog.setContentText("Bitte geben Sie den neuen Wert ein:"); Optional result = dialog.showAndWait(); if (result.isPresent()){ try{ double v = Double.parseDouble(result.get()); k.setWert(v); this.fillLvAuswahl(); viewer.updateImage(); updateInfofeld(); } catch (Exception e) { System.out.println("Keine Zahl eingegeben"); } } } } @FXML void bGeheZu(ActionEvent event) { Knoten k = viewer.getSelectedKnoten(); if (k!=null) { GraphOptions neu = options.copy(); neu.auswahl = 2; // single neu.parent = k; neu.bildAnzeigen = false; this.tabOeffnen(neu); } } @FXML void mBeenden(ActionEvent event) { } @FXML void mBesucheKnoten(ActionEvent event) { } @FXML void mBesuchtLoeschen(ActionEvent event) { } @FXML void mFaerbeKnoten(ActionEvent event) { } @FXML void mMarkiereKnoten(ActionEvent event) { } @FXML void mMarkierungenLoeschen(ActionEvent event) { } @FXML void mOeffnen(ActionEvent event) { } @FXML void mSchliessen(ActionEvent event) { } @FXML void mSpeichern(ActionEvent event) { } @FXML void mUeber(ActionEvent event) { } @FXML void mWertSetzen(ActionEvent event) { } @FXML void mZurueck(ActionEvent event) { } @FXML void bStatusRestore(ActionEvent event) { if(sicherung != null) { graph.setStatus(sicherung); update(); } } @FXML void bStatusSave(ActionEvent event) { sicherung = graph.getStatus(); bStatus.setDisable(false); } }