From 77ddb56d6945861e6c4b6b19d8f2f087e8add469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98ystein=20Kristoffer=20Tveit?= Date: Tue, 20 Apr 2021 09:28:45 +0000 Subject: [PATCH] Extract logic from classes --- .../app/controllers/EditorController.java | 67 +++----- .../app/controllers/FiletreeController.java | 117 ++------------ .../app/controllers/MenubarController.java | 87 ++++------- .../app/controllers/ModelineController.java | 2 + .../java/app/events/FileSelectedEvent.java | 8 +- src/main/java/app/events/OpenFileEvent.java | 8 +- .../java/app/events/OpenProjectEvent.java | 8 +- src/main/java/app/events/SaveFileEvent.java | 14 +- .../java/app/interfaces/FileManagement.java | 13 -- src/main/java/app/service/DialogBoxes.java | 14 ++ src/main/java/app/service/FileOperations.java | 118 ++++++++++++++ .../java/app/service/FiletreeOperations.java | 146 ++++++++++++++++++ .../app/controllers/EditorControllerTest.java | 17 +- .../controllers/MenubarControllerTest.java | 46 ++++++ 14 files changed, 416 insertions(+), 249 deletions(-) delete mode 100644 src/main/java/app/interfaces/FileManagement.java create mode 100644 src/main/java/app/service/DialogBoxes.java create mode 100644 src/main/java/app/service/FileOperations.java create mode 100644 src/main/java/app/service/FiletreeOperations.java create mode 100644 src/test/java/app/controllers/MenubarControllerTest.java diff --git a/src/main/java/app/controllers/EditorController.java b/src/main/java/app/controllers/EditorController.java index 909934f..4e93761 100644 --- a/src/main/java/app/controllers/EditorController.java +++ b/src/main/java/app/controllers/EditorController.java @@ -1,17 +1,13 @@ package app.controllers; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintWriter; import java.net.URL; +import java.nio.file.Path; import java.util.Collection; import java.util.ResourceBundle; -import java.util.Scanner; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; -import org.apache.commons.lang.ObjectUtils.Null; import org.fxmisc.richtext.CodeArea; import org.fxmisc.richtext.LineNumberFactory; import org.fxmisc.richtext.model.StyleSpans; @@ -23,26 +19,26 @@ import app.events.CutEvent; import app.events.EditorChangedEvent; import app.events.LanguageChangedEvent; +import app.events.OpenFileEvent; import app.events.PasteEvent; import app.events.RedoEvent; import app.events.SaveFileEvent; import app.events.ToggleCommentEvent; import app.events.ToggleWrapTextEvent; import app.events.UndoEvent; -import app.interfaces.FileManagement; import app.events.FileSaveStateChangedEvent; import app.events.FileSelectedEvent; import app.model.Model; +import app.service.FileOperations; import app.service.LanguageOperations; import javafx.fxml.FXML; import javafx.fxml.Initializable; -import javafx.scene.control.Alert; -import javafx.scene.control.Alert.AlertType; +import javafx.stage.Stage; /** * A FXML controller that controls the editor component of the UI */ -public class EditorController implements Initializable, Controller, FileManagement { +public class EditorController implements Initializable, Controller { @FXML private CodeArea editor; @@ -96,6 +92,7 @@ public class EditorController implements Initializable, Controller, FileManageme * ProgrammingLanguage.commentLine(line) */ private void toggleComment() { + // TODO: This logic might need to be moved to LanguageOperations if (editor.getSelectedText().equals("")) { String currentLine = editor.getText(editor.getCurrentParagraph()); @@ -149,52 +146,26 @@ public class EditorController implements Initializable, Controller, FileManageme * * @param filePath The path of the file */ - public void setEditorContent(String filePath) { - // if (filePath == null) { - // editor.clear(); - // editor.appendText("// New File"); - // return; - // } - try (Scanner sc = new Scanner(new File(filePath))) { - // if (filePath.endsWith(".java") || filePath.endsWith(".md")) { - editor.clear(); - while (sc.hasNextLine()) { - editor.appendText(sc.nextLine() + "\n"); - } - // } else { - // throw new FileNotFoundException(); - // } - - } catch (FileNotFoundException ex) { - Alert error = new Alert(AlertType.ERROR); - error.setContentText("Could not be opened!\nMust be a java or md file or not null. Try again."); - - error.showAndWait(); - System.err.println(filePath); - } + public void setEditorContent(Path filePath) { + String newContent = FileOperations.readFile(filePath); + editor.clear(); + editor.appendText(newContent); } /** * Saving/Writing to the file based on the spesific filepath. Otherwise it will * open an error dialog to give the user feedback about what has happened. - * - * @param filePath The path of the file */ - public void saveCodeArea(String filePath) { - try (PrintWriter writer = new PrintWriter(new File(filePath))) { - if (filePath.endsWith(".java") || filePath.endsWith(".md")) { - writer.println(editor.getText()); - } else { - throw new FileNotFoundException(); - } + public void saveCodeArea(boolean isNewFile) { + Stage stage = (Stage) editor.getScene().getWindow(); - } catch (FileNotFoundException ex) { - Alert error = new Alert(AlertType.ERROR); - error.setContentText("Could not save file!\nMust be a java or md file. Try again."); - - error.showAndWait(); - System.err.println(filePath); + if (isNewFile && FileOperations.saveFileWithDialog(stage, editor.getText())) { + this.eventBus.post(new OpenFileEvent(Model.getActiveFilePath())); + this.eventBus.post(new FileSaveStateChangedEvent(true)); } + else if (FileOperations.saveFile(Model.getProjectPath().toString(), editor.getText())) { + this.eventBus.post(new FileSaveStateChangedEvent(true)); + } } /** @@ -219,7 +190,7 @@ public class EditorController implements Initializable, Controller, FileManageme */ @Subscribe private void handle(SaveFileEvent event) { - this.saveCodeArea(event.getPath()); + this.saveCodeArea(event.getIsNewFile()); } @Subscribe diff --git a/src/main/java/app/controllers/FiletreeController.java b/src/main/java/app/controllers/FiletreeController.java index 68184d3..bec339b 100644 --- a/src/main/java/app/controllers/FiletreeController.java +++ b/src/main/java/app/controllers/FiletreeController.java @@ -4,18 +4,12 @@ import javafx.fxml.FXML; import javafx.scene.control.CheckBoxTreeItem; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeView; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; import java.io.File; -import java.io.IOException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; import java.util.ResourceBundle; import com.google.common.eventbus.EventBus; @@ -24,6 +18,7 @@ import com.google.common.eventbus.Subscribe; import app.events.FileSelectedEvent; import app.events.OpenProjectEvent; import app.model.Model; +import app.service.FiletreeOperations; import javafx.fxml.Initializable; /** @@ -33,19 +28,11 @@ public class FiletreeController implements Initializable, Controller { private EventBus eventBus; - // Creating the images for the icons. - Image folder = new Image(getClass().getResourceAsStream("/graphics/folder.png")); - Image md = new Image(getClass().getResourceAsStream("/graphics/md.png")); - Image java = new Image(getClass().getResourceAsStream("/graphics/java.png")); - Image placeholder = new Image(getClass().getResourceAsStream("/graphics/placeholder.png")); - @FXML private TreeView filetree; @Override - public void initialize(URL url, ResourceBundle resourceBundle) { - // TODO: Implement - } + public void initialize(URL url, ResourceBundle resourceBundle) {} @Override public void setEventBus(EventBus eventBus) { @@ -67,91 +54,11 @@ public class FiletreeController implements Initializable, Controller { filetree.setShowRoot(false); File fileInputChosen = new File(inputChosen); - generateTree(fileInputChosen, root); + FiletreeOperations.generateTree(fileInputChosen, root); filetree.setRoot(root); } - /** - * The method to generate the fileTree recursively. If it is a directory a - * CheckBoxStringItem is created and the method is called again. It goes through - * all until every directory or file inside the orginal CheckBoxItem is made. If - * the item is a file it sends it to the help function checkExtension which is - * described below. - */ - private void generateTree(File file, CheckBoxTreeItem parent) { - - if (file.isDirectory()) { - CheckBoxTreeItem element = new CheckBoxTreeItem<>(file.getName(), new ImageView(folder)); - parent.getChildren().add(element); - - List dirList = new ArrayList<>(); - List fileList = new ArrayList<>(); - - sortFiles(dirList, fileList, file); - - for (File f : dirList) { - generateTree(f, element); - } - - } else { - checkExtensions(file, parent); - } - } - - /** - * A helping function to sort the files/folders in the fileTree so that it shows - * in the correct order. - */ - private void sortFiles(List dirList, List fileList, File file) { - for (File f : file.listFiles()) { - if (f.isDirectory()) - dirList.add(f); - else { - fileList.add(f); - } - - } - dirList.addAll(fileList); - - } - - /** - * A help function to check if the extensions match .java or .md to insert the - * specific icons and sending it to another help funtion createExtension to - * create the new CheckboxTreeItem that will add to the parent. - */ - private void checkExtensions(File file, CheckBoxTreeItem parent) { - String name = file.getName(); - String ext = (name.substring(file.getName().lastIndexOf(".") + 1, file.getName().length())); - - try { - createExtension(name, getIconForFile(file), parent); - } catch (Exception e) { - System.err.println("ICON NOT FOUND: " + file.getPath()); - } - - // if ("java".equals(ext)) - // createExtension(name, java, parent); - // else if ("md".equals(ext)) - // createExtension(name, md, parent); - // else - // createExtension(name, placeholder, parent); - } - - private Image getIconForFile(File file) throws IOException { - String mimeType = Files.probeContentType(file.toPath()).replace('/', '-'); - String iconPath = (mimeType != null) - ? "/graphics/filetreeicons/" + mimeType + ".png" - : "/graphics/filetreeicons/file.png"; - return new Image(getClass().getResourceAsStream(iconPath)); - } - - private void createExtension(String name, Image image, CheckBoxTreeItem parent) { - CheckBoxTreeItem element = new CheckBoxTreeItem<>(name, new ImageView(image)); - parent.getChildren().add(element); - } - /* ------------------------------------------------------------------------ */ /* MouseClick */ /* ------------------------------------------------------------------------ */ @@ -164,20 +71,14 @@ public class FiletreeController implements Initializable, Controller { private void handleMouseClick(MouseEvent event) { if (event.getClickCount() == 2) { TreeItem item = filetree.getSelectionModel().getSelectedItem(); - String root = Model.getProjectPath().getFileName().toString(); - String path = ""; - while (!root.equals(item.getValue())) { - path = File.separator + item.getValue() + path; - item = item.getParent(); - } - path = Model.getProjectPath() + path; - Path pathToString = Paths.get(path); - if (!Files.isDirectory(pathToString)) { - Model.setActiveFilePath(pathToString); + Path path = FiletreeOperations.getPathOfTreeItem(item); + + if (!Files.isDirectory(path)) { + // TODO: Add setActiveFilePath Model modification into FileSelectedEvent + Model.setActiveFilePath(path); this.eventBus.post(new FileSelectedEvent(path)); } - } } @@ -191,7 +92,7 @@ public class FiletreeController implements Initializable, Controller { @Subscribe private void handle(OpenProjectEvent event) { - this.showTree(event.getPath()); + this.showTree(event.getPath().toString()); } } diff --git a/src/main/java/app/controllers/MenubarController.java b/src/main/java/app/controllers/MenubarController.java index c3586fe..4de1da3 100644 --- a/src/main/java/app/controllers/MenubarController.java +++ b/src/main/java/app/controllers/MenubarController.java @@ -1,9 +1,8 @@ package app.controllers; import java.io.File; +import java.io.FileNotFoundException; import java.net.URL; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ResourceBundle; import com.google.common.eventbus.EventBus; @@ -12,7 +11,6 @@ import com.google.common.eventbus.Subscribe; import app.events.CopyEvent; import app.events.CutEvent; import app.events.ExitApplicationEvent; -import app.events.FileSaveStateChangedEvent; import app.events.FileSelectedEvent; import app.events.LanguageChangedEvent; import app.events.OpenLinkInBrowserEvent; @@ -25,6 +23,8 @@ import app.events.ToggleCommentEvent; import app.events.ToggleWrapTextEvent; import app.events.UndoEvent; import app.model.Model; +import app.service.DialogBoxes; +import app.service.FileOperations; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; @@ -32,8 +32,6 @@ import javafx.scene.control.CheckMenuItem; import javafx.scene.control.MenuBar; import javafx.scene.control.RadioMenuItem; import javafx.scene.control.ToggleGroup; -import javafx.stage.DirectoryChooser; -import javafx.stage.FileChooser; import javafx.stage.Stage; /** @@ -50,9 +48,7 @@ public class MenubarController implements Initializable, Controller { private ToggleGroup languageToggleGroup; @Override - public void initialize(URL url, ResourceBundle resourceBundle) { - // TODO: implement - } + public void initialize(URL url, ResourceBundle resourceBundle) {} @Override public void setEventBus(EventBus eventBus) { @@ -65,6 +61,7 @@ public class MenubarController implements Initializable, Controller { /* ------------------------------------------------------------------------ */ @FXML private void handleNewFile() { + // TODO: Move Model modification inside event Model.setActiveFilePath(null); this.eventBus.post(new FileSelectedEvent(null)); } @@ -86,18 +83,17 @@ public class MenubarController implements Initializable, Controller { */ @FXML public void handleOpenFile() { - FileChooser fc = new FileChooser(); - fc.setTitle("Open File"); Stage stage = (Stage) menubar.getScene().getWindow(); - File chosenFile = fc.showOpenDialog(stage); - if (chosenFile != null) { - String correctFormat = chosenFile.getAbsolutePath().replace("\\", "\\\\"); + try { + File file = FileOperations.openFileWithDialog(stage); - Model.setActiveFilePath(chosenFile.toPath()); - this.eventBus.post(new FileSelectedEvent(correctFormat)); + // TODO: Move Model modification inside event + Model.setActiveFilePath(file.toPath()); + this.eventBus.post(new FileSelectedEvent(file.toPath())); + } catch (FileNotFoundException e) { + DialogBoxes.showErrorMessage("File not found!"); } - } /** @@ -105,19 +101,17 @@ public class MenubarController implements Initializable, Controller { */ @FXML private void handleOpenProject() { - DirectoryChooser dc = new DirectoryChooser(); - dc.setTitle("Open Project"); Stage stage = (Stage) menubar.getScene().getWindow(); - File chosenDir = dc.showDialog(stage); - if (chosenDir != null) { - String correctFormat = chosenDir.getAbsolutePath().replace("\\", "\\\\"); - - Model.setProjectPath(chosenDir.toPath()); - this.eventBus.post(new OpenProjectEvent(correctFormat)); + try { + File dir = FileOperations.openFolderWithDialog(stage); + // TODO: Move Model modification inside event + Model.setProjectPath(dir.toPath()); + this.eventBus.post(new OpenProjectEvent(dir.toPath())); + } catch (FileNotFoundException e) { + DialogBoxes.showErrorMessage("Folder not found!"); } - } /* ------------------------------------------------------------------------ */ @@ -129,12 +123,10 @@ public class MenubarController implements Initializable, Controller { */ @FXML private void handleSaveFile() { - if (Model.getActiveFilePath() != null) { - this.eventBus.post(new SaveFileEvent(Model.getActiveFilePath().toString())); - this.eventBus.post(new FileSaveStateChangedEvent(true)); - } else { + if (Model.getActiveFilePath() != null) + this.eventBus.post(new SaveFileEvent(false)); + else // New file needs a path handleSaveAsFile(); - } } /** @@ -142,29 +134,7 @@ public class MenubarController implements Initializable, Controller { */ @FXML private void handleSaveAsFile() { - FileChooser fc = new FileChooser(); - fc.setTitle("Save as"); - if (Model.getProjectPath() != null) { - fc.setInitialDirectory(Model.getProjectPath().toFile()); - } - Stage stage = (Stage) menubar.getScene().getWindow(); - - FileChooser.ExtensionFilter extJava = new FileChooser.ExtensionFilter("Java", "*.java"); - FileChooser.ExtensionFilter extMd = new FileChooser.ExtensionFilter("Markdown", "*.md"); - - fc.getExtensionFilters().addAll(extJava, extMd); - - File chosenLocation = fc.showSaveDialog(stage); - - if (chosenLocation != null) { - String chosenLocationToString = chosenLocation.toString(); - this.eventBus.post(new SaveFileEvent(chosenLocationToString)); - this.eventBus.post(new FileSelectedEvent(chosenLocationToString)); - - Path chosenLocationToPath = Paths.get(chosenLocationToString); - Model.setActiveFilePath(chosenLocationToPath); - this.eventBus.post(new FileSaveStateChangedEvent(true)); - } + this.eventBus.post(new SaveFileEvent(true)); } /** @@ -274,8 +244,15 @@ public class MenubarController implements Initializable, Controller { */ @Subscribe private void handle(LanguageChangedEvent event) { - this.languageToggleGroup.getToggles().stream().map(RadioMenuItem.class::cast) - .filter(t -> t.getId().equals("toggle" + event.getLanguage())).findFirst().orElseThrow().setSelected(true); + this.languageToggleGroup + .getToggles() + .stream() + .map(RadioMenuItem.class::cast) + .filter(t -> t.getId() + .equals("toggle" + event.getLanguage())) + .findFirst() + .orElseThrow() + .setSelected(true); } } diff --git a/src/main/java/app/controllers/ModelineController.java b/src/main/java/app/controllers/ModelineController.java index 418184c..5aa9c0c 100644 --- a/src/main/java/app/controllers/ModelineController.java +++ b/src/main/java/app/controllers/ModelineController.java @@ -29,6 +29,8 @@ public class ModelineController implements Initializable, Controller { private EventBus eventBus; + // TODO: Add current filename label + @Override public void initialize(URL url, ResourceBundle resourceBundle) { setColumnRow(0, 1); diff --git a/src/main/java/app/events/FileSelectedEvent.java b/src/main/java/app/events/FileSelectedEvent.java index 052b187..21647c7 100644 --- a/src/main/java/app/events/FileSelectedEvent.java +++ b/src/main/java/app/events/FileSelectedEvent.java @@ -1,5 +1,7 @@ package app.events; +import java.nio.file.Path; + /** * Event signalizing that a file was selected in the filetree. * @@ -7,7 +9,7 @@ package app.events; */ public class FileSelectedEvent extends Event { - private String path; + private Path path; /** * Event signalizing that a file was selected in the filetree. @@ -15,14 +17,14 @@ public class FileSelectedEvent extends Event { * Not to be confused with {@link OpenFileEvent} * @param path The path of the selected file */ - public FileSelectedEvent(String path) { + public FileSelectedEvent(Path path) { this.path = path; } /** * @return The path of the selected file */ - public String getPath() { + public Path getPath() { return this.path; } diff --git a/src/main/java/app/events/OpenFileEvent.java b/src/main/java/app/events/OpenFileEvent.java index 8227135..0c7b9ec 100644 --- a/src/main/java/app/events/OpenFileEvent.java +++ b/src/main/java/app/events/OpenFileEvent.java @@ -1,5 +1,7 @@ package app.events; +import java.nio.file.Path; + /** * Event signalizing that a file outside the current project is supposed to be opened in the editor. * @@ -7,20 +9,20 @@ package app.events; */ public class OpenFileEvent extends Event { - private String path; + private Path path; /** * Event signalizing that a file outside the current project is supposed to be opened in the editor. * @param path The path of the file to be opened */ - public OpenFileEvent(String path) { + public OpenFileEvent(Path path) { this.path = path; } /** * @return The path of the file to be opened */ - public String getPath() { + public Path getPath() { return this.path; } diff --git a/src/main/java/app/events/OpenProjectEvent.java b/src/main/java/app/events/OpenProjectEvent.java index 9701e84..41e058a 100644 --- a/src/main/java/app/events/OpenProjectEvent.java +++ b/src/main/java/app/events/OpenProjectEvent.java @@ -1,24 +1,26 @@ package app.events; +import java.nio.file.Path; + /** * Event signalizing that a folder is supposed to be opened in the filetree. */ public class OpenProjectEvent extends Event { - private String path; + private Path path; /** * Event signalizing that a folder is supposed to be opened in the filetree. * @param path The path of the folder to be opened */ - public OpenProjectEvent(String path) { + public OpenProjectEvent(Path path) { this.path = path; } /** * @return The path of the folder to be opened */ - public String getPath() { + public Path getPath() { return this.path; } } diff --git a/src/main/java/app/events/SaveFileEvent.java b/src/main/java/app/events/SaveFileEvent.java index d543bb8..c8210d0 100644 --- a/src/main/java/app/events/SaveFileEvent.java +++ b/src/main/java/app/events/SaveFileEvent.java @@ -2,24 +2,24 @@ package app.events; public class SaveFileEvent extends Event { - private String path; + private boolean isNewFile; /** * Event signalizing that a file is to be saved. * * Not to be confused with {@link FileSelectedEvent} * - * @param path The path of the selected file + * @param isNewFile The path of the selected file */ - public SaveFileEvent(String path) { - this.path = path; + public SaveFileEvent(boolean isNewFile) { + this.isNewFile = isNewFile; } /** - * @return The path of the selected file to be saved. + * @return Whether or not */ - public String getPath() { - return this.path; + public boolean getIsNewFile() { + return this.isNewFile; } } diff --git a/src/main/java/app/interfaces/FileManagement.java b/src/main/java/app/interfaces/FileManagement.java deleted file mode 100644 index 2b4ec9d..0000000 --- a/src/main/java/app/interfaces/FileManagement.java +++ /dev/null @@ -1,13 +0,0 @@ -package app.interfaces; - -/* -* An interface that contains two methods for reading and writing to files. -*/ - -public interface FileManagement { - - void setEditorContent(String filePath); - - void saveCodeArea(String filePath); - -} diff --git a/src/main/java/app/service/DialogBoxes.java b/src/main/java/app/service/DialogBoxes.java new file mode 100644 index 0000000..9a2e064 --- /dev/null +++ b/src/main/java/app/service/DialogBoxes.java @@ -0,0 +1,14 @@ +package app.service; + +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; + +public class DialogBoxes { + + public static void showErrorMessage(String errorMessage) { + Alert error = new Alert(AlertType.ERROR); + error.setContentText(errorMessage); + error.showAndWait(); + } + +} diff --git a/src/main/java/app/service/FileOperations.java b/src/main/java/app/service/FileOperations.java new file mode 100644 index 0000000..5e84b65 --- /dev/null +++ b/src/main/java/app/service/FileOperations.java @@ -0,0 +1,118 @@ +package app.service; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.nio.file.Path; +import java.util.Scanner; + +import app.model.Model; +import javafx.stage.DirectoryChooser; +import javafx.stage.FileChooser; +import javafx.stage.Stage; + +public class FileOperations { + + // FIXME: This class contains bugs when opening fiies and folders. + // TODO: Needs documentation and cleanup + // TODO: This class needs to be extensively error checked + + public static File openFileWithDialog(Stage stage) throws FileNotFoundException { + + FileChooser fc = new FileChooser(); + fc.setTitle("Open File"); + + File chosenFile = fc.showOpenDialog(stage); + + if (chosenFile == null) + throw new FileNotFoundException(); + // if (chosenFile != null) { + // String correctFormat = chosenFile.getAbsolutePath().replace("\\", "\\\\"); + // } + + return chosenFile; + + } + + public static File openFolderWithDialog(Stage stage) throws FileNotFoundException { + + DirectoryChooser dc = new DirectoryChooser(); + dc.setTitle("Open Project"); + + File dir = dc.showDialog(stage); + + if (dir == null) + throw new FileNotFoundException(); + + return dir; + } + + public static boolean saveFile(String filepath, String content) { + + try (PrintWriter writer = new PrintWriter(new File(filepath))) { + if (filepath.endsWith(".java") || filepath.endsWith(".md")) { + writer.println(content); + } else { + throw new FileNotFoundException(); + } + + } catch (FileNotFoundException ex) { + + DialogBoxes.showErrorMessage("Could not save file!\nMust be a java or md file. Try again."); + System.err.println(filepath); + return false; + } + return true; + + } + + public static boolean saveFileWithDialog(Stage stage, String content) { + FileChooser fc = new FileChooser(); + fc.setTitle("Save as"); + + if (Model.getProjectPath() != null) + fc.setInitialDirectory(Model.getProjectPath().toFile()); + + FileChooser.ExtensionFilter extJava = new FileChooser.ExtensionFilter("Java", "*.java"); + FileChooser.ExtensionFilter extMd = new FileChooser.ExtensionFilter("Markdown", "*.md"); + + fc.getExtensionFilters().addAll(extJava, extMd); + + File chosenLocation = fc.showSaveDialog(stage); + if (chosenLocation == null) + return false; + + if (saveFile(chosenLocation.getAbsolutePath(), content)) { + Model.setActiveFilePath(chosenLocation.toPath()); + return true; + } + + return false; + } + + public static String readFile(Path filePath) { + + if (filePath == null) + return ""; + + String result = ""; + + try (Scanner sc = new Scanner(filePath.toFile())) { + if (filePath.endsWith(".java") || filePath.endsWith(".md")) { + while (sc.hasNextLine()) { + result += (sc.nextLine() + "\n"); + } + } else { + throw new FileNotFoundException(); + } + + } catch (FileNotFoundException ex) { + DialogBoxes.showErrorMessage("Could not be opened!\nMust be a java or md file or not null. Try again."); + System.err.println(filePath); + } + + return result; + + } + +} diff --git a/src/main/java/app/service/FiletreeOperations.java b/src/main/java/app/service/FiletreeOperations.java new file mode 100644 index 0000000..13e9344 --- /dev/null +++ b/src/main/java/app/service/FiletreeOperations.java @@ -0,0 +1,146 @@ +package app.service; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +import app.model.Model; +import javafx.scene.control.CheckBoxTreeItem; +import javafx.scene.control.TreeItem; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; + +public class FiletreeOperations { + + // FIXME: File specific icons not working properly + // TODO: Clean up code that is not in use + + // Creating the images for the icons. + Image folder = new Image(getClass().getResourceAsStream("/graphics/folder.png")); + Image md = new Image(getClass().getResourceAsStream("/graphics/md.png")); + Image java = new Image(getClass().getResourceAsStream("/graphics/java.png")); + Image placeholder = new Image(getClass().getResourceAsStream("/graphics/placeholder.png")); + + // TODO: Error check for recursiveness, and files without icons + + /** + * The method to generate the fileTree recursively. If it is a directory a + * CheckBoxStringItem is created and the method is called again. It goes through + * all until every directory or file inside the orginal CheckBoxItem is made. If + * the item is a file it sends it to the help function checkExtension which is + * described below. + */ + public static void generateTree(File file, CheckBoxTreeItem parent) { + + Image folder = new Image(FiletreeOperations.class.getResourceAsStream("/graphics/folder.png")); + + if (file.isDirectory()) { + CheckBoxTreeItem element = new CheckBoxTreeItem<>(file.getName(), new ImageView(folder)); + parent.getChildren().add(element); + + List dirList = new ArrayList<>(); + List fileList = new ArrayList<>(); + + sortFiles(dirList, fileList, file); + + for (File f : dirList) { + generateTree(f, element); + } + + } else { + checkExtensions(file, parent); + } + } + + /** + * A helping function to sort the files/folders in the fileTree so that it shows + * in the correct order. + */ + private static void sortFiles(List dirList, List fileList, File file) { + for (File f : file.listFiles()) { + if (f.isDirectory()) + dirList.add(f); + else + fileList.add(f); + } + dirList.addAll(fileList); + + } + + /** + * A help function to check if the extensions match .java or .md to insert the + * specific icons and sending it to another help funtion createExtension to + * create the new CheckboxTreeItem that will add to the parent. + */ + private static void checkExtensions(File file, CheckBoxTreeItem parent) { + String name = file.getName(); + String ext = (name.substring(file.getName().lastIndexOf(".") + 1, file.getName().length())); + + try { + createExtension(name, getIconForFile(file), parent); + } catch (Exception e) { + System.err.println("[ERROR]: DEFAULT FILE ICON NOT FOUND"); + } + + // if ("java".equals(ext)) + // createExtension(name, java, parent); + // else if ("md".equals(ext)) + // createExtension(name, md, parent); + // else + // createExtension(name, placeholder, parent); + } + + private static Image getIconForFile(File file) throws IOException { + Image icon; + + try { + String mimeType = Files.probeContentType(file.toPath()).replace('/', '-'); + + String iconPath = "/graphics/filetreeicons/" + mimeType + ".png"; + if (mimeType == null) throw new IOException(); + + InputStream imageData = FiletreeOperations.class.getResourceAsStream(iconPath); + if (imageData == null) throw new IOException(); + + icon = new Image(imageData); + + } catch (IOException e) { + System.err.println("[ERROR]: ICON NOT FOUND: " + file.getPath()); + + // String iconPath = "/graphics/filetreeicons/file.png"; + String iconPath = "/graphics/placeholder.png"; + + InputStream imageData = FileOperations.class.getResourceAsStream(iconPath); + if (imageData == null) throw new IOException(); + + icon = new Image(imageData); + } + + return icon; + } + + private static void createExtension(String name, Image image, CheckBoxTreeItem parent) { + CheckBoxTreeItem element = new CheckBoxTreeItem<>(name, new ImageView(image)); + parent.getChildren().add(element); + } + + public static Path getPathOfTreeItem(TreeItem item) { + String root = Model.getProjectPath().getFileName().toString(); + String path = ""; + while (!root.equals(item.getValue())) { + path = File.separator + item.getValue() + path; + item = item.getParent(); + } + + path = Model.getProjectPath().toString() + path; + Path pathToString = Paths.get(path); + + return pathToString; + } + +} diff --git a/src/test/java/app/controllers/EditorControllerTest.java b/src/test/java/app/controllers/EditorControllerTest.java index aaaf10e..7fae56f 100644 --- a/src/test/java/app/controllers/EditorControllerTest.java +++ b/src/test/java/app/controllers/EditorControllerTest.java @@ -37,6 +37,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import app.testing.FxTestTemplate; import app.model.Model; import app.model.ProgrammingLanguage; +import app.service.FileOperations; import app.service.LanguageOperations; import app.events.CopyEvent; import app.events.CutEvent; @@ -88,16 +89,14 @@ public class EditorControllerTest extends FxTestTemplate { String resourcePath = "/testfile.txt"; String filePath = getClass().getResource(resourcePath).getPath(); File file = new File(filePath); - List content = - Files.readAllLines(file.toPath()) - .stream() - .map(s -> s + "\n") - .collect(Collectors.toList()); - eventBus.post(new FileSelectedEvent(filePath)); - verify(editor, times(content.size())).appendText(captor.capture()); + eventBus.post(new FileSelectedEvent(file.toPath())); + try (MockedStatic mocked = mockStatic(FileOperations.class)) { + mocked.when(() -> FileOperations.readFile(any())) + .thenReturn(""); - assertEquals(content, captor.getAllValues()); + mocked.verify(() -> FileOperations.readFile(file.toPath())); + } } @Test @@ -105,7 +104,7 @@ public class EditorControllerTest extends FxTestTemplate { public void testFileSelectedEventWithUnrealFile() throws IOException { String brokenFilePath = "/doesNotExist.txt"; - eventBus.post(new FileSelectedEvent(brokenFilePath)); + eventBus.post(new FileSelectedEvent(new File(brokenFilePath).toPath())); verify(editor, never()).clear(); } diff --git a/src/test/java/app/controllers/MenubarControllerTest.java b/src/test/java/app/controllers/MenubarControllerTest.java new file mode 100644 index 0000000..996f8ac --- /dev/null +++ b/src/test/java/app/controllers/MenubarControllerTest.java @@ -0,0 +1,46 @@ +package app.controllers; + +import com.google.common.eventbus.EventBus; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import app.testing.FxTestTemplate; +import javafx.scene.control.MenuBar; +import javafx.scene.control.ToggleGroup; + +// https://stackoverflow.com/questions/60403458/testing-overriden-eventhandler-in-java-javafx-spring-boot + +@ExtendWith(MockitoExtension.class) +public class MenubarControllerTest extends FxTestTemplate { + + @Mock + private MenuBar menubar; + + @Mock + private ToggleGroup languageToggleGroup; + + private EventBus eventBus; + + @InjectMocks + private MenubarController controller; + + + @BeforeEach + public void insertEventBus() { + this.eventBus = new EventBus(); + this.controller.setEventBus(eventBus); + } + + @Test + @DisplayName("") + public void testHandleOpenFile() { + + } + +}