/* * 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.url.mindmapmode; import java.awt.Component; import java.awt.dnd.DropTarget; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedInputStream; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; 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.OutputStreamWriter; import java.io.Reader; import java.io.SequenceInputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.channels.FileLock; import java.nio.charset.Charset; import java.util.LinkedList; import java.util.Set; import java.util.regex.Pattern; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.filechooser.FileFilter; import org.freeplane.core.extension.IExtension; import org.freeplane.core.resources.NamedObject; import org.freeplane.core.resources.ResourceController; import org.freeplane.core.resources.components.ComboProperty; import org.freeplane.core.resources.components.IPropertyControl; import org.freeplane.core.resources.components.IPropertyControlCreator; import org.freeplane.core.resources.components.OptionPanelBuilder; import org.freeplane.core.ui.IndexedTree; import org.freeplane.core.ui.components.OptionalDontShowMeAgainDialog; import org.freeplane.core.ui.components.UITools; import org.freeplane.core.util.Compat; import org.freeplane.core.util.FileUtils; import org.freeplane.core.util.LogUtils; import org.freeplane.core.util.TextUtils; import org.freeplane.features.link.LinkController; import org.freeplane.features.map.MapChangeEvent; import org.freeplane.features.map.MapController; import org.freeplane.features.map.MapModel; import org.freeplane.features.map.MapWriter.Mode; import org.freeplane.features.map.NodeModel; import org.freeplane.features.map.mindmapmode.MMapController; import org.freeplane.features.map.mindmapmode.MMapModel; import org.freeplane.features.mode.Controller; import org.freeplane.features.mode.ModeController; import org.freeplane.features.mode.mindmapmode.MModeController; import org.freeplane.features.text.TextController; import org.freeplane.features.ui.IMapViewChangeListener; import org.freeplane.features.url.UrlManager; import org.freeplane.n3.nanoxml.XMLException; import org.freeplane.n3.nanoxml.XMLParseException; /** * @author Dimitry Polivaev */ public class MFileManager extends UrlManager implements IMapViewChangeListener { private static final String BACKUP_EXTENSION = "bak"; private static final int DEBUG_OFFSET = 0; static private class BackupFlag implements IExtension { } private class MindMapFilter extends FileFilter { @Override public boolean accept(final File f) { if (f.isDirectory()) { return true; } final String extension = FileUtils.getExtension(f.getName()); if (extension != null) { if (extension.equals(UrlManager.FREEPLANE_FILE_EXTENSION_WITHOUT_DOT)) { return true; } else { return false; } } return false; } @Override public String getDescription() { return TextUtils.getText("mindmaps_desc"); } } private static final String BACKUP_FILE_NUMBER = "backup_file_number"; private static final String FREEPLANE_VERSION_UPDATER_XSLT = "/xslt/freeplane_version_updater.xslt"; private static File singleBackupDirectory; private File[] findFileRevisions(final File file, final File backupDir, final AlternativeFileMode mode) { final String fileExtensionPattern; if(mode == AlternativeFileMode.ALL) fileExtensionPattern = "(" + BACKUP_EXTENSION + "|"+ DoAutomaticSave.AUTOSAVE_EXTENSION + ")"; else fileExtensionPattern = DoAutomaticSave.AUTOSAVE_EXTENSION; final Pattern pattern = Pattern.compile("^" + Pattern.quote(backupFileName(file)) + "\\.+\\d+\\." + fileExtensionPattern); if (backupDir.exists()) { final File[] fileList = backupDir.listFiles(new java.io.FileFilter() { public boolean accept(final File f) { final String name = f.getName(); return pattern.matcher(name).matches() && f.isFile() // && (f.lastModified() > (file.lastModified() - DEBUG_OFFSET) || name.endsWith(BACKUP_EXTENSION)) &&(mode == AlternativeFileMode.ALL || f.lastModified() > (file.lastModified() - DEBUG_OFFSET)); } }); return fileList; } return new File[0]; } /** prevents name conflicts with singleBackupDirectory in most cases (uses the file's hashcode). */ private static String backupFileName(final File file) { if (singleBackupDirectory == null) return file.getName(); return file.getName() + "." + file.hashCode(); } private static void backupFile(final File file, final int backupFileNumber, final String extension) { if (backupFileNumber == 0) { return; } final File backupDir = MFileManager.backupDir(file); backupDir.mkdir(); if (backupDir.exists()) { final File backupFile = MFileManager.renameBackupFiles(backupDir, file, backupFileNumber, extension); if (!backupFile.exists()) { performBackup(file, backupFile); } } } private static void performBackup(final File file, final File backupFile) { try { FileUtils.copyFile(file, backupFile); backupFile.setLastModified(file.lastModified()); } catch (IOException e) { } } private static File backupDir(final File file) { if (singleBackupDirectory != null) return singleBackupDirectory; return new File(file.getParentFile(), DoAutomaticSave.BACKUP_DIR); } static File createBackupFile(final File backupDir, final File file, final int number, final String extension) { return new File(backupDir, backupFileName(file) + '.' + number + '.' + extension); } static File renameBackupFiles(final File backupDir, final File file, final int backupFileNumber, final String extension) { if (backupFileNumber == 0) { return null; } for (int i = backupFileNumber + 1;; i++) { final File newFile = MFileManager.createBackupFile(backupDir, file, i, extension); if (!newFile.exists()) { break; } newFile.delete(); } int i = backupFileNumber; for (;;) { final File newFile = MFileManager.createBackupFile(backupDir, file, i, extension); if (newFile.exists()) { break; } i--; if (i == 0) { break; } } if (i < backupFileNumber) { return MFileManager.createBackupFile(backupDir, file, i + 1, extension); } for (i = 1; i < backupFileNumber; i++) { final File newFile = MFileManager.createBackupFile(backupDir, file, i, extension); final File oldFile = MFileManager.createBackupFile(backupDir, file, i + 1, extension); newFile.delete(); if (!oldFile.renameTo(newFile)) { return null; } } return MFileManager.createBackupFile(backupDir, file, backupFileNumber, extension); } FileFilter filefilter = new MindMapFilter(); public MFileManager() { super(); createActions(); createPreferences(); if (ResourceController.getResourceController().getBooleanProperty("single_backup_directory")) { String value = ResourceController.getResourceController().getProperty("single_backup_directory_path"); // vb, 2010-10-14: I'm not exactly happy with putting this here - if you have a better place move it! if (value != null && value.indexOf("{freeplaneuserdir}") >= 0) { value = value.replace("{freeplaneuserdir}", ResourceController.getResourceController() .getFreeplaneUserDirectory()); ResourceController.getResourceController().setProperty("single_backup_directory_path", value); } singleBackupDirectory = new File(value); } } private void createPreferences() { final MModeController modeController = (MModeController) Controller.getCurrentModeController(); final OptionPanelBuilder optionPanelBuilder = modeController.getOptionPanelBuilder(); optionPanelBuilder.addCreator("Environment/load", new IPropertyControlCreator() { public IPropertyControl createControl() { final Set<String> charsets = Charset.availableCharsets().keySet(); final LinkedList<String> charsetList = new LinkedList<String>(charsets); charsetList.addFirst("JVMdefault"); final LinkedList<String> charsetTranslationList = new LinkedList<String>(charsets); charsetTranslationList.addFirst(TextUtils.getText("OptionPanel.default")); return new ComboProperty("default_charset", charsetList, charsetTranslationList); } }, IndexedTree.AS_CHILD); } private void backup(final File file) { if (file == null) { return; } final int backupFileNumber = ResourceController.getResourceController().getIntProperty(BACKUP_FILE_NUMBER, 0); MFileManager.backupFile(file, backupFileNumber, BACKUP_EXTENSION); } private void createActions() { final Controller controller = Controller.getCurrentController(); final ModeController modeController = controller.getModeController(); controller.addAction(new OpenAction()); controller.addAction(new OpenURLMapAction()); controller.addAction(new NewMapAction()); final File userTemplates = defaultUserTemplateDir(); userTemplates.mkdir(); modeController.addAction(new NewMapFromTemplateAction("new_map_from_user_templates", userTemplates)); modeController.addAction(new SaveAction()); modeController.addAction(new SaveAsAction()); modeController.addAction(new ExportBranchAction()); modeController.addAction(new ImportBranchAction()); modeController.addAction(new ImportLinkedBranchAction()); modeController.addAction(new ImportLinkedBranchWithoutRootAction()); modeController.addAction(new ImportExplorerFavoritesAction()); modeController.addAction(new ImportFolderStructureAction()); modeController.addAction(new RevertAction()); modeController.addAction(new OpenUserDirAction()); } public JFileChooser getFileChooser(boolean useDirectorySelector) { final JFileChooser fileChooser = getFileChooser(getFileFilter(), useDirectorySelector); return fileChooser; } public FileFilter getFileFilter() { return filefilter; }; protected JComponent createDirectorySelector(final JFileChooser chooser) { final JComboBox box = new JComboBox(); box.setEditable(false); final File dir = getLastCurrentDir() != null ? getLastCurrentDir() : chooser.getCurrentDirectory(); final File templateDir = defaultStandardTemplateDir(); final File userTemplateDir = defaultUserTemplateDir(); box.addItem(new NamedObject(dir, TextUtils.getText("current_dir"))); box.addItem(new NamedObject(templateDir, TextUtils.getText("template_dir"))); box.addItem(new NamedObject(userTemplateDir, TextUtils.getText("user_template_dir"))); box.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final JComboBox box = (JComboBox) e.getSource(); final NamedObject obj = (NamedObject) box.getSelectedItem(); final File dir = (File) obj.getObject(); chooser.setCurrentDirectory(dir); } }); File selectedDir = chooser.getCurrentDirectory(); final String selectedPath = selectedDir.getAbsolutePath(); if (!selectedDir.equals(dir)) { for (int i = 0; i < box.getItemCount(); i++) { NamedObject item = (NamedObject) box.getItemAt(i); File itemDir = (File) item.getObject(); if (itemDir.getAbsolutePath().equals(selectedPath)) { box.setSelectedItem(item); break; } } } return box; } /** * Creates a proposal for a file name to save the map. Removes all illegal * characters. Fixed: When creating file names based on the text of the root * node, now all the extra unicode characters are replaced with _. This is * not very good. For chinese content, you would only get a list of ______ * as a file name. Only characters special for building file paths shall be * removed (rather than replaced with _), like : or /. The exact list of * dangeous characters needs to be investigated. 0.8.0RC3. Keywords: suggest * file name. * * @param map */ private String getFileNameProposal(final MapModel map) { String rootText = TextController.getController().getPlainTextContent((map.getRootNode())); rootText = rootText.replaceAll("[&:/\\\\\0%$#~\\?\\*]+", ""); return rootText; } public URI getLinkByFileChooser(final MapModel map) { JFileChooser chooser = null; final File file = map.getFile(); if (file == null && LinkController.getLinkType() == LinkController.LINK_RELATIVE_TO_MINDMAP) { JOptionPane.showMessageDialog(Controller.getCurrentController().getViewController().getContentPane(), TextUtils.getText("not_saved_for_link_error"), "Freeplane", JOptionPane.WARNING_MESSAGE); return null; } if (getLastCurrentDir() != null) { chooser = new JFileChooser(getLastCurrentDir()); } else { chooser = new JFileChooser(); } chooser.setAcceptAllFileFilterUsed(true); chooser.setFileFilter(chooser.getAcceptAllFileFilter()); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); final int returnVal = chooser.showOpenDialog(Controller.getCurrentController().getViewController() .getContentPane()); if (returnVal != JFileChooser.APPROVE_OPTION) { return null; } final File input = chooser.getSelectedFile(); setLastCurrentDir(input.getParentFile()); return LinkController.toLinkTypeDependantURI(file, input); } /**@deprecated -- use MapIO*/ @Deprecated public void loadAndLock(final URL url, final MapModel map) throws FileNotFoundException, IOException, XMLParseException, URISyntaxException { final File file = Compat.urlToFile(url); if(file == null){ super.loadCatchExceptions(url, map); return; } if (!file.exists()) { throw new FileNotFoundException(TextUtils.format("file_not_found", file.getPath())); } if (!file.canWrite()) { map.setReadOnly(true); } try { final String lockingUser = tryToLock(map, file); if (lockingUser != null) { UITools.informationMessage(Controller.getCurrentController().getViewController().getFrame(), TextUtils.format("map_locked_by_open", file.getName(), lockingUser)); map.setReadOnly(true); } } catch (final Exception e) { LogUtils.severe(e); UITools.informationMessage(Controller.getCurrentController().getViewController().getFrame(), TextUtils.format("locking_failed_by_open", file.getName())); map.setReadOnly(true); } if (file.length() != 0) { //Fixme: Docear - set the file for the map before parsing the xml --> needed by org.docear.plugin.pdfutilities.features.AnnotationXmlBuilder:95 setFile(map, file); NodeModel root = loadTree(map, file); assert(map.getRootNode() == root); } if(map.getRootNode() == null) map.createNewRoot(); } public URL getAlternativeURL(final URL url, AlternativeFileMode mode){ try { final File file = Compat.urlToFile(url); if(file == null){ return url; } File alternativeFile; alternativeFile = getAlternativeFile(file, mode); if(alternativeFile != null) return Compat.fileToUrl(alternativeFile); else return null; } catch (MalformedURLException e) { } catch (URISyntaxException e) { } return null; } public enum AlternativeFileMode{ALL, AUTOSAVE}; public File getAlternativeFile(final File file, AlternativeFileMode mode){ final File[] revisions = findFileRevisions(file, MFileManager.backupDir(file), mode); if(revisions.length == 0 && mode == AlternativeFileMode.AUTOSAVE) return file; final FileRevisionsDialog newerFileRevisionsFoundDialog = new FileRevisionsDialog(file, revisions, mode); final File selectedFile = newerFileRevisionsFoundDialog.getSelectedFile(); if(file.equals(selectedFile)){ boolean success = file.setLastModified(System.currentTimeMillis()); if (!success) LogUtils.warn("Unable to set the last modification time for " + file); } return selectedFile; } /**@deprecated -- use MMapIO*/ @Deprecated public NodeModel loadTree(final MapModel map, final File file) throws XMLParseException, IOException { try { final NodeModel rootNode = loadTreeImpl(map, file); return rootNode; } catch (final Exception ex) { final String errorMessage = "Error while parsing file:" + file; LogUtils.warn(errorMessage, ex); UITools.errorMessage(errorMessage); final NodeModel result = new NodeModel(map); result.setText(errorMessage); return result; } } //DOCEAR private NodeModel loadTreeImpl(final MapModel map, final File f) throws FileNotFoundException, IOException, XMLException, MapConversionException { final BufferedInputStream file = new BufferedInputStream(new FileInputStream(f)); int versionInfoLength = 1000; final byte[] buffer = new byte[versionInfoLength]; final int readCount = file.read(buffer); final String mapStart = new String(buffer, FileUtils.defaultCharset().name()); final ByteArrayInputStream readBytes = new ByteArrayInputStream(buffer, 0, readCount); final InputStream sequencedInput = new SequenceInputStream(readBytes, file); Reader reader = null; MapVersionInterpreter versionInterpreter = MapVersionInterpreter.getVersionInterpreter(mapStart); if(versionInterpreter.anotherDialect){ String message = versionInterpreter.getDialectInfo(f.getAbsolutePath()); UITools.showMessage(message, JOptionPane.WARNING_MESSAGE); } if(versionInterpreter.needsConversion){ final int showResult = OptionalDontShowMeAgainDialog.show("really_convert_to_current_version", "confirmation", MMapController.RESOURCES_CONVERT_TO_CURRENT_VERSION, OptionalDontShowMeAgainDialog.ONLY_OK_SELECTION_IS_STORED); IMapInputStreamConverter isConverter = versionInterpreter.getMapInputStreamConverter(); if (showResult != JOptionPane.OK_OPTION || isConverter == null) { reader = UrlManager.getActualReader(sequencedInput); } else { sequencedInput.close(); reader = isConverter.getConvertedStream(f); } } else reader = UrlManager.getActualReader(sequencedInput); try { NodeModel root = Controller.getCurrentModeController().getMapController().getMapReader() .createNodeTreeFromXml(map, reader, Mode.FILE); if (versionInterpreter.getMapConverter() != null) { versionInterpreter.getMapConverter().convert(root); } return root; } finally { FileUtils.silentlyClose(reader); } } /**@deprecated -- use LinkController*/ @Deprecated @Override public void loadURL(final URI relative) { final MapModel map = Controller.getCurrentController().getMap(); if (map == null || map.getURL() == null) { if (!relative.toString().startsWith("#") && !relative.isAbsolute() || relative.isOpaque()) { Controller.getCurrentController().getViewController().out("You must save the current map first!"); final boolean result = ((MFileManager) UrlManager.getController()).save(map); if (!result) { return; } } } super.loadURL(relative); } /**@deprecated -- use MapIO*/ @Deprecated public void open() { final JFileChooser chooser = getFileChooser(false); chooser.setMultiSelectionEnabled(true); final int returnVal = chooser .showOpenDialog(Controller.getCurrentController().getViewController().getMapView()); if (returnVal != JFileChooser.APPROVE_OPTION) { return; } File[] selectedFiles; selectedFiles = chooser.getSelectedFiles(); for (int i = 0; i < selectedFiles.length; i++) { final File theFile = selectedFiles[i]; try { setLastCurrentDir(theFile.getParentFile()); Controller.getCurrentModeController().getMapController().newMap(Compat.fileToUrl(theFile)); } catch (final Exception ex) { handleLoadingException(ex); break; } } Controller.getCurrentController().getViewController().setTitle(); } /**@deprecated -- use MMapIO*/ @Deprecated public MapModel newMapFromDefaultTemplate() { final File file = defaultTemplateFile(); if (file != null) { return newMapFromTemplate(file); } final MapController mapController = Controller.getCurrentModeController().getMapController(); final MapModel map = mapController.newMap(); mapController.setSaved(map, true); return map; } public File defaultTemplateFile() { final String userDefinedTemplateFile = getStandardTemplateName(); final File absolute = new File(userDefinedTemplateFile); if(absolute.isAbsolute() && absolute.exists() && ! absolute.isDirectory()){ return absolute; } final File userTemplates = defaultUserTemplateDir(); final File userStandard = new File(userTemplates, userDefinedTemplateFile); if(userStandard.exists() && ! userStandard.isDirectory()) return userStandard; return null; } public File defaultUserTemplateDir() { final String userDir = ResourceController.getResourceController().getFreeplaneUserDirectory(); final File userTemplates = new File(userDir, "templates"); return userTemplates; } public File defaultStandardTemplateDir() { final String resourceBaseDir = ResourceController.getResourceController().getResourceBaseDir(); final File allUserTemplates = new File(resourceBaseDir, "templates"); return allUserTemplates; } public String getStandardTemplateName() { return ResourceController.getResourceController().getProperty("standard_template"); } /**@deprecated -- use MMapIO*/ @Deprecated public MapModel newMapFromTemplate(final File startFile) { final File file; if (startFile == null) { file = getLastCurrentDir(); } else if (startFile.isDirectory()) { final JFileChooser chooser = getFileChooser(true); chooser.setCurrentDirectory(startFile); final int returnVal = chooser.showOpenDialog(Controller.getCurrentController().getViewController() .getMapView()); if (returnVal != JFileChooser.APPROVE_OPTION) { return null; } file = chooser.getSelectedFile(); } else { file = startFile; } try { final MMapController mapController = (MMapController) Controller.getCurrentModeController().getMapController(); mapController.newUntitledMap(Compat.fileToUrl(file)); final Controller controller = Controller.getCurrentController(); final MapModel map = controller.getMap(); final Object rootText = map.getRootNode().getUserObject(); if(rootText instanceof NamedObject){ map.getRootNode().setText(rootText.toString()); } controller.getModeController().getMapController().setSaved(map, true); return map; } catch (Exception e) { handleLoadingException(e); } return null; } /**@deprecated -- use MMapIO*/ @Deprecated public void saveAsUserTemplate() { final JFileChooser chooser = new JFileChooser(); final FileFilter filter = getFileFilter(); chooser.addChoosableFileFilter(filter); chooser.setFileFilter(filter); final File userTemplates = defaultUserTemplateDir(); chooser.setCurrentDirectory(userTemplates); final int returnVal = chooser .showOpenDialog(Controller.getCurrentController().getViewController().getMapView()); if (returnVal != JFileChooser.APPROVE_OPTION) { return; } File file = chooser.getSelectedFile(); if (file.exists()) { final int overwriteMap = JOptionPane.showConfirmDialog(Controller.getCurrentController() .getViewController().getMapView(), TextUtils.getText("map_already_exists"), "Freeplane", JOptionPane.YES_NO_OPTION); if (overwriteMap != JOptionPane.YES_OPTION) { return; } } saveInternal((MMapModel) Controller.getCurrentController().getMap(), file, false); } /**@deprecated -- use MMapIO*/ @Deprecated public boolean save(final MapModel map) { return save(map, false); } public boolean save(final MapModel map, final boolean showHiddenFiles) { if (map == null || map.isSaved()) { return true; } if (map.getURL() == null || map.isReadOnly()) { return saveAs(map, showHiddenFiles); } else { return save(map, map.getFile()); } } /**@deprecated -- use MMapIO*/ @Deprecated public boolean save(final MapModel map, final File file) { if(file == null){ return saveAs(map); } try { if (null == map.getExtension(BackupFlag.class)) { map.addExtension(new BackupFlag()); backup(file); } final String lockingUser = tryToLock(map, file); if (lockingUser != null) { UITools.informationMessage(Controller.getCurrentController().getViewController().getFrame(), TextUtils.format("map_locked_by_save_as", file.getName(), lockingUser)); return false; } } catch (final Exception e) { UITools.informationMessage(Controller.getCurrentController().getViewController().getFrame(), TextUtils.format("locking_failed_by_save_as", file.getName())); return false; } final URL urlBefore = map.getURL(); final boolean saved = saveInternal((MMapModel) map, file, false); if (!saved) { return false; } map.setReadOnly(false); final URL urlAfter = map.getURL(); final MMapController mapController = (MMapController) Controller.getCurrentModeController().getMapController(); mapController.fireMapChanged(new MapChangeEvent(this, map, UrlManager.MAP_URL, urlBefore, urlAfter)); mapController.fireMapSaved(map); mapController.setSaved(map, true); return true; } /**@deprecated -- use MMapIO*/ @Deprecated public boolean saveAs(final MapModel map) { return saveAs(map, false); } public boolean saveAs(final MapModel map, boolean showHiddenFiles) { //FIXME - DOCEAR: changed the getFileChooser from 'true' to 'false' because its for files not directories final JFileChooser chooser = getFileChooser(false); if (getMapsParentFile(map) == null) { chooser.setSelectedFile(new File(getFileNameProposal(map) + org.freeplane.features.url.UrlManager.FREEPLANE_FILE_EXTENSION)); } else { chooser.setSelectedFile(map.getFile()); } if (showHiddenFiles) { chooser.setFileHidingEnabled(false); } chooser.setDialogTitle(TextUtils.getText("SaveAsAction.text")); final int returnVal = chooser .showSaveDialog(Controller.getCurrentController().getViewController().getMapView()); if (returnVal != JFileChooser.APPROVE_OPTION) { return false; } File f = chooser.getSelectedFile(); setLastCurrentDir(f.getParentFile()); final String ext = FileUtils.getExtension(f.getName()); if (!ext.equals(org.freeplane.features.url.UrlManager.FREEPLANE_FILE_EXTENSION_WITHOUT_DOT)) { f = new File(f.getParent(), f.getName() + org.freeplane.features.url.UrlManager.FREEPLANE_FILE_EXTENSION); } if (f.exists()) { final int overwriteMap = JOptionPane.showConfirmDialog(Controller.getCurrentController() .getViewController().getMapView(), TextUtils.getText("map_already_exists"), "Freeplane", JOptionPane.YES_NO_OPTION); if (overwriteMap != JOptionPane.YES_OPTION) { return false; } } // extra backup in this case. File oldFile = map.getFile(); if (oldFile != null) { oldFile = oldFile.getAbsoluteFile(); } if (!f.getAbsoluteFile().equals(oldFile) && null != map.getExtension(BackupFlag.class)) { map.removeExtension(BackupFlag.class); } if (save(map, f)) { Controller.getCurrentController().getMapViewManager().updateMapViewName(); Controller.getCurrentModeController().getMapController().fireMapSavedAs(map); return true; } return false; } /** * This method is intended to provide both normal save routines and saving * of temporary (internal) files. */ boolean saveInternal(final MMapModel map, final File file, final boolean isInternal) { if (file.exists() && !file.canWrite()) { LogUtils.severe("Attempt to write in read-only file."); return false; } try { if (map.getTimerForAutomaticSaving() != null) { map.getTimerForAutomaticSaving().cancel(); } if (!isInternal) { map.setURL(Compat.fileToUrl(file)); map.setSaved(true); } writeToFile(map, file); map.scheduleTimerForAutomaticSaving(); return true; } catch (final IOException e) { final String message = TextUtils.format("save_failed", file.getName()); if (!isInternal) { UITools.errorMessage(message); } else { Controller.getCurrentController().getViewController().out(message); } } catch (final Exception e) { LogUtils.severe("Error in MapModel.save(): ", e); } map.scheduleTimerForAutomaticSaving(); return false; } /**@deprecated -- use MMapIO*/ @Deprecated public void writeToFile(final MapModel map, final File file) throws FileNotFoundException, IOException { final FileOutputStream out = new FileOutputStream(file); final FileLock lock = out.getChannel().tryLock(); if (lock == null) { throw new IOException("can not obtain file lock for " + file); } try { final BufferedWriter fileout = new BufferedWriter(new OutputStreamWriter(out)); Controller.getCurrentModeController().getMapController().getMapWriter() .writeMapAsXml(map, fileout, Mode.FILE, true, false); } finally { if (lock.isValid()) { lock.release(); } } } public void setFile(final MapModel map, final File file) { try { final URL url = Compat.fileToUrl(file); setURL(map, url); } catch (final MalformedURLException e) { LogUtils.severe(e); } } /** * Attempts to lock the map using a semaphore file * * @return If the map is locked, return the name of the locking user, * otherwise return null. * @throws Exception * , when the locking failed for other reasons than that the * file is being edited. * * @deprecated -- use MMapIO */ @Deprecated public String tryToLock(final MapModel map, final File file) throws Exception { final String lockingUser = ((MMapModel) map).getLockManager().tryToLock(file); final String lockingUserOfOldLock = ((MMapModel) map).getLockManager().popLockingUserOfOldLock(); if (lockingUserOfOldLock != null) { UITools.informationMessage(Controller.getCurrentController().getViewController().getFrame(), TextUtils.format("locking_old_lock_removed", file.getName(), lockingUserOfOldLock)); } return lockingUser; } public void afterViewChange(final Component oldView, final Component newView) { } public void afterViewClose(final Component oldView) { } public void afterViewCreated(final Component mapView) { if (mapView != null) { final FileOpener fileOpener = new FileOpener(); new DropTarget(mapView, fileOpener); } } public void beforeViewChange(final Component oldView, final Component newView) { } public static MFileManager getController(ModeController modeController) { return (MFileManager) modeController.getExtension(UrlManager.class); } }