package application; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Files; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.function.Predicate; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import application.customviews.EntryView; import application.customviews.FileView; import application.customviews.SubEntryView; import application.enums.EntryType; import application.enums.NavState; import application.helpers.ChangeViewCallback; import application.helpers.Utils; import application.helpers.WorkWhileProgressThread; import application.helpers.wrappers.Element; import application.helpers.wrappers.Occupation; import application.helpers.wrappers.WrappedException; import application.helpers.wrappers.WriteSelection; import application.parsing.ParsingWrapper; import application.parsing.ReadHandler; import application.res.Backgrounds; import application.res.Colors; import application.res.Occupations; import application.res.PrivacyStatementText; import application.res.Text; import javafx.application.HostServices; import javafx.beans.binding.Bindings; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.ObservableList; import javafx.event.Event; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.geometry.Point2D; import javafx.scene.Cursor; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.CheckBox; import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.control.ProgressIndicator; import javafx.scene.control.ScrollPane; import javafx.scene.control.TextArea; import javafx.scene.control.Tooltip; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.Clipboard; import javafx.scene.input.ClipboardContent; import javafx.scene.input.DataFormat; import javafx.scene.input.DragEvent; import javafx.scene.input.Dragboard; import javafx.scene.input.MouseEvent; import javafx.scene.input.TransferMode; import javafx.scene.layout.BorderPane; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.shape.Line; import javafx.stage.DirectoryChooser; import javafx.stage.Stage; import javafx.util.Duration; /** * Main class of the application. Changes the views, commands the work and * manages the navigation * * @author Bianca * */ public class UICoordinator implements ChangeListener { /** Callback for interaction during the progressView**/ private ChangeViewCallback cb; /** Scene of the application**/ private Scene scene; /** The frame of the application**/ private BorderPane frame; /** The name of the file containing the health data**/ private String filename; /** The label for interaction with the drag and drop of the health data file **/ private Label ddlabel; /** A label where text can be written (in the intro view) about the file not being correct **/ private Label wrong_file; /** contains all data found in the health file to be displayed **/ private VBox datalist; /** The stage of the application **/ private Stage stage; /** Worker for all kinds of parsing**/ private ParsingWrapper worker; /** Directory for saving the files which will be created**/ private File dirForSaving; /** The filename of the file to be created **/ private File fileForSaving; /** All files created in temp directory. Keys are the readable filenames**/ private HashMap filesInTempWithDesc; /** Checkbox for agreeing to the privacy policy (intro view)**/ private CheckBox privAgree; /** count of elements selected in the overview**/ private int selectCount = 0; /** The label for setting the filepath on where to save the created file **/ private Label path; /** Handler which directs the user to the privacy view **/ private EventHandler toPrivacyView; /** Host services of the system**/ private HostServices hostServices; /** The job given by the user.**/ private Occupation occupation; /** Text containing the information if files could not be written **/ private String errorWritingFiles = ""; // Navigation /** navigation element for the intro view**/ private BorderPane start; /** navigation element for the overview view**/ private BorderPane select; /** navigation element for the inspect view**/ private BorderPane inspect; /** navigation element for the result view**/ private BorderPane result; /** navigation element for the privacy view**/ private BorderPane privacy; /** * Constructor which initializes the scene. It creates and sets the first view, * loads the stylesheet and creates the frame. */ public UICoordinator() { cb = new ChangeViewCallback(this); datalist = new VBox(); datalist.setId("datalist"); datalist.setBorder(Utils.darkBlueBorder); ddlabel = new Label(Text.SELECT_FILE); wrong_file = new Label(); wrong_file.setId("error"); frame = setUpFrame(); scene = new Scene(frame, 800, 650); frame.minHeightProperty().bind(Bindings.createDoubleBinding(() -> scene.getHeight(), scene.heightProperty())); frame.minWidthProperty().bind(Bindings.createDoubleBinding(() -> scene.getWidth(), scene.widthProperty())); changeView(getIntroView()); String css = this.getClass().getResource("style.css").toExternalForm(); scene.getStylesheets().add(css); } /** * Sets the attribute of the HostServices for this object * @param hs the hostServices of the system */ public void setHostServices(HostServices hs) { this.hostServices = hs; } /** * Method initializes the frame: sets title, logo and the navigation bar * * @return initialized frame (left and top are frame) */ private BorderPane setUpFrame() { BorderPane frame = new BorderPane(); frame.setId("frame"); //header BorderPane header = new BorderPane(); Label title = new Label(Text.TITLE); header.setCenter(title); ImageView logo = new ImageView(new Image(this.getClass().getResourceAsStream("RI_Logo_weiss_en.png"))); logo.setFitWidth(172.2 * 1.5); //these sizes are related to the image logo.setFitHeight(49.55 * 1.5); header.setLeft(logo); header.setId("frameheader"); frame.setTop(header); //Navigation, labels on the right needed for tooltips VBox nav = new VBox(); nav.setMinWidth(100); nav.setId("navigation"); nav.setFillWidth(true); int buttonCount = 5; privacy = new BorderPane(); privacy.minHeightProperty() .bind(Bindings.createDoubleBinding(() -> nav.getHeight() / buttonCount, nav.heightProperty())); ImageView dsgvoImage = new ImageView(new Image(this.getClass().getResourceAsStream("dsgvo.png"))); privacy.setCenter(dsgvoImage); privacy.setRight(new Label()); privacy.setUserData(Text.MENU_PRIVACY_POLICY); nav.getChildren().add(privacy); start = new BorderPane(); ImageView startImage = new ImageView(new Image(this.getClass().getResourceAsStream("start2.png"))); start.setCenter(startImage); start.minHeightProperty() .bind(Bindings.createDoubleBinding(() -> nav.getHeight() / buttonCount, nav.heightProperty())); start.setCenter(startImage); start.setRight(new Label()); start.setUserData(Text.MENU_DATA_IMPORT); nav.getChildren().add(start); select = new BorderPane(); select.minHeightProperty() .bind(Bindings.createDoubleBinding(() -> nav.getHeight() / buttonCount, nav.heightProperty())); ImageView selectImage = new ImageView(new Image(this.getClass().getResourceAsStream("select.png"))); select.setCenter(selectImage); select.setRight(new Label()); select.setUserData(Text.MENU_DATA_SELECTION); nav.getChildren().add(select); inspect = new BorderPane(); inspect.minHeightProperty() .bind(Bindings.createDoubleBinding(() -> nav.getHeight() / buttonCount, nav.heightProperty())); ImageView inspectImage = new ImageView(new Image(this.getClass().getResourceAsStream("inspect.png"))); inspect.setCenter(inspectImage); inspect.setRight(new Label()); inspect.setUserData(Text.MENU_REVIEW); nav.getChildren().add(inspect); result = new BorderPane(); result.minHeightProperty() .bind(Bindings.createDoubleBinding(() -> nav.getHeight() / buttonCount, nav.heightProperty())); ImageView resultImage = new ImageView(new Image(this.getClass().getResourceAsStream("result.png"))); result.setCenter(resultImage); result.setRight(new Label()); result.setUserData(Text.MENU_DATA_UPLOAD); nav.getChildren().add(result); frame.setLeft(nav); updateNav(NavState.INIT); //Footer BorderPane footer = new BorderPane(); footer.setId("framefooter"); footer.setCenter(new Label(Text.FOOTER_TEXT)); frame.setBottom(footer); nav.minHeightProperty().bind(Bindings.createDoubleBinding(() -> frame.getHeight() - header.getHeight() - footer.getHeight() - Utils.darkBlueBorder.getInsets().getBottom() * 2, frame.heightProperty())); return frame; } /** * Adjusts the navigation to the state wanted * @param state new navigation state */ public void updateNav(NavState state) { //handlers which will be used more than once //those are handlers for going to these views the *first* time with the current data EventHandler toOverview = new EventHandler() { @Override public void handle(MouseEvent arg0) { changeView(getProgressView(Text.WIP_READING_FILE)); WorkWhileProgressThread t = new WorkWhileProgressThread(cb, true); t.start(); } }; EventHandler toIntroView = new EventHandler() { @Override public void handle(MouseEvent arg0) { changeView(getIntroView()); updateNav(NavState.INIT); if (filename == null) { ddlabel.setText(Text.SELECT_FILE); } else { ddlabel.setText(String.format(Text.FOUND_FILE, filename)); } } }; EventHandler toInspectView = new EventHandler() { @Override public void handle(MouseEvent arg0) { changeView(getProgressView(Text.WIP_CREATE_FILE)); WorkWhileProgressThread t = new WorkWhileProgressThread(cb, false); t.start(); } }; EventHandler toResultView = new EventHandler() { @Override public void handle(MouseEvent arg0) { fileForSaving = worker.writeToZipFile(filesInTempWithDesc, dirForSaving); changeView(getResultView()); updateNav(NavState.RESULT); } }; toPrivacyView = new EventHandler() { @Override public void handle(MouseEvent arg0) { changeView(getPrivacyView()); updateNav(NavState.PRIVACY_STATEMENT); } }; //these handlers are used for returning to a previous state EventHandler returnToIntroView = new EventHandler() { @Override public void handle(MouseEvent arg0) { changeView(getIntroView()); updateNav(NavState.IMPORT_GIVEN); privAgree.setSelected(true); ddlabel.setText(String.format(Text.FOUND_FILE, filename)); } }; EventHandler returnToOverview = new EventHandler() { @Override public void handle(MouseEvent event) { changeView(getOverviewView()); updateNav(NavState.DATA_AND_PATH_SELECTED); path.setText(String.format(Text.F_SAVE_AT,dirForSaving.getAbsolutePath())); } }; //always active setNavElemActive(privacy, toPrivacyView); if (state == NavState.PRIVACY_STATEMENT) { setNavElemSelected(privacy, toPrivacyView); setNavElemDeselected(start); setNavElemDeselected(select); setNavElemDeselected(inspect); setNavElemDeselected(result); } if (state == NavState.INIT) { //first statment for tooltip setNavElemActive(start, returnToIntroView); setNavElemSelected(start, toIntroView); setNavElemInactive(select); setNavElemInactive(inspect); setNavElemInactive(result); } if (state == NavState.IMPORT_GIVEN) { setNavElemSelected(start, returnToIntroView); setNavElemActive(select, toOverview); setNavElemInactive(inspect); setNavElemInactive(result); } if (state == NavState.SELECT_DATA) { setNavElemActive(start, returnToIntroView); setNavElemSelected(select, toOverview); setNavElemInactive(inspect); setNavElemInactive(result); } if (state == NavState.DATA_AND_PATH_SELECTED) { setNavElemActive(start, returnToIntroView); setNavElemSelected(select, returnToOverview); setNavElemActive(inspect, toInspectView); setNavElemInactive(result); } if (state == NavState.START_AGAIN) { setNavElemSelected(start, returnToIntroView); setNavElemDeselected(select); setNavElemDeselected(inspect); setNavElemDeselected(result); } if (state == NavState.INSPECT) { setNavElemActive(start, returnToIntroView); setNavElemActive(select, returnToOverview); setNavElemSelected(inspect, toInspectView); setNavElemActive(result, toResultView); } if (state == NavState.INSPECT_WITH_ERROR) { setNavElemActive(start, returnToIntroView); setNavElemActive(select, returnToOverview); setNavElemSelected(inspect, toInspectView); setNavElemDeselected(result); } if (state == NavState.RESULT) { setNavElemActive(start, returnToIntroView); setNavElemActive(select, returnToOverview); setNavElemActive(inspect, toInspectView); setNavElemSelected(result, toResultView); } } /** * Sets a navigation element to be active. That makes it clickable. * @param element Element to be set active * @param onClick action to be done when it is clicked. */ private void setNavElemActive(BorderPane element, EventHandler onClick) { element.setBackground(Backgrounds.darkBlueBackground); element.setBorder(null); Tooltip tooltip = new Tooltip(element.getUserData().toString()); element.setOnMouseEntered(new EventHandler() { @Override public void handle(MouseEvent event) { Point2D p = element.localToScreen(element.getLayoutBounds().getMaxX(), element.getLayoutBounds().getMinY()); ((Label)element.getRight()).setTooltip(tooltip); tooltip.show(((Label)element.getRight()), p.getX(), p.getY()); tooltip.setAutoHide(true); } }); element.setOnMouseExited(new EventHandler() { @Override public void handle(MouseEvent event) { tooltip.hide(); } }); element.setOnMouseClicked(onClick); } /** * Sets a navigation element as inactive * @param element the element which will be inactive */ private void setNavElemInactive(BorderPane element) { element.setBackground(Backgrounds.greyBackground); element.setOnMouseEntered(null); element.setBorder(null); element.setOnMouseClicked(null); } /** * Selects a navigation element. It indicates the currently active view * @param element Navigation element to be selected * @param onClick Handler which should be executed in case it was clicked on */ private void setNavElemSelected(BorderPane element, EventHandler onClick) { element.setBackground(Backgrounds.darkBlueBackground); element.setBorder(Utils.redBorder); element.setOnMouseClicked(onClick); } /** * Deselects a navigation element * @param element the element to be deselected */ private void setNavElemDeselected(BorderPane element) { element.setBorder(null); } /** * Initialized the stage * @param stage */ public void setStage(Stage stage) { this.stage = stage; stage.setScene(scene); stage.setTitle(Text.TITLE); stage.getIcons().add(new Image(this.getClass().getResourceAsStream("RI_Logo_blau_en_short.png"))); stage.show(); } /** * Switches the displayed view (always in a ScrollPane) * @param view The new view to be shown */ public void changeView(Pane view) { ScrollPane scroll = new ScrollPane(); scroll.setContent(view); scroll.setId("scroll"); frame.setCenter(scroll); scroll.getStyleClass().add("edge-to-edge"); view.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> frame.getCenter().minWidth(0), frame.widthProperty())); scroll.setFitToWidth(true); } /** * Returns the scene * @return the described value */ public Scene getScene() { return scene; } /** * Creates the first view which is shown after starting the application. It * allows the user to insert a health file and check the privacy policy * * @return the created view */ private VBox getIntroView() { VBox container = new VBox(); container.setId("container"); container.getChildren().add(new Label(Text.MAIN_INFO)); Label appleLink = new Label(Text.APPLE_LINK_EXPORT); container.getChildren().add(appleLink); appleLink.setTextFill(Colors.grey); appleLink.setOnMouseEntered(new EventHandler() { @Override public void handle(Event event) { appleLink.setTextFill(Colors.blue); } }); appleLink.setOnMouseExited(new EventHandler() { @Override public void handle(Event event) { appleLink.setTextFill(Colors.grey); } }); appleLink.setOnMouseClicked(new EventHandler() { @Override public void handle(Event event) { try { hostServices.showDocument(new URL(Text.APPLE_LINK_EXPORT).toExternalForm()); } catch (MalformedURLException e) { //do nth } } }); //Allow drag and drop for the health file HBox ddTarget = new HBox(); ddTarget.setId("ddTarget"); ddlabel.setId("ddLabel"); ddTarget.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth(), container.widthProperty())); ddlabel.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> ddTarget.getWidth(), ddTarget.widthProperty())); ddTarget.getChildren().add(ddlabel); ddTarget.setOnDragOver(new EventHandler() { @Override public void handle(DragEvent event) { if (event.getGestureSource() != ddTarget && event.getDragboard().hasFiles()) { event.acceptTransferModes(TransferMode.COPY_OR_MOVE); } event.consume(); } }); ddTarget.setOnDragDropped(new EventHandler() { @Override public void handle(DragEvent event) { Dragboard db = event.getDragboard(); boolean success = false; if (db.hasFiles()) { filename = db.getFiles().toString().replace("[", "").replace("]", ""); ddlabel.setText(String.format(Text.FOUND_FILE, filename)); checkFile(filename); success = true; } event.setDropCompleted(success); event.consume(); } }); container.getChildren().add(ddTarget); container.getChildren().add(wrong_file); //check privacy policy privAgree = new CheckBox(); privAgree.setText(Text.PRIVACY_STATEMENT_ACCEPTED); privAgree.setWrapText(true); privAgree.setStyle("-fx-font-family: \"Arial\""); privAgree.selectedProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { checkFile(filename); } }); privAgree.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth(), container.widthProperty())); container.getChildren().add(privAgree); //Button to be directed to the privacy view HBox gotToPrivacyView = new HBox(); gotToPrivacyView.setPrefHeight(50); gotToPrivacyView.setId("goToPriv"); BorderPane button = new BorderPane(); button.setCenter(new Label(Text.GO_TO_PRIVACY_STATEMENT)); button.setOnMouseClicked(toPrivacyView); button.setId("goToPrivButton"); gotToPrivacyView.getChildren().addAll(button); HBox.setHgrow(button, Priority.ALWAYS); container.getChildren().add(gotToPrivacyView); return container; } /** * checks on a superficial level whether the input health file is correct * (fileType) and adjusts the navigation * * @param filename Filename to check */ private void checkFile(String filename) { if (filename != null && (filename.endsWith(".xml") || filename.endsWith(".zip"))) { if (privAgree.isSelected()) { updateNav(NavState.IMPORT_GIVEN); } else { updateNav(NavState.INIT); } wrong_file.setText(""); } else if (filename != null) { updateNav(NavState.INIT); wrong_file.setText(Text.NO_VALID_FILE); } } /** * Creates a progress view to be shown when the application needs some time * working * * @param text Text to be displayed in the view * @return the created view */ public VBox getProgressView(String text) { VBox container = new VBox(); container.setId("container"); Label l = new Label(text); container.getChildren().add(l); ProgressIndicator PI = new ProgressIndicator(); container.getChildren().add(PI); return container; } /** * This creates the third view which shows the created files in temp dir and * allows the user to inspect them. Don't change any widths and heights here!!! * * @return the created view */ public VBox getInspectView() { VBox container = new VBox(); container.setId("container"); container.setPadding(new Insets(0, 0, 5, 0)); Label l = new Label(Text.PLEASE_INSPECT); container.getChildren().add(l); GridPane files = new GridPane(); files.setBorder(Utils.darkBlueBorder); int oneFileViewWidth = FileView.WIDTH; int filesBorderWidth = (int) (files.getBorder().getInsets().getLeft() + files.getBorder().getInsets().getRight()); container.getChildren().add(files); files.maxWidthProperty().bind(Bindings.createDoubleBinding(() -> // windowWidth - (border*2) = width for fileViews // floor(width for fileViews/Fileview.width) = number of possible views // number of possible views*FileView.width = needed width for fileViews // needed width for fileViews+ borders = complete width (Math.floor((container.getWidth() - filesBorderWidth) / oneFileViewWidth) * oneFileViewWidth) // borders of the FlowPane + filesBorderWidth, container.widthProperty())); // if the container width changes, the number of views should also change container.widthProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, Number oldValue, Number newValue) { int oneFileViewWidth = FileView.WIDTH; int filesBorderWidth = (int) (files.getBorder().getInsets().getLeft() + files.getBorder().getInsets().getRight()); int col = 0; int row = 0; int colElems = (int) ((container.getWidth() - filesBorderWidth) / oneFileViewWidth); if (filesInTempWithDesc != null) { files.getChildren().clear(); for (String desc : filesInTempWithDesc.keySet()) { files.add(new FileView(filesInTempWithDesc.get(desc), desc, hostServices), col, row); col++; if (col == colElems) { row++; col = 0; } } } else { files.getChildren().add(new Label(errorWritingFiles)); } } }); return container; } /** * Creates the second view which contains all the information of the health data * * @return created view */ public VBox getOverviewView() { VBox container = new VBox(); container.setId("container"); // Label selectText = new Label(Text.SELECT_CATEGORIES); // container.getChildren().add(selectText); // container.getChildren().add(new Label(Text.SELECT_INTRO)); // input the job container.getChildren().add(getJobSelection(container)); // View for clicking and setting the path for saving the resulting data BorderPane selectSavePath = new BorderPane(); String currentUsersHomeDir = System.getProperty("user.home"); if(dirForSaving==null) { dirForSaving= new File(currentUsersHomeDir); } path = new Label(String.format(Text.F_LABEL_SAVE_PATH, currentUsersHomeDir)); selectSavePath.setCenter(path); path.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth(), container.widthProperty())); path.setOnMouseClicked(new EventHandler() { @Override public void handle(MouseEvent event) { DirectoryChooser dirChooser = new DirectoryChooser(); dirChooser.setTitle("Save Data"); File var = dirChooser.showDialog(stage); if (var != null) { dirForSaving = var; path.setText(String.format(Text.F_SAVE_AT, dirForSaving.getPath())); if (selectCount > 0) { updateNav(NavState.DATA_AND_PATH_SELECTED); } } } }); path.setOnMouseEntered(new EventHandler() { @Override public void handle(Event event) { path.setTextFill(Colors.blue); } }); path.setOnMouseExited(new EventHandler() { @Override public void handle(Event event) { path.setTextFill(Color.BLACK); } }); container.getChildren().add(selectSavePath); container.getChildren().add(new Label(Text.SELECT_HOW_TO)); // These are the buttons to help selection HBox selectButtons = new HBox(); VBox.setVgrow(selectButtons, Priority.ALWAYS); selectButtons.setId("selectButtons"); BorderPane selectAll = new BorderPane(); selectAll.setCenter(new Label(Text.SELECT_ALL)); selectAll.setOnMouseClicked(new EventHandler() { @Override public void handle(MouseEvent arg0) { for (Node n : datalist.getChildren()) { if (n instanceof EntryView) { EntryView i = (EntryView) n; i.setSelected(true, true); } } } }); BorderPane deselectAll = new BorderPane(); deselectAll.setCenter(new Label(Text.DESELECT_ALL)); deselectAll.setOnMouseClicked(new EventHandler() { @Override public void handle(MouseEvent arg0) { updateNav(NavState.SELECT_DATA); for (Node n : datalist.getChildren()) { if (n instanceof EntryView) { EntryView i = (EntryView) n; i.setSelected(false, true); } } } }); BorderPane selectCurrentResearchMinimum = new BorderPane(); Label l = new Label(Text.SELECT_BASIC_FIELD_OF_INTEREST); l.setWrapText(true); selectCurrentResearchMinimum.minHeightProperty() .bind(Bindings.createDoubleBinding(() -> l.getMaxHeight(), l.maxHeightProperty())); selectCurrentResearchMinimum.maxHeightProperty() .bind(Bindings.createDoubleBinding(() -> l.getMaxHeight(), l.maxHeightProperty())); selectCurrentResearchMinimum.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> l.getWidth(), l.widthProperty())); selectCurrentResearchMinimum.setCenter(l); selectCurrentResearchMinimum.setOnMouseClicked(new EventHandler() { @Override public void handle(MouseEvent arg0) { for (Node n : datalist.getChildren()) { if (n instanceof EntryView) { EntryView i = (EntryView) n; i.setSelected(false, true); } } for (Node n : datalist.getChildren()) { if (n instanceof EntryView) { EntryView i = (EntryView) n; // Top level // biologicalSex, regionCode if (i.getEntryType().equals(EntryType.BIOLOGICAL_SEX) || i.getEntryType().equals(EntryType.REGION_CODE)) { i.setSelected(true, true); } // sub elements // year of birth, stepCount, if (i.getEntryType().equals(EntryType.DATE_OF_BIRTH)) { i.selectSubelement(Text.YEAR); } if (i.getEntryType().equals(EntryType.RECORD)) { i.selectSubelement("StepCount"); } } } } }); BorderPane selectCurrentResearchAdvanced = new BorderPane(); Label lAdvanced = new Label(Text.SELECT_ADVANCED_FIELD_OF_INTEREST); lAdvanced.setWrapText(true); selectCurrentResearchAdvanced.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> lAdvanced.getWidth(), lAdvanced.widthProperty())); selectCurrentResearchAdvanced.setCenter(lAdvanced); selectCurrentResearchAdvanced.setOnMouseClicked(new EventHandler() { @Override public void handle(MouseEvent arg0) { for (Node n : datalist.getChildren()) { if (n instanceof EntryView) { EntryView i = (EntryView) n; i.setSelected(false, true); } } for (Node n : datalist.getChildren()) { if (n instanceof EntryView) { EntryView i = (EntryView) n; // Top level if (i.getEntryType().equals(EntryType.BIOLOGICAL_SEX) || i.getEntryType().equals(EntryType.REGION_CODE)) { i.setSelected(true, true); } // sub elements if (i.getEntryType().equals(EntryType.DATE_OF_BIRTH)) { i.selectSubelement(Text.YEAR); } if (i.getEntryType().equals(EntryType.RECORD)) { i.selectSubelement("StepCount"); i.selectSubelement("RestingHeartRate"); i.selectSubelement("BodyMass"); i.selectSubelement("Height"); i.selectSubelement("RespiratoryRate"); i.selectSubelement("SwimmingStrokeCount"); i.selectSubelement("DistanceSwimming"); i.selectSubelement("SleepAnalysis"); i.selectSubelement("DistanceWalkingRunning"); i.selectSubelement("HeartRate"); i.selectSubelement("DistanceCycling"); i.selectSubelement("HeartRateVariabilitySDNN"); } if (i.getEntryType().equals(EntryType.WORKOUT)) { i.selectSubelement("Cycling"); i.selectSubelement("Walking"); i.selectSubelement("Running"); i.selectSubelement("Swimming"); } } } } }); selectButtons.getChildren().addAll(selectAll, selectCurrentResearchAdvanced, selectCurrentResearchMinimum,deselectAll); //-30 here needed because of padding and spacing etc. selectAll.minWidthProperty() .bind(Bindings.createDoubleBinding(() ->(selectButtons.getWidth()-30)/4, selectButtons.widthProperty())); deselectAll.minWidthProperty() .bind(Bindings.createDoubleBinding(() ->(selectButtons.getWidth()-30)/4, selectButtons.widthProperty())); selectCurrentResearchAdvanced.minWidthProperty() .bind(Bindings.createDoubleBinding(() ->(selectButtons.getWidth()-30)/4, selectButtons.widthProperty())); selectCurrentResearchMinimum.minWidthProperty() .bind(Bindings.createDoubleBinding(() ->(selectButtons.getWidth()-30)/4, selectButtons.widthProperty())); //Fix for apple: boxes are too big on init without this selectAll.maxHeightProperty() .bind(Bindings.createDoubleBinding(() ->80.0, selectAll.heightProperty())); selectCurrentResearchMinimum.maxHeightProperty() .bind(Bindings.createDoubleBinding(() ->80.0, selectCurrentResearchMinimum.heightProperty())); selectCurrentResearchAdvanced.maxHeightProperty() .bind(Bindings.createDoubleBinding(() ->80.0, selectCurrentResearchAdvanced.heightProperty())); deselectAll.maxHeightProperty() .bind(Bindings.createDoubleBinding(() ->80.0, deselectAll.heightProperty())); container.getChildren().add(selectButtons); deselectAll.requestFocus(); // Here is the data, but its only drawn here. Loading of the data is done // somewhere else BorderPane datacontainer = new BorderPane(); datacontainer.setPadding(new Insets(5)); datacontainer.setId("datacontainer"); datacontainer.setCenter(datalist); container.getChildren().add(datacontainer); datacontainer.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth(), container.widthProperty())); datacontainer.maxWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth(), container.widthProperty())); datalist.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth(), container.widthProperty())); datalist.maxWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth(), container.widthProperty())); return container; } /** * Returns the matching occupation list from {@link Occupations}, inserts * {@code Text.NOT_SET} and selects a subset from the prefix (if level >2) * @param prefix The prefix of the string (number combination) * to define the subset. The code of the super group. * @return The described value, {@code null} if value < 0 or > 4 */ private ObservableList getOccupationList( String prefix) { Predicate prefixPred = new Predicate() { @Override public boolean test(String t) { return t.startsWith(prefix)||t.equals(Text.NOT_SET); } }; if(prefix.length()==0) { return Occupations.JOBS_LEVEL_1; } else if(prefix.length()==1) { return Occupations.JOBS_LEVEL_2.filtered(prefixPred); } else if(prefix.length()==2) { return Occupations.JOBS_LEVEL_3.filtered(prefixPred); } else if(prefix.length()==3) { return Occupations.JOBS_LEVEL_4.filtered(prefixPred); } return null; } /** * This method creates a styled comboBox for the occupations * @param container For the width binding * @return the created comboBox */ private ComboBox getComboBox(Pane container) { ComboBox box= new ComboBox<>(); box.setDisable(true); box.setBackground(Backgrounds.lightGreyBackground); box.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth()-(2*container.getBorder().getInsets().getRight()), container.widthProperty())); box.maxWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth()-(2*container.getBorder().getInsets().getRight()), container.widthProperty())); return box; } /** * Method creates and prepares the dropdown selections for the jobs. * @param container Container for binding the width to * @return A pane containing the dropdowns and info texts */ private Pane getJobSelection(Pane container) { Label addJob = new Label(Text.ADD_JOB); VBox comboContainer = new VBox(); comboContainer.setBorder(Utils.darkBlueBorder); ComboBox levelOne = getComboBox(comboContainer); ComboBox levelTwo = getComboBox(comboContainer); ComboBox levelThree = getComboBox(comboContainer); ComboBox levelFour = getComboBox(comboContainer); levelOne.setStyle("-fx-font-family :\"Arial\""); levelTwo.setStyle("-fx-font-family :\"Arial\""); levelThree.setStyle("-fx-font-family :\"Arial\""); levelFour.setStyle("-fx-font-family :\"Arial\""); levelOne.setItems(getOccupationList("")); levelOne.setDisable(false); levelOne.setValue(Text.NOT_SET); occupation= new Occupation(Text.NOT_SET); levelOne.valueProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, String oldValue, String newValue) { occupation.setLevelOne(newValue); if(newValue.equals(Text.NOT_SET)) { levelTwo.setDisable(true); occupation.setLevelTwo(null); levelTwo.setItems(null); } else { String prefix = ""+newValue.charAt(0); levelTwo.setItems(getOccupationList(prefix)); levelTwo.setDisable(false); levelTwo.setValue(Text.NOT_SET); } } }); levelTwo.valueProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, String oldValue, String newValue) { occupation.setLevelTwo(newValue); if(newValue==null ||newValue.equals(Text.NOT_SET)) { levelThree.setItems(null); occupation.setLevelThree(null); levelThree.setDisable(true); } else { String prefix = ""+newValue.substring(0,2); levelThree.setItems(getOccupationList( prefix)); levelThree.setDisable(false); levelThree.setValue(Text.NOT_SET); } } }); levelThree.valueProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, String oldValue, String newValue) { occupation.setLevelThree(newValue); if(newValue==null ||newValue.equals(Text.NOT_SET)) { occupation.setLevelFour(null); levelFour.setItems(null); levelFour.setDisable(true); } else { String prefix = newValue.substring(0,3); levelFour.setItems(getOccupationList( prefix)); levelFour.setDisable(false); levelFour.setValue(Text.NOT_SET); } } }); levelFour.valueProperty().addListener(new ChangeListener(){ @Override public void changed(ObservableValue observable, String oldValue, String newValue) { occupation.setLevelFour(newValue); }}); comboContainer.getChildren().add(levelOne); comboContainer.getChildren().add(levelTwo); comboContainer.getChildren().add(levelThree); comboContainer.getChildren().add(levelFour); HBox jobInfo = new HBox(); jobInfo.setId("jobInfo"); jobInfo.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth(), container.widthProperty())); jobInfo.maxWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth(), container.widthProperty())); jobInfo.maxHeightProperty() .bind(Bindings.createDoubleBinding(() -> jobInfo.getPrefHeight(), jobInfo.prefHeightProperty())); comboContainer.minHeightProperty() .bind(Bindings.createDoubleBinding(() -> addJob.getHeight(), addJob.heightProperty())); addJob.maxWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth()/2, container.widthProperty())); HBox.setHgrow(comboContainer,Priority.ALWAYS); jobInfo.getChildren().add(comboContainer); jobInfo.getChildren().add(addJob); // VBox occupationSelection = new VBox(); // occupationSelection.setBorder(Utils.darkBlueBorder); // occupationSelection.getChildren().add(jobInfo); // occupationSelection.getChildren().add(new OccupationSelectionView(1, getOccupationList(""))); return jobInfo; } /** * The health data file is read and the overview of all found data is included * in the datalist * * @throws WrappedException if the file coulnd't be read */ public void fillDataList() throws WrappedException { datalist.getChildren().clear(); File file; if (filename.contains(".zip")) { // a zip file can't be read just like this and so the containing file needs to // be copied into temp try { ZipFile f = new ZipFile(filename); String xmlFileName = "apple_health_export/Export.xml"; file = Files.createTempFile("health_data", "__Export.xml").toFile(); file.deleteOnExit(); ZipEntry xml = f.getEntry(xmlFileName); if (xml == null) { xml = f.getEntry(xmlFileName.toLowerCase()); } try (BufferedInputStream is = new BufferedInputStream(f.getInputStream(xml)); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file))) { byte[] b = new byte[1024]; int res = is.read(b); while (res > -1) { out.write(b, 0, res); res = is.read(b); } } f.close(); } catch (Exception e) { // The zip-File couldn't be read, maybe it was the wrong file or error throw new WrappedException(e, Text.E_READ_ZIP_FILE); } } else { file = new File(filename); } try { worker = new ParsingWrapper(file); } catch (Exception e) { throw new WrappedException(e, Text.E_READ_XML_FILE); } ReadHandler read = worker.getRead(); // an EntryView is created per EntryType (ME) for (EntryType type : EntryType.ALL_ME_ONES) { EntryView ev; if (type.equals(EntryType.EXPORT_DATE)) { ev = new EntryView(new Element(type, read.getExportDate())); } else if (type.equals(EntryType.REGION_CODE)) { ev = new EntryView(new Element(type, read.getRegionCode())); } else if (type == EntryType.DATE_OF_BIRTH) { String value = read.getDateOfBirth(); if (value == null || value.equals("") || value.equals(Text.NOT_SET)) { // Don't add an element when there is no data given continue; } ev = new EntryView(new Element(type, read.getDateOfBirth()), read.getSplitDateOfBirth()); } else { String value = read.getMeInfo(type); if (value == null || value.equals("") || value.equals(Text.NOT_SET)) { // Don't add an element when there is no data given continue; } ev = new EntryView(new Element(type, value)); } ev.maxWidthProperty() .bind(Bindings.createDoubleBinding( () -> datalist.getWidth() - datalist.getBorder().getInsets().getRight() * 2, datalist.widthProperty())); ev.minWidthProperty() .bind(Bindings.createDoubleBinding( () -> datalist.getWidth() - datalist.getBorder().getInsets().getRight() * 2, datalist.widthProperty())); datalist.getChildren().add(ev); datalist.getChildren().add(getSeparator(datalist)); ev.addCheckListener(this); } // an EntryView is created per EntryType (not ME) for (EntryType type : EntryType.ALL_SEPARATE_ONES) { int n = read.getTypeNumber(type); if (n > 0) { EntryView ev; if (type == EntryType.WORKOUT) { ev = new EntryView(new Element(type, n + ""), read.getSubWorkouts()); } else if (type == EntryType.RECORD) { ev = new EntryView(new Element(type, n + ""), read.getSubRecords()); } else { ev = new EntryView(new Element(type, n + "")); } ev.addCheckListener(this); ev.maxWidthProperty() .bind(Bindings.createDoubleBinding( () -> datalist.getWidth() - datalist.getBorder().getInsets().getRight() * 2, datalist.widthProperty())); ev.minWidthProperty() .bind(Bindings.createDoubleBinding( () -> datalist.getWidth() - datalist.getBorder().getInsets().getRight() * 2, datalist.widthProperty())); datalist.getChildren().add(ev); datalist.getChildren().add(getSeparator(datalist)); } } if (datalist.getChildren().size() > 0) // something inside, so there is a separator too much { datalist.getChildren().remove(datalist.getChildren().size() - 1); } } /** * Used to display in the overview when the initial health file couldn't be * read. Consists of a BorderPane with a text in its center * * @param text Text to be displayed * @return the created BorderPane */ private BorderPane getEmptyFileView(String text) { BorderPane p = new BorderPane(); p.setCenter(new Label(text)); return p; } /** * In case there was an error reading the inital health file, the overview will * only show an information text regarding the error * * @param text Text to be displayed */ public void setErrorReadingFile(String text) { datalist.getChildren().add(getEmptyFileView(text)); } /** * Saves the error which occurred when the temp files are created * * @param text Details on why it didn't work */ public void setErrorWritingTempFiles(String text) { filesInTempWithDesc = null; errorWritingFiles = text; } /** * Creates a horizontal separator line to be used in lists * * @param toBind The view it should be bound to (length wise) * @return The created separator */ private BorderPane getSeparator(Pane toBind) { BorderPane p = new BorderPane(); Line line = new Line(); line.setStartX(0); line.setStartY(0); line.setEndY(0); line.endXProperty().bind(Bindings.createDoubleBinding( () -> toBind.getWidth() - toBind.getBorder().getInsets().getRight() * 2, toBind.widthProperty())); line.setStroke(Colors.darkGrey); p.setCenter(line); return p; } /** * Creates the last view showing the overview of all saved data and the help to * upload the created zip file **/ public VBox getResultView() { VBox container = new VBox(); container.setId("container"); Label done = new Label(Text.SUCCESS); container.getChildren().add(done); // buttons for easier access to nextcloud HBox nextcloudHelp = new HBox(); nextcloudHelp.setId("nextcloudHelp"); nextcloudHelp.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth(), container.widthProperty())); // open in browser BorderPane goToNextcloud = new BorderPane(); goToNextcloud.setId("goToNextcloud"); Label nextcloudText = new Label(Text.NEXTCLOUD); goToNextcloud.setCenter(nextcloudText); goToNextcloud.setLeft(new ImageView( new Image(this.getClass(). getResourceAsStream("internet.png"),64.0,64.0, true, true))); goToNextcloud.setOnMouseClicked(new EventHandler() { // open in browser if possible @Override public void handle(MouseEvent arg0) { try { hostServices.showDocument(new URL(Text.NEXTCLOUD_ADDRESS).toExternalForm()); } catch (MalformedURLException e) { // otherwise do nothing } } }); nextcloudHelp.getChildren().add(goToNextcloud); List clipboardFiles = new ArrayList<>(); clipboardFiles.add(fileForSaving); // copy filepath to clipboard BorderPane copyToClipboard = new BorderPane(); copyToClipboard.setId("copyToClipboard"); Label clipBoardText = new Label(Text.COPY_FILE_PATH); copyToClipboard.setCenter(clipBoardText); copyToClipboard.setLeft(new ImageView( new Image(this.getClass(). getResourceAsStream("filepath.png"),64.0,64.0, true, true))); copyToClipboard.setOnMouseClicked(new EventHandler() { @Override public void handle(MouseEvent arg0) { final Clipboard clipboard = Clipboard.getSystemClipboard(); final ClipboardContent content = new ClipboardContent(); content.putString(fileForSaving.getAbsolutePath()); clipboard.setContent(content); Point2D p = clipBoardText.localToScreen(clipBoardText.getLayoutBounds().getCenterX(), clipBoardText.getLayoutBounds().getCenterY()); Tooltip copied = new Tooltip(Text.FILE_PATH_IN_CLIPBOARD); clipBoardText.setTooltip(copied); copied.show(clipBoardText, p.getX(), p.getY()); copied.setHideDelay(Duration.seconds(5)); copied.autoHideProperty().set(true); } }); // drag file to browser BorderPane dragToNextcloud = new BorderPane(); dragToNextcloud.setId("dragToServer"); dragToNextcloud.setCenter(new Label(Text.DRAG_FILE)); dragToNextcloud.setLeft(new ImageView( new Image(this.getClass(). getResourceAsStream("archive.png"),64.0,64.0, true, true))); dragToNextcloud.setOnMouseEntered(new EventHandler() { @Override public void handle(MouseEvent event) { scene.setCursor(Cursor.OPEN_HAND); } }); dragToNextcloud.setOnMouseExited(new EventHandler() { @Override public void handle(MouseEvent event) { scene.setCursor(Cursor.DEFAULT); } }); dragToNextcloud.setOnDragDetected(new EventHandler() { @Override public void handle(MouseEvent event) { /* drag was detected, start a drag-and-drop gesture */ /* allow any transfer mode */ Dragboard db = dragToNextcloud.startDragAndDrop(TransferMode.ANY); /* Put a string on a dragboard */ ClipboardContent content = new ClipboardContent(); content.put(DataFormat.FILES, clipboardFiles); // content.putString(source.getText()); db.setContent(content); event.consume(); } }); HBox.setHgrow(copyToClipboard, Priority.ALWAYS); HBox.setHgrow(dragToNextcloud, Priority.ALWAYS); HBox.setHgrow(goToNextcloud, Priority.ALWAYS); nextcloudHelp.getChildren().add(dragToNextcloud); nextcloudHelp.getChildren().add(copyToClipboard); container.getChildren().add(nextcloudHelp); TextArea copyable = new TextArea(String.format(Text.F_RAW_UPLOAD_DATA, fileForSaving.getAbsolutePath(),Text.NEXTCLOUD_ADDRESS)); copyable.setEditable(false); copyable.setWrapText(true); copyable.setStyle("-fx-font-family :\"Arial\""); copyable.setId("buttonProblems"); copyable.setFocusTraversable(false); copyable.setPrefHeight(70); container.getChildren().add(copyable); // table to show all saved data VBox overview = new VBox(); overview.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth(), container.widthProperty())); container.getChildren().add(overview); overview.setId("savedOverview"); overview.setBorder(Utils.darkBlueBorder); // header Label savedOverview = new Label(Text.DATA_OVERVIEW); savedOverview.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> overview.getWidth(), overview.widthProperty())); overview.getChildren().add(savedOverview); savedOverview.setStyle("-fx-font-weight: bold"); // add job if (!occupation.getLevelOne().equals(Text.NOT_SET)) { Label x = new Label(String.format(Text.F_SAVED_DATA_VALUE_SUBCATEGORY, EntryType.JOB.getValue(), Text.OCCUPATION_LEVEL_ONE, occupation.getLevelOne())); x.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> overview.getWidth(), overview.widthProperty())); overview.getChildren().add(x); overview.getChildren().add(getSeparator(overview)); if (!occupation.getLevelTwo().equals(Text.NOT_SET)) { Label x2 = new Label(String.format(Text.F_SAVED_DATA_VALUE_SUBCATEGORY, EntryType.JOB.getValue(), Text.OCCUPATION_LEVEL_TWO, occupation.getLevelTwo())); x2.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> overview.getWidth(), overview.widthProperty())); overview.getChildren().add(x2); overview.getChildren().add(getSeparator(overview)); if (!occupation.getLevelThree().equals(Text.NOT_SET)) { Label x3 = new Label(String.format(Text.F_SAVED_DATA_VALUE_SUBCATEGORY, EntryType.JOB.getValue(), Text.OCCUPATION_LEVEL_THREE, occupation.getLevelThree())); x3.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> overview.getWidth(), overview.widthProperty())); overview.getChildren().add(x3); overview.getChildren().add(getSeparator(overview)); if (!occupation.getLevelFour().equals(Text.NOT_SET)) { Label x4 = new Label(String.format(Text.F_SAVED_DATA_VALUE_SUBCATEGORY, EntryType.JOB.getValue(), Text.OCCUPATION_LEVEL_FOUR, occupation.getLevelFour())); x4.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> overview.getWidth(), overview.widthProperty())); overview.getChildren().add(x4); overview.getChildren().add(getSeparator(overview)); } } } } // add all selected Data for (Node n : datalist.getChildren()) { if (n instanceof EntryView) // this should always be true { EntryView i = (EntryView) n; EntryType type = i.getEntryType(); if (i.getSelected()) { if (type.equals(EntryType.WORKOUT) || type.equals(EntryType.RECORD) || type.equals(EntryType.DATE_OF_BIRTH)) { // selected ones with subelements for (SubEntryView s : i.getSelectedSubElements()) { Label x = new Label(String.format(Text.F_SAVED_DATA_VALUE_SUBCATEGORY_ENTRIES, type.getValue(), Utils.shortenHKStrings(s.getName()), s.getValue())); if (type.equals(EntryType.DATE_OF_BIRTH)) { x = new Label(String.format(Text.F_SAVED_DATA_VALUE_SUBCATEGORY, type.getValue(), s.getName(), s.getValue())); } x.minWidthProperty().bind( Bindings.createDoubleBinding(() -> overview.getWidth(), overview.widthProperty())); overview.getChildren().add(x); overview.getChildren().add(getSeparator(overview)); } } else { // selected ones without subelements String value = i.getValue(); Label x = new Label(String.format(Text.F_SAVED_DATA_VALUE, type.getValue(), value)); if (type.equals(EntryType.ACTIVITY_SUMMARY)) { x = new Label(String.format(Text.F_SAVED_DATA_ENTRIES, type.getValue(), value)); } x.minWidthProperty().bind( Bindings.createDoubleBinding(() -> overview.getWidth(), overview.widthProperty())); overview.getChildren().add(x); overview.getChildren().add(getSeparator(overview)); } } } } return container; } /** * creates the view to show the privacy policy * * @return */ public VBox getPrivacyView() { VBox container = new VBox(); container.setId("container"); container.getChildren().add(getHeaderLabel(PrivacyStatementText.heading,22)); container.getChildren().add(getContentLabel(PrivacyStatementText.responsibleParty, container)); container.getChildren().add(getContentLabel(PrivacyStatementText.introText, container)); container.getChildren().add(getHeaderLabel(PrivacyStatementText.headingSec1, 16)); container.getChildren().add(getContentLabel(PrivacyStatementText.contentSec1, container)); container.getChildren().add(getHeaderLabel(PrivacyStatementText.headingSec2, 16)); container.getChildren().add(getContentLabel(PrivacyStatementText.contentSec2, container)); container.getChildren().add(getHeaderLabel(PrivacyStatementText.headingSec3, 16)); container.getChildren().add(getContentLabel(PrivacyStatementText.contentSec3, container)); container.getChildren().add(getHeaderLabel(PrivacyStatementText.headingSec4, 16)); container.getChildren().add(getContentLabel(PrivacyStatementText.contentSec4, container)); container.getChildren().add(getHeaderLabel(PrivacyStatementText.headingSec5, 16)); container.getChildren().add(getContentLabel(PrivacyStatementText.contentSec5, container)); return container; } private Label getHeaderLabel(String text, int size) { Label res = new Label(text); res.setStyle("-fx-font-weight: bold; -fx-font-size: "+size+"px;"); return res; } /** * Creates a label for the Privacy view which is used for normal text content. Fills the whole width of its parent * @param text Text to be displayed * @param container Parent to set the width * @return created label */ private Label getContentLabel(String text, Pane container) { Label res = new Label(text); res.minWidthProperty() .bind(Bindings.createDoubleBinding(() -> container.getWidth(), container.widthProperty())); return res; } /** * Creates the files in the temp directory * * @throws WrappedException */ public void createTempFiles() throws WrappedException { filesInTempWithDesc = worker.writeSelectedDataToFiles(new WriteSelection(datalist), occupation); } @Override public void changed(ObservableValue checkbox, Boolean oldValue, Boolean newValue) { if (newValue) { selectCount++; } else { selectCount--; } if (selectCount > 0 && dirForSaving != null) { updateNav(NavState.DATA_AND_PATH_SELECTED); } else { updateNav(NavState.SELECT_DATA); } } }