/* ****************************************************************************** * Copyright (c) 2006-2012 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ package org.xmind.ui.internal; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.osgi.framework.Bundle; import org.xmind.core.Core; import org.xmind.core.IManifest; import org.xmind.core.IWorkbook; import org.xmind.core.IWorkbookBuilder; import org.xmind.core.event.ICoreEventListener; import org.xmind.core.event.ICoreEventRegistration; import org.xmind.core.event.ICoreEventSource; import org.xmind.core.event.ICoreEventSupport; import org.xmind.core.internal.MarkerGroup; import org.xmind.core.internal.dom.StyleSheetImpl; import org.xmind.core.internal.event.CoreEventSupport; import org.xmind.core.internal.zip.ArchiveConstants; import org.xmind.core.marker.AbstractMarkerResource; import org.xmind.core.marker.IMarker; import org.xmind.core.marker.IMarkerGroup; import org.xmind.core.marker.IMarkerResource; import org.xmind.core.marker.IMarkerResourceProvider; import org.xmind.core.marker.IMarkerSheet; import org.xmind.core.style.IStyle; import org.xmind.core.style.IStyleSheet; import org.xmind.core.util.FileUtils; import org.xmind.ui.mindmap.IResourceManager; import org.xmind.ui.mindmap.MindMapUI; import org.xmind.ui.prefs.PrefConstants; import org.xmind.ui.util.Logger; import org.xmind.ui.util.ResourceFinder; public class MindMapResourceManager implements IResourceManager { private static final String PATH_MARKERS = "markers/"; //$NON-NLS-1$ private static final String PATH_USER_MARKERS = "markers/"; //$NON-NLS-1$ private static final String PATH_STYLES = "styles/"; //$NON-NLS-1$ private static final String USER_STYLES_TEMP_LOCATION = PATH_STYLES + "userStyles"; //$NON-NLS-1$ private static final String USER_THEME_TEMP_LOCATION = PATH_STYLES + "userThemes"; //$NON-NLS-1$ private static final String MARKER_SHEET_XML = "markerSheet.xml"; //$NON-NLS-1$ private static final String MARKER_SHEET = "markerSheet"; //$NON-NLS-1$ private static final String DEFAULT_STYLES_XML = "defaultStyles.xml"; //$NON-NLS-1$ private static final String STYLES_XML = "styles.xml"; //$NON-NLS-1$ private static final String THEMES_XML = "themes.xml"; //$NON-NLS-1$ private static final String STYLES = "styles"; //$NON-NLS-1$ private static final String THEMES = "themes"; //$NON-NLS-1$ private static final String EXT_PROPERTIES = ".properties"; //$NON-NLS-1$ private static class SystemMarkerResourceProvider implements IMarkerResourceProvider { public IMarkerResource getMarkerResource(IMarker marker) { return new SystemMarkerResource(marker); } public boolean isPermanent() { return true; } } private static class SystemMarkerResource extends AbstractMarkerResource { public SystemMarkerResource(IMarker marker) { super(marker, PATH_MARKERS); } public InputStream getInputStream() { URL url = getURL(); if (url == null) return null; try { return url.openStream(); } catch (IOException e) { } return null; } public OutputStream getOutputStream() { return null; } private URL getURL() { return find(getFullPath()); } @Override public boolean equals(Object obj) { if (obj == this) return true; if (obj == null || !(obj instanceof SystemMarkerResource)) return false; return super.equals(obj); } } private static class UserMarkerResourceProvider implements IMarkerResourceProvider { public IMarkerResource getMarkerResource(IMarker marker) { return new UserMarkerResource(marker); } public boolean isPermanent() { return false; } } private static class UserMarkerResource extends AbstractMarkerResource { public UserMarkerResource(IMarker marker) { super(marker, PATH_USER_MARKERS); } private File getFile() { String path = Core.getWorkspace().getAbsolutePath(getFullPath()); if (path == null) return null; return new File(path); } public InputStream getInputStream() { File file = getFile(); if (file != null) try { return new FileInputStream(file); } catch (FileNotFoundException e) { } return null; } public OutputStream getOutputStream() { File file = FileUtils.ensureFileParent(getFile()); if (file != null) try { return new FileOutputStream(file); } catch (FileNotFoundException e) { } return null; } @Override public boolean equals(Object obj) { if (obj == this) return true; if (obj == null || !(obj instanceof UserMarkerResource)) return false; return super.equals(obj); } } protected static class RecentMarkerGroup extends MarkerGroup implements ICoreEventSource { public static final RecentMarkerGroup instance = new RecentMarkerGroup(); private static final int CAPACITY = 6; private List<IMarker> markers = new ArrayList<IMarker>(CAPACITY); private ICoreEventSupport eventSupport = new CoreEventSupport(); private RecentMarkerGroup() { } public void addMarker(IMarker marker) { if (markers.contains(marker)) return; while (markers.size() >= CAPACITY) { markers.remove(markers.size() - 1); } markers.add(0, marker); eventSupport.dispatchTargetChange(this, Core.MarkerAdd, marker); } public List<IMarker> getMarkers() { return markers; } public String getName() { return MindMapMessages.RecentUsed; } public void setSingleton(boolean singleton) { } public IMarkerSheet getOwnedSheet() { return null; } public IMarkerSheet getParent() { return null; } public boolean isSingleton() { return false; } public void removeMarker(IMarker marker) { } public void setName(String name) { } public String getId() { return "org.xmind.ui.RecentMarkerGroup"; //$NON-NLS-1$ } public Object getRegisterKey() { return getId(); } public ICoreEventRegistration registerCoreEventListener(String type, ICoreEventListener listener) { return eventSupport.registerCoreEventListener(this, type, listener); } public int hashCode() { return super.hashCode(); } public ICoreEventSupport getCoreEventSupport() { return eventSupport; } } private IMarkerSheet systemMarkerSheet = null; private IMarkerSheet userMarkerSheet = null; private IMarkerGroup recentMarkerGroup = null; private IStyleSheet defaultStyleSheet = null; private IStyleSheet systemStyleSheet = null; private IWorkbook userStylesContainer = null; private IStyle blankTheme = null; private IStyle defaultTheme = null; private IStyleSheet systemThemeSheet = null; private IWorkbook userThemesContainer = null; /* * (non-Javadoc) * * @see org.xmind.ui.internal.IMarkerSheetManager#getSystemMarkerSheet() */ public IMarkerSheet getSystemMarkerSheet() { if (systemMarkerSheet == null) { systemMarkerSheet = createSystemMarkerShet(); } return systemMarkerSheet; } private IMarkerSheet createSystemMarkerShet() { URL url = find(PATH_MARKERS, MARKER_SHEET_XML); if (url != null) { try { IMarkerSheet sheet = Core.getMarkerSheetBuilder().loadFromURL( url, new SystemMarkerResourceProvider()); URL propUrl = find(PATH_MARKERS, MARKER_SHEET, EXT_PROPERTIES); if (propUrl != null) { try { InputStream propStream = propUrl.openStream(); if (propStream != null) { try { Core.getMarkerSheetBuilder().loadProperties( propStream, sheet); } finally { try { propStream.close(); } catch (IOException e) { } } } } catch (Exception e) { Logger.log(e, "Failed to load system marker properties: " //$NON-NLS-1$ + propUrl); } } return sheet; } catch (Exception e) { Logger.log(e, "Failed to load system marker from: " + url); //$NON-NLS-1$ } } return Core.getMarkerSheetBuilder().createMarkerSheet( new SystemMarkerResourceProvider()); } /* * (non-Javadoc) * * @see org.xmind.ui.internal.IMarkerSheetManager#getUserMarkerSheet() */ public IMarkerSheet getUserMarkerSheet() { if (userMarkerSheet == null) { userMarkerSheet = createUserMarkerSheet(); initUserMarkerSheet(userMarkerSheet); } return userMarkerSheet; } public void saveUserMarkerSheet() { if (userMarkerSheet != null) { String path = Core.getWorkspace().getAbsolutePath( PATH_USER_MARKERS + MARKER_SHEET_XML); File file = FileUtils.ensureFileParent(new File(path)); try { userMarkerSheet.save(new FileOutputStream(file)); } catch (Exception e) { Logger.log(e); } } } private void initUserMarkerSheet(IMarkerSheet sheet) { sheet.setParentSheet(getSystemMarkerSheet()); } private IMarkerSheet createUserMarkerSheet() { String path = Core.getWorkspace().getAbsolutePath( PATH_USER_MARKERS + MARKER_SHEET_XML); if (path != null) { File file = new File(path); if (file.exists()) { try { return Core.getMarkerSheetBuilder().loadFromFile(file, new UserMarkerResourceProvider()); } catch (Exception e) { Logger.log(e, "Failed to load user marker from: " + file); //$NON-NLS-1$ } } } return Core.getMarkerSheetBuilder().createMarkerSheet( new UserMarkerResourceProvider()); } public IMarkerGroup getRecentMarkerGroup() { if (recentMarkerGroup == null) { recentMarkerGroup = new RecentMarkerGroup(); } return recentMarkerGroup; } public IStyleSheet getDefaultStyleSheet() { if (defaultStyleSheet == null) { defaultStyleSheet = createDefaultStyleSheet(); } return defaultStyleSheet; } private IStyleSheet createDefaultStyleSheet() { URL url = find(PATH_STYLES, DEFAULT_STYLES_XML); if (url != null) { try { return Core.getStyleSheetBuilder().loadFromUrl(url); } catch (Exception e) { Logger.log(e, "Failed to load default styles: " + url); //$NON-NLS-1$ } } return Core.getStyleSheetBuilder().createStyleSheet(); } public IStyleSheet getSystemStyleSheet() { if (systemStyleSheet == null) { systemStyleSheet = createSystemStyleSheet(); } return systemStyleSheet; } private IStyleSheet createSystemStyleSheet() { URL url = find(PATH_STYLES, STYLES_XML); if (url != null) { try { IStyleSheet sheet = Core.getStyleSheetBuilder() .loadFromUrl(url); URL propUrl = find(PATH_STYLES, STYLES, EXT_PROPERTIES); if (propUrl != null) { try { InputStream propStream = propUrl.openStream(); if (propStream != null) { try { Core.getStyleSheetBuilder().loadProperties( propStream, sheet); } finally { try { propStream.close(); } catch (IOException e) { } } } } catch (Exception e) { Logger.log(e, "Failed to load saved style properties: " //$NON-NLS-1$ + propUrl); } } return sheet; } catch (Exception e) { Logger.log(e, "Falied to load saved styles: " + url); //$NON-NLS-1$ } } return Core.getStyleSheetBuilder().createStyleSheet(); } public IStyleSheet getUserStyleSheet() { if (userStylesContainer == null) { userStylesContainer = createUserStylesContainer(); } return userStylesContainer.getStyleSheet(); } private IWorkbook createUserStylesContainer() { IWorkbook stylesContainer = null; String path = Core.getWorkspace().getAbsolutePath( USER_STYLES_TEMP_LOCATION); File file = new File(path); if (file.exists() && file.isDirectory() && new File(file, ArchiveConstants.CONTENT_XML).exists()) { try { stylesContainer = Core.getWorkbookBuilder() .loadFromTempLocation(path); } catch (Exception e) { Logger.log(e, "Failed to load user styles from: " + file); //$NON-NLS-1$ } } if (stylesContainer == null) { FileUtils.ensureDirectory(file); stylesContainer = Core.getWorkbookBuilder().createWorkbook(); } stylesContainer.setTempLocation(path); return stylesContainer; } public void saveUserStyleSheet() { if (userStylesContainer != null) { try { userStylesContainer.saveTemp(); } catch (Exception e) { Logger.log(e); } } } public IStyle getBlankTheme() { if (blankTheme == null) { blankTheme = Core.getStyleSheetBuilder().createStyleSheet() .createStyle(IStyle.THEME); blankTheme.setName(MindMapMessages.DefaultTheme_title); } return blankTheme; } public IStyle getDefaultTheme() { if (defaultTheme == null) { defaultTheme = findDefaultTheme(); } return defaultTheme; } private IStyle findDefaultTheme() { if (Platform.isRunning()) { String defaultId = MindMapUIPlugin.getDefault() .getPreferenceStore() .getString(PrefConstants.DEFUALT_THEME); if (defaultId != null && !"".equals(defaultId)) { //$NON-NLS-1$ IStyle theme = getSystemThemeSheet().findStyle(defaultId); if (theme == null) { // theme = getUserStyleSheet().findStyle(defaultId); theme = getUserThemeSheet().findStyle(defaultId); } if (theme != null) return theme; } } return getBlankTheme(); } public void setDefaultTheme(String id) { IStyle theme = null; if (id != null && !"".equals(id)) { //$NON-NLS-1$ theme = getBlankTheme(); if (!id.equals(theme.getId())) { theme = getSystemThemeSheet().findStyle(id); if (theme == null) { theme = getUserThemeSheet().findStyle(id); } } } if (theme == null) id = null; this.defaultTheme = theme; MindMapUIPlugin.getDefault().getPreferenceStore().setValue( PrefConstants.DEFUALT_THEME, id); } public IStyleSheet getSystemThemeSheet() { if (systemThemeSheet == null) { systemThemeSheet = createSystemThemeSheet(); } return systemThemeSheet; } private IStyleSheet createSystemThemeSheet() { URL url = find(PATH_STYLES, THEMES_XML); if (url != null) { try { IStyleSheet sheet = Core.getStyleSheetBuilder() .loadFromUrl(url); URL propUrl = find(PATH_STYLES, THEMES, EXT_PROPERTIES); if (propUrl != null) { try { InputStream propStream = propUrl.openStream(); if (propStream != null) { try { Core.getStyleSheetBuilder().loadProperties( propStream, sheet); } finally { try { propStream.close(); } catch (IOException e) { } } } } catch (Exception e) { Logger.log(e, "Failed to load theme properties: " //$NON-NLS-1$ + propUrl); } } return sheet; } catch (Exception e) { Logger.log(e, "Falied to load system themes: " + url); //$NON-NLS-1$ } } return Core.getStyleSheetBuilder().createStyleSheet(); } public IStyleSheet getUserThemeSheet() { if (userThemesContainer == null) { userThemesContainer = createUserThemeContainer(); } IStyleSheet styleSheet = userThemesContainer.getStyleSheet(); IManifest manifest = userThemesContainer.getManifest(); ((StyleSheetImpl) styleSheet).setManifest(manifest); return styleSheet; } private IWorkbook createUserThemeContainer() { IWorkbook stylesContainer = null; String path = Core.getWorkspace().getAbsolutePath( USER_THEME_TEMP_LOCATION); //styles/userThemes File file = new File(path); IWorkbookBuilder workbookBuilder = Core.getWorkbookBuilder(); if (file.exists() && file.isDirectory() && new File(file, ArchiveConstants.CONTENT_XML).exists()) { try { stylesContainer = workbookBuilder.loadFromTempLocation(path); } catch (Exception e) { Logger.log(e, "Failed to load user themes from: " + file); //$NON-NLS-1$ } } if (stylesContainer == null) { FileUtils.ensureDirectory(file); stylesContainer = workbookBuilder.createWorkbook(); } stylesContainer.setTempLocation(path); return stylesContainer; } public void saveUserThemeSheet() { if (userThemesContainer != null) { try { userThemesContainer.saveTemp(); } catch (Exception e) { } } } private static URL find(String fullPath) { Bundle bundle = Platform.getBundle(MindMapUI.PLUGIN_ID); if (bundle != null) { return FileLocator.find(bundle, new Path(fullPath), null); } return null; } private static URL find(String mainPath, String subPath) { return find(mainPath + subPath); } private static URL find(String mainPath, String prefix, String suffix) { return ResourceFinder.findResource(MindMapUI.PLUGIN_ID, mainPath, prefix, suffix); } }