package com.teotigraphix.caustic.application; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.ResourceBundle; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.EventHandler; import javafx.scene.SceneBuilder; import javafx.scene.layout.Pane; import javafx.stage.DirectoryChooser; import javafx.stage.Stage; import javafx.stage.StageBuilder; import javafx.stage.WindowEvent; import javax.inject.Named; import com.cathive.fx.guice.GuiceApplication; import com.cathive.fx.guice.GuiceFXMLLoader; import com.google.inject.Inject; import com.google.inject.Module; import com.teotigraphix.caustic.application.IPreferenceManager.Editor; import com.teotigraphix.caustic.controller.IApplicationController; import com.teotigraphix.caustic.mediator.StageMediator; import com.teotigraphix.caustic.model.IStageModel; import com.teotigraphix.caustic.screen.IScreenManager; import com.teotigraphix.caustic.screen.IScreenView; import com.teotigraphix.caustic.utils.FileUtil; import com.teotigraphix.caustk.application.ICaustkApplicationProvider; import com.teotigraphix.caustk.core.CtkDebug; import com.teotigraphix.caustk.service.IInjectorService; /* App requirements; - config - ApplicationConfiguration - ApplicationConstants - ApplicationModule - FooApplication extends JavaFXApplication - resources - app/package/view/RootLayout.fxml - FooApplication.properties - APP_TITLE - APP_DIRECTORY - main.css Mediators - DesktopMediatorBase extends MediatorBase Application.start(Stage) - save stage instance to StageModel - create the ui - load the RootPane.fxml - add the main.css - add mediators to list - call create() on all mediators - add app listeners (close etc) - call preinitialize() on all mediators - IApplicationController.start() - set caustic storage - set application root usinf 'APP_DIRECTORY' resource - ICaustkApplication.initialize() - ICaustkController.initialize() - create application root dir - create ALL sub controllers - fire(OnApplicationInitialize) - IProjectManager.initialize() - load .settings file - ICaustkApplication.start() - ICaustkController.start() - fire(OnApplicationStart) - find lastProject in settings if note exists - IProjectManager.create() - IProjectManager.save() - fire(OnProjectManagerChange[LOAD]) else - IProjectManager.load(lastProj) - project.open() - fire(OnProjectManagerChange[LOAD]) - trigger(OnModelRegister) - trigger(OnMediatorRegister) */ /** * The {@link JavaFXApplication} is the base app for all apps that implement a * single Bitmap UI. */ public abstract class JavaFXApplication extends GuiceApplication { @Inject @Named("resources") ResourceBundle resourceBundle; @Inject protected GuiceFXMLLoader loader; // XXX This has to be put in the Andorid Application impl // and use controller.addComponent(IInjectorService.class); @Inject protected IInjectorService injectorService; @Inject protected IApplicationController applicationController; @Inject protected ICaustkApplicationProvider applicationProvider; @Inject protected IStageModel stageModel; @Inject protected IScreenManager screenManager; @Inject protected IPreferenceManager preferenceManager; @Inject protected IApplicationPreferences applicationPreferences; @Inject protected StageMediator stageMediator; // is there a proper place for this? private List<Class<? extends IScreenView>> screens = new ArrayList<>(); private Pane root; private Editor editor; Pane getRoot() { return root; } @Override public void init(List<Module> modules) throws Exception { } @Override public void start(Stage primaryStage) throws Exception { stageModel.setStage(primaryStage); // XXX special case, maybe a better place to put this applicationProvider.get().getController() .addComponent(IInjectorService.class, injectorService); CtkDebug.log("Create main app UI"); createRootPane(); addListeners(); setupWorkingDirectory(); CtkDebug.log("Create IScreenView instances"); initScreens(screens); for (Class<? extends IScreenView> type : screens) { screenManager.addScreen(type); } CtkDebug.log("Create ScreenManager"); screenManager.create(getRoot()); // registers screenManager which then will loop through all screens applicationController.registerMediatorObservers(); CtkDebug.log("Start application controller"); // set roots, call initialize(), start() on application, start app model // create or load last project applicationController.start(); applicationController.load(); applicationController.registerModels(); applicationController.registerMeditors(); applicationController.show(); CtkDebug.log("Show the application"); show(); } public void show() { double x = applicationPreferences.getFloat("x", -10f); double y = applicationPreferences.getFloat("y", -10f); double width = applicationPreferences.getFloat("width", -10f); double height = applicationPreferences.getFloat("height", -10f); Stage stage = stageModel.getStage(); x = (x < 0) ? 0 : x; y = (y < 0) ? 0 : y; width = (width == -10) ? stage.getWidth() : width; height = (height == -10) ? stage.getHeight() : height; stage.setX(x); stage.setY(y); stage.setWidth(width); stage.setHeight(height); editor = applicationPreferences.edit(); stage.xProperty().addListener(new ChangeListener<Number>() { @Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { editor.putFloat("x", newValue.floatValue()); } }); stage.yProperty().addListener(new ChangeListener<Number>() { @Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { editor.putFloat("y", newValue.floatValue()); } }); stage.widthProperty().addListener(new ChangeListener<Number>() { @Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { editor.putFloat("width", newValue.floatValue()); } }); stage.heightProperty().addListener(new ChangeListener<Number>() { @Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { editor.putFloat("height", newValue.floatValue()); } }); stage.show(); } private void setupWorkingDirectory() { String causticDirectory = preferenceManager.getString("causticRoot", null); if (causticDirectory == null) { DirectoryChooser chooser = FileUtil.createDefaultDirectoryChooser(null, "Choose Caustic application root"); File causticFile = chooser.showDialog(null); if (causticFile != null && causticFile.isDirectory()) { causticDirectory = causticFile.getPath(); preferenceManager.edit().putString("causticRoot", causticDirectory).commit(); } else { throw new RuntimeException("Caustic directory invalid."); } } File workingDirectory = new File(causticDirectory).getParentFile(); applicationProvider.get().getConfiguration().setCausticStorage(workingDirectory); File applicationRoot = new File(workingDirectory, resourceBundle.getString("APP_DIRECTORY")); applicationProvider.get().getConfiguration().setApplicationRoot(applicationRoot); } // screenManager.addScreen(MainScreenView.class); protected abstract void initScreens(List<Class<? extends IScreenView>> screens); protected abstract String getRootPane(); protected void createRootPane() throws IOException { final Stage stage = stageModel.getStage(); root = loader.load(getClass().getResource(getRootPane())).getRoot(); StageBuilder.create().title(resourceBundle.getString("APP_TITLE")).resizable(false) .scene(SceneBuilder.create().root(root).build()).applyTo(stage); stage.getScene().getStylesheets().add(getClass().getResource("/main.css").toExternalForm()); stage.setResizable(true); // this is adding 10 px on width & height } protected void addListeners() { stageModel.getStage().setOnCloseRequest(new EventHandler<WindowEvent>() { public void handle(WindowEvent we) { try { editor.commit(); applicationProvider.get().save(); } catch (IOException e) { e.printStackTrace(); } applicationProvider.get().close(); } }); } /* Sub class applications need the following public static void main(String[] args) { Application.launch(args); } */ }