package org.docear.plugin.core.mindmap; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.swing.SwingUtilities; import org.docear.plugin.core.DocearController; import org.docear.plugin.core.MapItem; import org.docear.plugin.core.features.DocearMapModelExtension; import org.docear.plugin.core.features.MapModificationSession; import org.docear.plugin.core.ui.SwingWorkerDialog; import org.freeplane.core.util.LogUtils; import org.freeplane.core.util.TextUtils; import org.freeplane.features.map.INodeView; import org.freeplane.features.map.MapChangeEvent; import org.freeplane.features.map.MapModel; import org.freeplane.features.mode.Controller; import org.freeplane.features.url.UrlManager; import org.freeplane.features.url.mindmapmode.MFileManager; import org.freeplane.plugin.workspace.WorkspaceUtils; import org.freeplane.view.swing.map.MapView; import org.freeplane.view.swing.map.NodeView; import org.jdesktop.swingworker.SwingWorker; public class MindmapUpdateController { private final MapModificationSession session = new MapModificationSession(); private final ArrayList<AMindmapUpdater> updaters = new ArrayList<AMindmapUpdater>(); private boolean showDialog = true; public MindmapUpdateController(){} public MindmapUpdateController(boolean showDialog){ this.showDialog = showDialog; } public void addMindmapUpdater(AMindmapUpdater updater) { this.updaters.add(updater); } public List<AMindmapUpdater> getMindmapUpdaters() { return this.updaters; } public boolean updateAllMindmapsInWorkspace() { List<MapItem> maps = new ArrayList<MapItem>(); for (URI uri : WorkspaceUtils.getModel().getAllNodesFiltered(".mm")) { maps.add(new MapItem(uri)); } return updateMindmaps(maps); } public boolean updateRegisteredMindmapsInWorkspace() { return updateRegisteredMindmapsInWorkspace(false); } public boolean updateRegisteredMindmapsInWorkspace(boolean openMindmapsToo) { List<MapItem> maps = new ArrayList<MapItem>(); for (URI uri : DocearController.getController().getLibrary().getMindmaps()) { maps.add(new MapItem(uri)); } if (openMindmapsToo) { for (MapItem item : getAllOpenMaps()) { maps.add(item); } } return updateMindmaps(maps); } public boolean updateOpenMindmaps() { List<MapItem> maps = getAllOpenMaps(); return updateMindmaps(maps); } private List<MapItem> getAllOpenMaps() { List<MapItem> maps = new ArrayList<MapItem>(); Map<String, MapModel> openMaps = Controller.getCurrentController().getMapViewManager().getMaps(); for (String name : openMaps.keySet()) { maps.add(new MapItem(openMaps.get(name))); } return maps; } public boolean updateCurrentMindmap() { return updateCurrentMindmap(false); } public boolean updateCurrentMindmap(boolean closeWhenDone) { List<MapItem> maps = new ArrayList<MapItem>(); try { maps.add(new MapItem(Controller.getCurrentController().getMap())); } catch (NullPointerException e) { } Controller.getCurrentController().getMap().setSaved(false); return updateMindmaps(maps, closeWhenDone); } public boolean updateMindmapsInList(List<MapModel> maps) { List<MapItem> mapItems = new ArrayList<MapItem>(); for (MapModel map : maps) { try { mapItems.add(new MapItem(map)); } catch (NullPointerException e) { } } return updateMindmaps(mapItems); } public boolean updateMindmaps(List<MapItem> uris) { return updateMindmaps(uris, false); } public boolean updateMindmaps(List<MapItem> maps, boolean closeWhenDone) { final SwingWorker<Void, Void> thread = getUpdateThread(maps, closeWhenDone); if(showDialog){ SwingWorkerDialog workerDialog = new SwingWorkerDialog(Controller.getCurrentController().getViewController().getJFrame()); workerDialog.setHeadlineText(TextUtils.getText("updating_mindmaps_headline")); workerDialog.setSubHeadlineText(TextUtils.getText("updating_mindmaps_subheadline")); workerDialog.showDialog(thread); workerDialog = null; } else{ final ExecutorService executor = Executors.newSingleThreadExecutor(); thread.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if(evt.getPropertyName().equals(SwingWorkerDialog.IS_CANCELED) || evt.getPropertyName().equals(SwingWorkerDialog.IS_DONE)){ if(thread != null){ thread.cancel(true); } if(executor != null){ executor.shutdownNow(); } } } }); executor.execute(thread); } return !thread.isCancelled(); } public SwingWorker<Void, Void> getUpdateThread(final List<MapItem> maps) { return getUpdateThread(maps, false); } public SwingWorker<Void, Void> getUpdateThread(final List<MapItem> maps, final boolean closeWhenDone) { return new SwingWorker<Void, Void>() { private int totalCount; private boolean mapHasChanged = false; private final long start = System.currentTimeMillis(); @Override protected Void doInBackground() throws Exception { try { if (maps == null || maps.size() == 0) { return null; } NodeView.setModifyModelWithoutRepaint(true); MapView.setNoRepaint(true); fireStatusUpdate(SwingWorkerDialog.SET_PROGRESS_BAR_INDETERMINATE, null, null); fireStatusUpdate(SwingWorkerDialog.PROGRESS_BAR_TEXT, null, TextUtils.getText("computing_node_count")); totalCount = maps.size()*getMindmapUpdaters().size(); if (canceled()) return null; fireStatusUpdate(SwingWorkerDialog.SET_PROGRESS_BAR_DETERMINATE, null, null); int count = 0; fireProgressUpdate(100 * count / totalCount); for (AMindmapUpdater updater : getMindmapUpdaters()) { count++; fireStatusUpdate(SwingWorkerDialog.PROGRESS_BAR_TEXT, null, updater.getTitle()); if (canceled()) return null; for (MapItem mapItem : maps) { mapHasChanged = false; MapModel map = null; try { map = mapItem.getModel(); if (map==null || map.isReadOnly()) { continue; } map.getExtension(DocearMapModelExtension.class).setMapModificationSession(session); } catch (Exception ex) { LogUtils.warn("MindmapUpdateController$SwingWorker.doInBackground().1 "+ex.getMessage()+" ("+mapItem.getIdentifierForDialog()+")"); } fireStatusUpdate(SwingWorkerDialog.DETAILS_LOG_TEXT, null, updater.getTitle()+": " + mapItem.getIdentifierForDialog()); fireStatusUpdate(SwingWorkerDialog.SET_SUB_HEADLINE, null, TextUtils.getText("updating_against_p1") + getMapTitle(map) + TextUtils.getText("updating_against_p2")); this.mapHasChanged = updater.updateMindmap(map); fireProgressUpdate(100 * count / totalCount); if (this.mapHasChanged) { if (!mapItem.isMapOpen()) { saveMap(map); MapChangeEvent event = new MapChangeEvent(this, UrlManager.MAP_URL, map.getURL(), null); Controller.getCurrentModeController().getMapController().fireMapChanged(event); map.destroy(); } else { map.setSaved(false); map.setReadOnly(false); } } } } fireStatusUpdate(SwingWorkerDialog.SET_SUB_HEADLINE, null, TextUtils.getText("updating_mapviews")); fireStatusUpdate(SwingWorkerDialog.PROGRESS_BAR_TEXT, null, TextUtils.getText("updating_mapviews")); } catch (InterruptedException e) { LogUtils.info("MindmapUpdateController aborted."); } catch (Exception e) { LogUtils.warn(e); } return null; } private String getMapTitle(MapModel map) { String mapTitle = ""; if (map.getFile() != null) { mapTitle = map.getFile().getName(); } else { mapTitle = map.getTitle(); } return mapTitle; } protected void done() { NodeView.setModifyModelWithoutRepaint(false); MapView.setNoRepaint(false); for (MapItem item : maps) { if (item.isMapOpen()) { LogUtils.info("updating view for map: " + item.getIdentifierForDialog()); long l = System.currentTimeMillis(); for(INodeView nodeView : item.getModel().getRootNode().getViewers()) { if(nodeView instanceof NodeView) { ((NodeView) nodeView).updateAll(); } } LogUtils.info("resetting folding complete: "+(System.currentTimeMillis()-l)); } } if (this.isCancelled() || Thread.currentThread().isInterrupted()) { this.firePropertyChange(SwingWorkerDialog.IS_DONE, null, TextUtils.getText("update_canceled")); } else { this.firePropertyChange(SwingWorkerDialog.SET_PROGRESS_BAR_DETERMINATE, null, null); this.firePropertyChange(SwingWorkerDialog.IS_DONE, null, TextUtils.getText("update_complete")); } if (closeWhenDone) { try { this.firePropertyChange(SwingWorkerDialog.CLOSE, null, null); } catch (Exception e) { e.printStackTrace(); } } else { long time = System.currentTimeMillis() - this.start; this.firePropertyChange(SwingWorkerDialog.DETAILS_LOG_TEXT, null, TextUtils.getText("execution_time") + " " + time + " ms"); } } private boolean canceled() throws InterruptedException { Thread.sleep(1L); return (this.isCancelled() || Thread.currentThread().isInterrupted()); } private void fireStatusUpdate(final String propertyName, final Object oldValue, final Object newValue) throws InterruptedException, InvocationTargetException { SwingUtilities.invokeAndWait(new Runnable() { public void run() { firePropertyChange(propertyName, oldValue, newValue); } }); } private void fireProgressUpdate(final int progress) throws InterruptedException, InvocationTargetException { SwingUtilities.invokeAndWait(new Runnable() { public void run() { setProgress(progress); } }); } private void saveMap(MapModel map) throws InterruptedException, InvocationTargetException { if (!this.mapHasChanged) { return; } fireStatusUpdate(SwingWorkerDialog.DETAILS_LOG_TEXT, null, TextUtils.getText("update_references_save_map") + map.getURL().getPath()); map.setSaved(false); ((MFileManager) UrlManager.getController()).save(map, false); } }; } }