package org.freeplane.plugin.workspace; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.io.Writer; import java.util.Enumeration; import java.util.Properties; import java.util.Vector; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.JTree; import org.freeplane.core.resources.IFreeplanePropertyListener; import org.freeplane.core.resources.ResourceController; import org.freeplane.core.util.LogUtils; import org.freeplane.features.map.IMapLifeCycleListener; import org.freeplane.features.map.MapModel; import org.freeplane.features.mode.Controller; import org.freeplane.features.mode.ModeController; import org.freeplane.features.mode.mindmapmode.MModeController; import org.freeplane.features.ui.ViewController; import org.freeplane.features.url.UrlManager; import org.freeplane.main.application.ApplicationResourceController; import org.freeplane.plugin.workspace.components.TreeView; import org.freeplane.plugin.workspace.components.WorkspaceSplitPaneUI; import org.freeplane.plugin.workspace.controller.AWorkspaceExpansionStateHandler; import org.freeplane.plugin.workspace.controller.DefaultNodeTypeIconManager; import org.freeplane.plugin.workspace.controller.DefaultWorkspaceComponentHandler; import org.freeplane.plugin.workspace.controller.DefaultWorkspaceExpansionStateHandler; import org.freeplane.plugin.workspace.controller.DefaultWorkspaceKeyHandler; import org.freeplane.plugin.workspace.controller.DefaultWorkspaceMouseHandler; import org.freeplane.plugin.workspace.controller.DefaultWorkspaceTreeModelListener; import org.freeplane.plugin.workspace.controller.INodeTypeIconManager; import org.freeplane.plugin.workspace.controller.IOController; import org.freeplane.plugin.workspace.dnd.WorkspaceTransferHandler; import org.freeplane.plugin.workspace.event.IWorkspaceEventListener; import org.freeplane.plugin.workspace.event.WorkspaceEvent; import org.freeplane.plugin.workspace.io.AFileNodeCreator; import org.freeplane.plugin.workspace.io.FileReadManager; import org.freeplane.plugin.workspace.io.FileSystemAlterationMonitor; import org.freeplane.plugin.workspace.io.FilesystemManager; import org.freeplane.plugin.workspace.model.AWorkspaceTreeNode; import org.freeplane.plugin.workspace.model.WorkspaceIndexedTreeModel; import org.freeplane.plugin.workspace.nodes.WorkspaceRoot; public class WorkspaceController implements IFreeplanePropertyListener, IMapLifeCycleListener, ActionListener { public static final String WORKSPACE_RESOURCE_URL_PROTOCOL = "workspace"; public static final String PROPERTY_RESOURCE_URL_PROTOCOL = "property"; public static final String WORKSPACE_VERSION = "1.0"; private static WorkspaceController workspaceController; private static WorkspaceConfiguration configuration ; private static final IOController workspaceIOController = new IOController(); private static final FileSystemAlterationMonitor monitor = new FileSystemAlterationMonitor(30000); private final FilesystemManager fsReader; private final Vector<IWorkspaceEventListener> workspaceListeners = new Vector<IWorkspaceEventListener>(); private TreeView view; private Container oldContentPane; private Container WSContentPane; private SingleContentPane contentPane; private WorkspacePreferences preferences; private FileReadManager fileTypeManager; private WorkspaceTransferHandler transferHandler; private WorkspaceIndexedTreeModel model = new WorkspaceIndexedTreeModel(); String workspaceLocation; private boolean isInitialized = false; private DefaultWorkspaceExpansionStateHandler expansionStateHandler; private INodeTypeIconManager nodeTypeIconManager; protected static final boolean firstApplicationStart; static { final File userPreferencesFile = ApplicationResourceController.getUserPreferencesFile(); firstApplicationStart = !userPreferencesFile.exists(); } /*********************************************************************************** * CONSTRUCTORS **********************************************************************************/ private WorkspaceController(ModeController modeController) { LogUtils.info("Initializing WorkspaceEnvironment"); registerToIMapLifeCycleListener(); preparePreferences(modeController); initTree(); registerTreeModelEventListener(); this.fsReader = new FilesystemManager(getFileTypeManager()); } /*********************************************************************************** * METHODS * @return **********************************************************************************/ protected static WorkspaceController createController(ModeController modeController) { if(workspaceController == null) { workspaceController = new WorkspaceController(modeController); configuration = new WorkspaceConfiguration(); } return workspaceController; } private void registerToIMapLifeCycleListener() { Controller.getCurrentModeController().getMapController().addMapLifeCycleListener(this); } private void registerTreeModelEventListener(){ getWorkspaceModel().addTreeModelListener(new DefaultWorkspaceTreeModelListener()); } public static boolean isFirstApplicationStart() { return firstApplicationStart; } public void initialStart() { //initializeConfiguration(); initializeView(); isInitialized = true; } public static WorkspaceController getController() { return workspaceController; } public static IOController getIOController() { return workspaceIOController; } public boolean isInitialized() { return isInitialized; } public WorkspaceConfiguration getConfiguration() { return configuration; } public FileSystemAlterationMonitor getFileSystemAlterationMonitor() { return monitor; } public INodeTypeIconManager getNodeTypeIconManager() { if(nodeTypeIconManager == null) { nodeTypeIconManager = new DefaultNodeTypeIconManager(); } return nodeTypeIconManager; } public JTree getWorkspaceViewTree() { return getWorkspaceView().getTreeView(); } public void showWorkspace(boolean visible) { ResourceController resCtrl = Controller.getCurrentController().getResourceController(); resCtrl.setProperty(WorkspacePreferences.SHOW_WORKSPACE_PROPERTY_KEY, visible); if (visible) { int width = resCtrl.getIntProperty(WorkspacePreferences.WORKSPACE_WIDTH_PROPERTY_KEY, 200); setWorkspaceWidth(width); getContentPane().revalidate(); } else { setWorkspaceWidth(-1); getContentPane().revalidate(); } } public FilesystemManager getFilesystemMgr() { return this.fsReader; } public void addToolBar(JComponent bar) { getWorkspaceView().add(bar, BorderLayout.PAGE_END); getWorkspaceView().repaint(); } public void removeToolBar(JComponent bar) { getWorkspaceView().remove(bar); } public void saveConfigurationAsXML(Writer writer) { getConfiguration().saveConfiguration(writer); } public WorkspaceTransferHandler getTransferHandler() { return transferHandler; } public void removeWorkspaceListener(IWorkspaceEventListener listener) { synchronized (workspaceListeners) { workspaceListeners.remove(listener); } } public void addWorkspaceListener(IWorkspaceEventListener listener) { synchronized (workspaceListeners) { this.workspaceListeners.add(listener); } } public void removeAllListeners() { synchronized (workspaceListeners) { this.workspaceListeners.removeAllElements(); } } private boolean loadInProcess = false; public void loadWorkspace() { if(loadInProcess) { return; } loadInProcess = true; WorkspaceController.getController().fireOpenWorkspace(new WorkspaceEvent(this)); if (getPreferences().getWorkspaceLocation() == null) { WorkspaceUtils.showWorkspaceChooserDialog(); } initTree(); initializeConfiguration(); reloadView(); showWorkspace(Controller.getCurrentController().getResourceController().getBooleanProperty(WorkspacePreferences.SHOW_WORKSPACE_PROPERTY_KEY)); getExpansionStateHandler().restoreExpansionStates(); fireWorkspaceReady(new WorkspaceEvent(getConfiguration())); loadInProcess = false; } public void refreshWorkspace() { Enumeration<AWorkspaceTreeNode> children = ((WorkspaceRoot) getWorkspaceModel().getRoot()).children(); while(children.hasMoreElements()) { children.nextElement().refresh(); } } public WorkspaceIndexedTreeModel getWorkspaceModel() { if(model == null) { model = new WorkspaceIndexedTreeModel(); } return model; } private void preparePreferences(ModeController modeController) { if (this.preferences == null) { this.preferences = new WorkspacePreferences(modeController); ResourceController resCtrl = Controller.getCurrentController().getResourceController(); resCtrl.addPropertyChangeListener(this); } } public WorkspacePreferences getPreferences() { return this.preferences; } public AWorkspaceExpansionStateHandler getExpansionStateHandler() { if (expansionStateHandler == null) { expansionStateHandler = new DefaultWorkspaceExpansionStateHandler(); } return expansionStateHandler; } private void initTree() { getWorkspaceModel().resetIndex(); getWorkspaceModel().setRoot(new WorkspaceRoot()); } private void initializeConfiguration() { ResourceController resCtrl = Controller.getCurrentController().getResourceController(); String workspaceLocation = getPreferences().getWorkspaceLocation(); if (workspaceLocation == null || workspaceLocation.trim().length() <= 0) { resCtrl.setProperty(WorkspacePreferences.SHOW_WORKSPACE_PROPERTY_KEY, false); showWorkspace(false); return; } resetWorkspaceView(); fireConfigurationBeforeLoading(new WorkspaceEvent(getConfiguration())); if (getConfiguration().load()) { fireConfigurationLoaded(new WorkspaceEvent(getConfiguration())); showWorkspace(getPreferences().isWorkspaceVisible()); UrlManager.getController().setLastCurrentDir(new File(getPreferences().getWorkspaceLocation())); fireWorkspaceChanged(new WorkspaceEvent(getConfiguration())); } else { showWorkspace(Controller.getCurrentController().getResourceController() .getBooleanProperty(WorkspacePreferences.SHOW_WORKSPACE_PROPERTY_KEY)); getPreferences().setNewWorkspaceLocation(null); } } private TreeView getWorkspaceView() { if (this.view == null) { this.view = new TreeView(); this.view.getTreeView().setModel(getWorkspaceModel()); this.view.addComponentListener(new DefaultWorkspaceComponentHandler(this.view)); DefaultWorkspaceMouseHandler mouseHandler = new DefaultWorkspaceMouseHandler(); this.view.getTreeView().addMouseListener(mouseHandler); this.view.getTreeView().addMouseMotionListener(mouseHandler); this.view.getTreeView().addKeyListener(new DefaultWorkspaceKeyHandler()); this.view.getTreeView().setRowHeight(18); this.view.getTreeView().addTreeExpansionListener((DefaultWorkspaceExpansionStateHandler) getExpansionStateHandler()); this.transferHandler = WorkspaceTransferHandler.configureDragAndDrop(this.view.getTreeView()); } return this.view; } private Container getOldContentPane() { if (this.oldContentPane == null) { MModeController modeController = (MModeController) Controller.getCurrentModeController(); this.oldContentPane = new JPanel(new BorderLayout()); for (Component comp : modeController.getController().getViewController().getJFrame().getContentPane().getComponents()) { this.oldContentPane.add(comp); } } return this.oldContentPane; } private Container getWSContentPane() { if (this.WSContentPane == null) { this.WSContentPane = new JPanel(new BorderLayout()); this.WSContentPane.setMinimumSize(new Dimension(0, 0)); final JSplitPane splitPane = new JSplitPane(); splitPane.setDividerSize(7); splitPane.setUI(new WorkspaceSplitPaneUI()); splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT); splitPane.setAutoscrolls(true); splitPane.setLeftComponent(getWorkspaceView()); splitPane.setRightComponent(getOldContentPane()); this.WSContentPane.add(splitPane); } return this.WSContentPane; } private void setWorkspaceWidth(int width) { JSplitPane splitPane = (JSplitPane) (getWSContentPane().getComponent(0)); if(width != -1) { getWorkspaceView().setVisible(true); getWorkspaceView().setSize(width, 0); splitPane.setDividerLocation(width); splitPane.setDividerSize(7); splitPane.setEnabled(true); } else { getWorkspaceView().setVisible(false); splitPane.setEnabled(false); splitPane.setDividerSize(0); } } private void resetWorkspaceView() { this.view = null; this.WSContentPane = null; } private void initializeView() { getOldContentPane(); ViewController viewController = (ViewController) Controller.getCurrentController().getViewController(); viewController.getJFrame().setContentPane(new JPanel(new BorderLayout())); viewController.getJFrame().getContentPane().add(getContentPane()); reloadView(); } private void reloadView() { getContentPane().setComponent(getWSContentPane()); } private SingleContentPane getContentPane() { if (this.contentPane == null) { this.contentPane = new SingleContentPane(); this.contentPane.setLayout(new BorderLayout()); } return this.contentPane; } private FileReadManager getFileTypeManager() { if (this.fileTypeManager == null) { this.fileTypeManager = new FileReadManager(); Properties props = new Properties(); try { props.load(this.getClass().getResourceAsStream("/conf/filenodetypes.properties")); Class<?>[] args = {}; for (Object key : props.keySet()) { try { Class<?> clazz = org.freeplane.plugin.workspace.creator.DefaultFileNodeCreator.class; clazz = this.getClass().getClassLoader().loadClass(key.toString()); AFileNodeCreator handler = (AFileNodeCreator) clazz.getConstructor(args).newInstance(); handler.setFileTypeList(props.getProperty(key.toString(), ""), "\\|"); this.fileTypeManager.addFileHandler(handler); } catch (ClassNotFoundException e) { LogUtils.warn("Class not found [" + key + "]", e); } catch (ClassCastException e) { LogUtils.warn("Class [" + key + "] is not of type: PhysicalNode", e); } catch (Exception e) { e.printStackTrace(); } } } catch (IOException e) { e.printStackTrace(); } } return this.fileTypeManager; } // protected void dispatchWorkspaceEvent(WorkspaceEvent event) { // for (IWorkspaceEventListener listener : workspaceListener) { // //listener.processEvent(event); // } // } protected void fireOpenWorkspace(WorkspaceEvent event) { synchronized (workspaceListeners) { for (IWorkspaceEventListener listener : workspaceListeners) { listener.openWorkspace(event); //listener.processEvent(event); } } } protected void fireCloseWorkspace(WorkspaceEvent event) { synchronized (workspaceListeners) { for (IWorkspaceEventListener listener : workspaceListeners) { listener.closeWorkspace(event); } } } protected void fireWorkspaceChanged(WorkspaceEvent event) { synchronized (workspaceListeners) { for (IWorkspaceEventListener listener : workspaceListeners) { listener.workspaceChanged(event); //listener.processEvent(event); } } } protected void fireWorkspaceReady(WorkspaceEvent event) { synchronized (workspaceListeners) { for (IWorkspaceEventListener listener : workspaceListeners) { listener.workspaceReady(event); } } } protected void fireConfigurationLoaded(WorkspaceEvent event) { synchronized (workspaceListeners) { for (IWorkspaceEventListener listener : workspaceListeners) { listener.configurationLoaded(event); } } } protected void fireConfigurationBeforeLoading(WorkspaceEvent event) { synchronized (workspaceListeners) { for (IWorkspaceEventListener listener : workspaceListeners) { listener.configurationBeforeLoading(event); } } } protected void fireToolBarChanged(WorkspaceEvent event) { synchronized (workspaceListeners) { for (IWorkspaceEventListener listener : workspaceListeners) { listener.toolBarChanged(event); } } } /*********************************************************************************** * REQUIRED METHODS FOR INTERFACES **********************************************************************************/ public void propertyChanged(String propertyName, String newValue, String oldValue) { // if (propertyName.equals(WorkspacePreferences.WORKSPACE_LOCATION_NEW)) // { // if (newValue != null && newValue.trim().length() > 0) { // Controller.getCurrentController().getResourceController() // .setProperty(WorkspacePreferences.SHOW_WORKSPACE_PROPERTY_KEY, true); // reloadWorkspace(); // } // } } public void actionPerformed(ActionEvent e) { } /*********************************************************************************** * INTERNAL CLASSES **********************************************************************************/ private class SingleContentPane extends JPanel { private static final long serialVersionUID = 1L; public void setComponent(Component comp) { this.removeAll(); this.add(comp); } } public void onCreate(MapModel map) { } public void onRemove(MapModel map) { } public void onSavedAs(MapModel map) { refreshWorkspace(); } public void onSaved(MapModel map) { } }