package view.hugo.pane; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.stage.Stage; import javafx.stage.WindowEvent; import model.hugo.Hugo; import model.toml.TomlConfig; import model.utility.CallbackVisitor; import model.utility.FileHandler; import view.filetree.FileTreeTable; import view.hugo.hmd.TabbedHMDPostEditor; import view.toml.TomlConfigEditor; import view.utils.ExceptionAlerter; import view.utils.TimedUpdaterUtil; import java.io.File; import java.io.IOException; import java.util.*; import java.util.prefs.Preferences; /** * Created by Sohan Chowdhury on 8/21/16. * Website: sohanchy.com * Email: [email protected] */ public class HugoPane extends Accordion { @FXML CheckBox autoOpenCheckBox; //Config Editor @FXML private TextField confBlogTitleField, confBlogAuthorField, confBlogDisqusField; @FXML private ChoiceBox<DirChoiceWrapper> confBlogThemeVBox; @FXML private Button confBlogPrefSaveButton; //BLOG @FXML private Button liveBlogServerToggleButton, buildBlogButton; @FXML private Button openBlogInBrowserButton; @FXML private Label buildStatusLabel; //Content @FXML private ChoiceBox<DirChoiceWrapper> writeContentTypeChoiceBox; @FXML private Button createContentTypeButton; @FXML private TextField contentTypeTextField; //Main LOGIC private String hugoBlogRootDirPath, hugoBlogOutputDirPath, hugoBlogContentDirPath, hugoBlogThemesDirPath; private String hugoSiteConfigFilePath; private boolean liveServerRunning = false; private Hugo hugoServer; private TabbedHMDPostEditor tabbedHMDPostEditor; @FXML private TitledPane blogTitledPane, prefTitledPane, contentTitledPane; private FileTreeTable fileTreeTable; public HugoPane() { super(); bindFxml(); setupGui(); String autoOpen = Preferences.userNodeForPackage(view.wizard.WelcomeWizard.class).get("auto_open", "false"); if (autoOpen.equals("true")) { autoOpenCheckBox.setSelected(true); } } private void setupGui() { this.setExpandedPane(contentTitledPane); //Disable Content folder create button if empty contentTypeTextField.textProperty().addListener((observable, oldValue, newValue) -> { createContentTypeButton.setDisable(newValue.trim().isEmpty()); }); } private void bindFxml() { FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("hugo_pane.fxml")); fxmlLoader.setRoot(this); fxmlLoader.setController(this); try { fxmlLoader.load(); } catch (IOException e) { System.out.println("Failed to load fxml" + e.getMessage()); ExceptionAlerter.showException(e); throw new RuntimeException(e); } this.getStyleClass().add("hugo-pane"); } public void setup(String hugoSiteDirPath, TabbedHMDPostEditor tabbedHMDPostEditor, FileTreeTable fileTreeTable) { setHugoSitePaths(hugoSiteDirPath); this.tabbedHMDPostEditor = tabbedHMDPostEditor; this.fileTreeTable = fileTreeTable; } private void reloadTreeTable() { if (fileTreeTable != null) { fileTreeTable.reloadTree(); } } public void setup(String hugoSiteDirPath, TabbedHMDPostEditor tabbedHMDPostEditor) { this.setup(hugoSiteDirPath, tabbedHMDPostEditor, null); } public void setHugoSitePaths(String hugoSiteDirPath) { this.hugoBlogRootDirPath = hugoSiteDirPath; this.hugoBlogContentDirPath = hugoSiteDirPath + File.separator + "content"; this.hugoBlogThemesDirPath = hugoSiteDirPath + File.separator + "themes"; this.hugoBlogOutputDirPath = hugoSiteDirPath + File.separator + "public"; this.hugoSiteConfigFilePath = hugoSiteDirPath + File.separator + "config.toml"; setupConfBlog(); buildContentTypesList(); } @FXML private void onLiveBlogServerToggle() { toggleLiveBlogServer(); updateBlogServerToggleButton(); TimedUpdaterUtil.callAfter(new CallbackVisitor() { @Override public void call() { if (!openBlogInBrowserButton.isDisabled() && !liveServerRunning) { updateBlogServerToggleButton(); ExceptionAlerter.showException(new Exception("Hugo faced a catastrophic error \n" + hugoServer.getHugoOut())); } } }); this.getScene().getWindow().setOnCloseRequest(new EventHandler<WindowEvent>() { @Override public void handle(WindowEvent event) { stopLiveBlogServer(); } }); } private void restartLiveBlogServerIfRunning() { if (liveServerRunning) { onLiveBlogServerToggle(); TimedUpdaterUtil.callAfter(new CallbackVisitor() { @Override public void call() { onLiveBlogServerToggle(); } }); } } private void updateBlogServerToggleButton() { if (!liveServerRunning) { liveBlogServerToggleButton.setText("Start Live Blog Server"); openBlogInBrowserButton.setDisable(true); } else { liveBlogServerToggleButton.setText("Stop Live Blog Server"); openBlogInBrowserButton.setDisable(false); } } @FXML private void onOpenBlogInBrowserButton() { HostServicesProviderUtil.INSTANCE.getHostServices().showDocument("http://localhost:1313"); } private void toggleLiveBlogServer() { if (!liveServerRunning) { hugoServer = new Hugo(hugoBlogRootDirPath); hugoServer.startHugoServer(new CallbackVisitor() { @Override public void call() { stopLiveBlogServer(); } }); liveServerRunning = hugoServer.isServerAlive(); } else { stopLiveBlogServer(); } } public void stopLiveBlogServer() { if (liveServerRunning) { hugoServer.stopHugoServer(); liveServerRunning = !liveServerRunning; } } @FXML private void onBuildBlog() { TomlConfig tomlConfig = new TomlConfig(hugoSiteConfigFilePath); TextInputDialog dialog = new TextInputDialog(tomlConfig.getTomlMap().get("baseURL").toString()); dialog.setTitle("Confirm BaseUrl"); dialog.setHeaderText("Where will you upload your site?\n" + "Ex: mywebsite.com/blog \n" + "If upload is in root ex: mywebsite.com then you can leave this as \"/\"\n" + "(If you don't understand just click OK)"); dialog.setContentText("Blog Upload BaseUrl: "); Optional<String> result = dialog.showAndWait(); if (result.isPresent()) { Map<String, Object> tomlConfigMap = tomlConfig.getTomlMap(); tomlConfigMap.put("baseURL", result.get()); tomlConfig.setTomlMap(tomlConfigMap); tomlConfig.writeTomlMap(); buildBlog(); } } private void buildBlog() { buildBlogButton.setDisable(true); buildStatusLabel.setText("Build Status: Building..."); Hugo hugoBuilder = new Hugo(hugoBlogRootDirPath); hugoBuilder.runHugoBuild(new CallbackVisitor() { @Override public void call() { buildStatusLabel.setText("Build Status: ..."); TimedUpdaterUtil.temporaryLabeledUpdate(buildStatusLabel, "Build Status: Done."); showBuildSuccess(); buildBlogButton.setDisable(false); } }); hugoBuilder.getPubDir(); } private void showBuildSuccess() { Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setTitle("Build Successful"); alert.setHeaderText("Your blog was built successfully!"); alert.setContentText("You can find the static files at:"); TextArea textArea = new TextArea(hugoBlogOutputDirPath); textArea.setEditable(false); textArea.setWrapText(true); textArea.setMaxWidth(Double.MAX_VALUE); textArea.setPrefRowCount(2); // Set expandable Exception into the dialog pane. alert.getDialogPane().setExpandableContent(textArea); alert.getDialogPane().setExpanded(true); alert.showAndWait(); } private void buildContentTypesList() { writeContentTypeChoiceBox.getItems().clear(); writeContentTypeChoiceBox.getItems().addAll(getDirChoiceWrapperList(hugoBlogContentDirPath)); writeContentTypeChoiceBox.getSelectionModel().selectFirst(); } public List<DirChoiceWrapper> getDirChoiceWrapperList(String dirContainerPath) { File[] dirList = new File(dirContainerPath).listFiles(File::isDirectory); List<DirChoiceWrapper> wrappedDirList = new ArrayList<DirChoiceWrapper>(); if (dirList == null) throw new AssertionError(); Arrays.sort(dirList, new Comparator<File>() { public int compare(File f1, File f2) { return Long.valueOf(f2.lastModified()).compareTo(f1.lastModified()); } }); for (File f : dirList) { wrappedDirList.add(new DirChoiceWrapper(f)); } return wrappedDirList; } @FXML private void onWriteButton() { String selectedDir = writeContentTypeChoiceBox.getValue().getDirPath(); TabbedHMDPostEditor.createNewPostAndOpen(tabbedHMDPostEditor, selectedDir); reloadTreeTable(); } @FXML private void onCreateType() { String dirPath = hugoBlogContentDirPath + File.separator + TabbedHMDPostEditor.toPrettyURL(contentTypeTextField.getText()); String oldText = createContentTypeButton.getText(); if (FileHandler.makeDir(dirPath)) { contentHasChanged(); reloadTreeTable(); TimedUpdaterUtil.temporaryLabeledUpdate(createContentTypeButton, "Done!"); } else { TimedUpdaterUtil.temporaryLabeledUpdate(createContentTypeButton, "Failed!"); } } @FXML private void onOpenAdvancedConfig() { Stage tomlConfigEditorStage = new Stage(); tomlConfigEditorStage.setTitle("Site Preference Editor (TOML)"); tomlConfigEditorStage.setScene(new Scene(new TomlConfigEditor(hugoSiteConfigFilePath))); tomlConfigEditorStage.showAndWait(); } public void contentHasChanged() { //Update UI here buildContentTypesList(); } private void setupConfBlog() { TomlConfig tomlConfig = new TomlConfig(hugoSiteConfigFilePath); confBlogTitleField.setText(tomlConfig.getTomlMap().get("title").toString()); setupConfBlogThemeVBox(tomlConfig); Map<String, Object> paramsMap = (Map<String, Object>) tomlConfig.getTomlMap().get("params"); String paramAuthor = (String) paramsMap.get("Author"); String paramDisqus = (String) paramsMap.get("Disqus"); confBlogAuthorField.setText(paramAuthor); confBlogDisqusField.setText(paramDisqus); } private void setupConfBlogThemeVBox(TomlConfig tomlConfig) { confBlogThemeVBox.getItems().clear(); List<DirChoiceWrapper> dirChoiceWrapperList = getDirChoiceWrapperList(hugoBlogThemesDirPath); confBlogThemeVBox.getItems().addAll(dirChoiceWrapperList); //Select Current Theme String currentlySelectedTheme = tomlConfig.getTomlMap().get("theme").toString(); int currentThemesIndex = dirChoiceWrapperList.indexOf( new DirChoiceWrapper( new File(hugoBlogThemesDirPath + File.separator + currentlySelectedTheme ) ) ); if (currentThemesIndex > -1) { confBlogThemeVBox.getSelectionModel().select(currentThemesIndex); } else { ExceptionAlerter.showException(new Exception("Config file has theme that is not in theme directory.")); } } @FXML private void onConfBlogPrefButton() { String userBlogTitle = confBlogTitleField.getText(); String userBlogTheme = confBlogThemeVBox.getValue().getName(); String userBlogParamAuthor = confBlogAuthorField.getText(); String userBlogParamDisqus = confBlogDisqusField.getText(); TomlConfig tomlConfig = new TomlConfig(hugoSiteConfigFilePath); Map<String, Object> mainTomlConfigMap = tomlConfig.getTomlMap(); mainTomlConfigMap.put("title", userBlogTitle); mainTomlConfigMap.put("theme", userBlogTheme); Map<String, Object> paramsMap = (Map<String, Object>) tomlConfig.getTomlMap().get("params"); paramsMap.put("Author", userBlogParamAuthor); paramsMap.put("Disqus", userBlogParamDisqus); mainTomlConfigMap.put("params", paramsMap); tomlConfig.setTomlMap(mainTomlConfigMap); restartLiveBlogServerIfRunning(); tomlConfig.writeTomlMap(); TimedUpdaterUtil.temporaryLabeledUpdate(confBlogPrefSaveButton, "Saved."); } @FXML private void autoOpenClicked() { if (autoOpenCheckBox.isSelected()) { Preferences.userNodeForPackage(view.wizard.WelcomeWizard.class).put("auto_open", "true"); } else { Preferences.userNodeForPackage(view.wizard.WelcomeWizard.class).put("auto_open", "false"); } } //For wrapping directory chosen private class DirChoiceWrapper { private File dir; DirChoiceWrapper(File dir) { this.dir = dir; } @Override public String toString() { return dir.getName(); } public File getDir() { return this.dir; } public String getDirPath() { return this.dir.getPath(); } @Override public boolean equals(Object obj) { if (obj instanceof DirChoiceWrapper) { return this.getDir().equals(((DirChoiceWrapper) obj).getDir()); } return super.equals(obj); } public String getName() { return this.dir.getName(); } } }