/*
* Freeplane - mind map editor
* Copyright (C) 2008 Joerg Mueller, Daniel Polansky, Christian Foltin, Dimitry Polivaev
*
* This file is created by Dimitry Polivaev in 2008.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.freeplane.features.mode;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.freeplane.core.extension.ExtensionContainer;
import org.freeplane.core.extension.IExtension;
import org.freeplane.core.resources.OptionPanelController;
import org.freeplane.core.resources.ResourceController;
import org.freeplane.core.resources.components.IValidator;
import org.freeplane.core.util.Compat;
import org.freeplane.core.util.LogUtils;
import org.freeplane.features.map.IMapSelection;
import org.freeplane.features.map.MapModel;
import org.freeplane.features.ui.IMapViewManager;
import org.freeplane.features.ui.ViewController;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinBase;
import com.sun.jna.platform.win32.WinDef;
/**
* Provides the methods to edit/change a Node. Forwards all messages to
* MapModel(editing) or MapView(navigation).
*/
public class Controller extends AController {
private final ExtensionContainer extensionContainer;
/**
* Converts from a local link to the real file URL of the documentation map.
* (Used to change this behavior under MacOSX).
*/
private ModeController modeController;
private ModeController modeController4build;
final private Map<String, ModeController> modeControllers = new LinkedHashMap<String, ModeController>();
private ViewController viewController;
private final ResourceController resourceController;
private final List<IValidator> optionValidators = new ArrayList<IValidator>();
final private OptionPanelController optionPanelController;
public Controller(ResourceController resourceController) {
super();
if(currentController == null){
currentController = this;
}
this.resourceController = resourceController;
this.optionPanelController = new OptionPanelController();
extensionContainer = new ExtensionContainer(new HashMap<Class<? extends IExtension>, IExtension>());
addAction(new MoveToRootAction());
addAction(new CenterSelectedNodeAction());
}
public void addExtension(final Class<? extends IExtension> clazz, final IExtension extension) {
extensionContainer.addExtension(clazz, extension);
}
public void addModeController(final ModeController modeController) {
modeControllers.put(modeController.getModeName(), modeController);
}
/**
* Closes the actual map.
*
* @param withoutSave
* true= without save.
*/
public void close(final boolean withoutSave) {
getMapViewManager().close(withoutSave);
}
public IExtension getExtension(final Class<? extends IExtension> clazz) {
return extensionContainer.getExtension(clazz);
}
/**
* @return
*/
public MapModel getMap() {
return getViewController().getMap();
}
public IMapViewManager getMapViewManager() {
return getViewController().getMapViewManager();
}
/** @return the current modeController. */
public ModeController getModeController() {
return modeController4build != null ? modeController4build : modeController;
}
public ModeController getModeController(final String modeName) {
return modeControllers.get(modeName);
}
public Set<String> getModes() {
return modeControllers.keySet();
}
public IMapSelection getSelection() {
return getViewController().getSelection();
}
/**
* @return
*/
public ViewController getViewController() {
return viewController;
}
public void quit() {
if (shutdown()) {
System.exit(0);
}
}
/**
* @param actionEvent
*/
public void quit(final ActionEvent actionEvent) {
getActions().get("QuitAction").actionPerformed(actionEvent);
}
public void selectMode(ModeController newModeController) {
modeController4build = null;
final ModeController oldModeController = modeController;
if (oldModeController == newModeController) {
return;
}
if (oldModeController != null) {
oldModeController.shutdown();
}
LogUtils.info("requesting mode: " + newModeController.getModeName());
modeController = newModeController;
viewController.selectMode(oldModeController, newModeController);
getMapViewManager().changeToMode(newModeController.getModeName());
newModeController.startup();
}
public void selectMode(final String modeName) {
final ModeController newModeController = modeControllers.get(modeName);
if (newModeController == null) {
return;
}
if (modeController == newModeController) {
return;
}
selectMode(newModeController);
}
public void setViewController(final ViewController viewController) {
this.viewController = viewController;
}
public boolean shutdown() {
getViewController().saveProperties();
ResourceController.getResourceController().saveProperties();
if (!getViewController().quit()) {
return false;
}
extensionContainer.getExtensions().clear();
return true;
}
public static void exec(final String command) throws IOException {
exec(command, false);
}
public static void exec(final String command, boolean waitFor) throws IOException {
if (Compat.isWindowsOS()) {
LogUtils.info("using jna to execute " + command);
windowsNativeExec(command, waitFor);
}
else {
LogUtils.info("execute " + command);
Runtime.getRuntime().exec(command);
}
}
public static void exec(final String[] command) throws IOException {
exec(command, false);
}
public static void exec(final String[] command, boolean waitFor) throws IOException {
if (Compat.isWindowsOS()) {
String commandString = command[0];
for (int i=1; i<command.length; i++) {
commandString += " " + command[i];
}
LogUtils.info("using jna to execute: " + commandString);
try {
windowsNativeExec(commandString, waitFor);
} catch (Exception e) {
throw new IOException(e.getMessage()+" for command: "+commandString);
}
}
else {
LogUtils.info("execute: " + Arrays.toString(command));
Runtime.getRuntime().exec(command);
}
}
private static void windowsNativeExec(String command, boolean waitFor) throws IllegalStateException {
WinBase.PROCESS_INFORMATION.ByReference processInfo = new WinBase.PROCESS_INFORMATION.ByReference();
WinBase.STARTUPINFO startupInfo = new WinBase.STARTUPINFO();
try {
if (!Kernel32.INSTANCE.CreateProcess(
null, // Application name, not needed if supplied in command line
command, // Command line
null, // Process security attributes
null, // Thread security attributes
true, // Inherit handles
new WinDef.DWORD(0) , // Creation flags
null, // Environment
null, // Directory
startupInfo,
processInfo)) {
throw new IllegalStateException("Error creating process. Last error: " +
Kernel32.INSTANCE.GetLastError());
}
if (waitFor) {
Kernel32.INSTANCE.WaitForSingleObject(processInfo.hProcess, Kernel32.INFINITE);
}
}
finally {
// The CreateProcess documentation indicates that it is very important to
// close the returned handles
Kernel32.INSTANCE.CloseHandle(processInfo.hThread);
Kernel32.INSTANCE.CloseHandle(processInfo.hProcess);
}
}
private static ThreadLocal<Controller> threadController = new ThreadLocal<Controller>();
private static Controller currentController = null;
public static Controller getCurrentController() {
final Controller controller = threadController.get();
return controller != null ? controller : currentController;
}
public static void setCurrentController(final Controller controller){
currentController = controller;
}
public static ModeController getCurrentModeController() {
return getCurrentController().getModeController();
}
public void selectModeForBuild(ModeController modeController4build) {
this.modeController4build = modeController4build;
}
public ResourceController getResourceController() {
return resourceController;
}
public void addOptionValidator(IValidator validator) {
optionValidators.add(validator);
}
public List<IValidator> getOptionValidators() {
return optionValidators;
}
public OptionPanelController getOptionPanelController() {
return optionPanelController;
}
}