package org.geopublishing.geopublisher.swing;
/*******************************************************************************
* Copyright (c) 2010 Stefan A. Tzeggai.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v2.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* Stefan A. Tzeggai - initial API and implementation
******************************************************************************/
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.WindowConstants;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.log4j.Logger;
import org.geopublishing.atlasViewer.AVProps;
import org.geopublishing.atlasViewer.AtlasConfig;
import org.geopublishing.atlasViewer.AtlasRefInterface;
import org.geopublishing.atlasViewer.dp.DpEntry;
import org.geopublishing.atlasViewer.dp.DpRef;
import org.geopublishing.atlasViewer.dp.Group;
import org.geopublishing.atlasViewer.dp.layer.DpLayer;
import org.geopublishing.atlasViewer.dp.media.DpMedia;
import org.geopublishing.atlasViewer.exceptions.AtlasImportException;
import org.geopublishing.atlasViewer.map.Map;
import org.geopublishing.atlasViewer.swing.AVSwingUtil;
import org.geopublishing.geopublisher.AMLExporter;
import org.geopublishing.geopublisher.AtlasConfigEditable;
import org.geopublishing.geopublisher.GpUtil;
import org.geopublishing.geopublisher.gui.internal.GPDialogManager;
import org.geopublishing.geopublisher.gui.map.DesignHTMLInfoPane;
import chrriis.dj.nativeswing.swtimpl.components.JFileDialog;
import chrriis.dj.nativeswing.swtimpl.components.JFileDialog.DialogType;
import de.schmitzm.i18n.I18NUtil;
import de.schmitzm.io.IOUtil;
import de.schmitzm.jfree.chart.style.ChartStyle;
import de.schmitzm.lang.LangUtil;
import de.schmitzm.swing.DialogManager;
import de.schmitzm.swing.ExceptionDialog;
import de.schmitzm.swing.FileExtensionFilter;
import de.schmitzm.swing.SwingUtil;
import de.schmitzm.swing.swingworker.AtlasSwingWorker;
public class GpSwingUtil extends GpUtil {
private static final Logger LOGGER = Logger.getLogger(GpSwingUtil.class);
/**
* Deletes a {@link DpEntry}. This deletes the Entry from the Atlas'
* datapool, as well as all references to it, as well as the folder on disk.
*
* @param ace
* {@link AtlasConfigEditable} where the {@link DpEntry} is part
* of.
* @param dpe
* {@link DpEntry} to be deleted.
* @param askUserToVerify
* If <code>true</code>, the user will be asked for confirmation.
* The confirmation will list all references. If
* <code>false</code>, the DPE and all references are
* automatically removed.
*
* @return <code>null</code> if the deletion failed or was aborted by the
* user. Otherwise the removed {@link DpEntry}.
*/
public static DpEntry<?> deleteDpEntry(Component owner,
AtlasConfigEditable ace, DpEntry<?> dpe, boolean askUserToVerify) {
LinkedList<AtlasRefInterface<?>> references = new LinkedList<AtlasRefInterface<?>>();
// ****************************************************************************
// Go through all mapPoolEntries and groups and count the references to
// this DatapoolEntry
// ****************************************************************************
Set<Map> mapsWithReferences = new HashSet<Map>();
for (Map map : ace.getMapPool().values()) {
for (DpRef<DpLayer<?, ? extends ChartStyle>> ref : map.getLayers()) {
if (ref.getTargetId().equals(dpe.getId())) {
references.add(ref);
mapsWithReferences.add(map);
}
}
for (DpRef<DpMedia<? extends ChartStyle>> ref : map.getMedia()) {
if (ref.getTargetId().equals(dpe.getId())) {
references.add(ref);
mapsWithReferences.add(map);
}
}
map.getAdditionalStyles().remove(dpe.getId());
map.getSelectedStyleIDs().remove(dpe.getId());
}
int countRefsInMappool = references.size();
// ****************************************************************************
// Go through all group tree count the references to this DatapoolEntry
// ****************************************************************************
Group group = ace.getRootGroup();
Group.findReferencesTo(group, dpe, references, false);
if (askUserToVerify) {
// Ask the user if she still wants to delete the DPE, even though
// references exist.
int res = JOptionPane.showConfirmDialog(owner, GpUtil.R(
"DeleteDpEntry.QuestionDeleteDpeAndReferences", dpe
.getFilename(), countRefsInMappool, LangUtil
.stringConcatWithSep(", ", mapsWithReferences),
references.size() - countRefsInMappool, dpe.getTitle()
.toString()), GpUtil
.R("DataPoolWindow_Action_DeleteDPE_label" + " "
+ dpe.getTitle()), JOptionPane.YES_NO_OPTION);
if (res != JOptionPane.YES_OPTION)
return null;
}
// Close all dialogs that use this layer
if (!GPDialogManager.closeAllMapComposerDialogsUsing(dpe))
return null;
// ****************************************************************************
// Delete the references first. Kill DesignMapViewJDialogs if affected.
// Abort everything if the user doesn't want to close the
// DesignMapViewJDialog.
// ****************************************************************************
for (Map map : ace.getMapPool().values()) {
boolean affected = false;
// Check all the layers
final LinkedList<DpRef<DpLayer<?, ? extends ChartStyle>>> layersNew = new LinkedList<DpRef<DpLayer<?, ? extends ChartStyle>>>();
for (DpRef<DpLayer<?, ? extends ChartStyle>> ref : map.getLayers()) {
if (!ref.getTargetId().equals(dpe.getId()))
layersNew.add(ref);
else {
affected = true;
}
}
// Check all the media
final List<DpRef<DpMedia<? extends ChartStyle>>> mediaNew = new LinkedList<DpRef<DpMedia<? extends ChartStyle>>>();
for (DpRef<DpMedia<? extends ChartStyle>> ref : map.getMedia()) {
if (!ref.getTargetId().equals(dpe.getId()))
mediaNew.add(ref);
else {
affected = true;
}
}
// Close any open DesignMapViewJDialogs or abort if the user doesn't
// want to close.
if (affected) {
if (!GPDialogManager.dm_MapComposer.close(map))
return null;
}
// Now we change this map
map.setLayers(layersNew);
map.setMedia(mediaNew);
// Under windows deleting the .prj of a Shape fails if we do not
// uncache any affected map here.
map.uncache();
}
Group.findReferencesTo(group, dpe, references, true);
final File dir = new File(ace.getDataDir(), dpe.getDataDirname());
try {
FileUtils.deleteDirectory(dir);
} catch (IOException e) {
ExceptionDialog.show(owner, e);
}
return ace.getDataPool().remove(dpe.getId());
}
/**
* Checks if a filename is OK for the AV. Asks the use to accespt the
* changed name
*
* @param owner
* GUI owner
* @param nameCandidate
* Filename to check, e.g. bahn.jpg
* @return <code>null</code> if the user didn't accept the new filename.
*
* @throws AtlasImportException
* if the user doesn't like the change of the filename.
*/
public static String cleanFilenameWithUI(Component owner,
String nameCandidate) throws AtlasImportException {
String cleanName = IOUtil.cleanFilename(nameCandidate);
if (!cleanName.equals(nameCandidate)) {
/**
* The candidate was not clean. Ask the user to accept the new name
* or cancel.
*/
if (!AVSwingUtil.askOKCancel(owner,
R("Cleanfile.Question", nameCandidate, cleanName))) {
throw new AtlasImportException(R(
"Cleanfile.Denied.ImportCancelled", nameCandidate));
}
}
return cleanName;
}
/**
* Validates, that all directory references actually exist. If some
* directory is missing, asks the user if he want's to delete the entry and
* all references to it.<br/>
* Also checks that all directories in <code>ad/data</code> folder are
* actually referenced. If now, the used is asked to delete the folder.</br>
* This method also initializes the size-cache for every {@link DpEntry}.
*/
public static void validate(AtlasConfigEditable ace, final Component owner) {
LOGGER.debug("starting validation of datatpool");
LinkedList<DpEntry<?>> errorEntries = new LinkedList<DpEntry<?>>();
// ****************************************************************************
// First collect all erroneous DpEntries...
// ****************************************************************************
for (DpEntry<?> dpe : ace.getDataPool().values()) {
File dir = new File(ace.getDataDir(), dpe.getDataDirname());
// Checking for possible errors...
if (!dir.exists() || !dir.isDirectory()) {
errorEntries.add(dpe);
} else {
// Calculate the size of the folder now and cache it for
// later...
ace.getFolderSize(dpe);
}
}
// ****************************************************************************
// ... now delete them. (We should not modify a datapool that we are
// iterating through.
// ****************************************************************************
for (final DpEntry<?> dpe : errorEntries) {
final String msg1 = GpUtil.R(
"AtlasLoader.Validation.dpe.invalid.msg", dpe.getTitle(),
dpe.getId());
final String msg2 = GpUtil.R(
"AtlasLoader.Validation.dpe.invalid.msg.folderDoesnExist",
new File(ace.getDataDir(), dpe.getDataDirname())
.getAbsolutePath());
final String question = GpUtil
.R("AtlasLoader.Validation.dpe.invalid.msg.exitOrRemoveQuestion");
if (SwingUtil.askYesNo(owner, msg1 + "\n" + msg2 + "\n" + question)) {
deleteDpEntry(owner, ace, dpe, false);
}
}
cleanFolder(ace, owner);
}
/**
* Checks the data dir folder of the {@link AtlasConfigEditable} and asks to
* delete any unexpected folders.
*
* @param owner
* if <code>null</code> all files will be deleted automatically
*/
public static void cleanFolder(AtlasConfigEditable ace,
final Component owner) {
File[] unreferencedDirs = new File[0];
// ****************************************************************************
// now list all directories in ad/html and check whether they are
// actually used
// ****************************************************************************
for (File dir : ace.getHtmlDir().listFiles()) {
if (!dir.isDirectory())
continue;
if (dir.getName().startsWith("."))
continue;
// if (dir.getName().equals(AtlasConfigEditable.IMAGES_DIRNAME))
// continue;
if (dir.getName().equals(AtlasConfigEditable.ABOUT_DIRNAME))
continue;
boolean isReferenced = false;
for (Map map : ace.getMapPool().values()) {
if (ace.getHtmlDirFor(map).getName().equals(dir.getName())) {
isReferenced = true;
break;
}
}
// ****************************************************************************
// now list all directories in ad/data and check whether they are
// actually used
// ****************************************************************************
if (!isReferenced) {
for (DpEntry<?> dpe : ace.getDataPool().values()) {
if (dpe.getDataDirname().equals(dir.getName())) {
isReferenced = true;
break;
}
}
}
if (isReferenced)
continue;
unreferencedDirs = LangUtil.extendArray(unreferencedDirs, dir);
LOGGER.info("The directory " + IOUtil.escapePath(dir)
+ " is not referenced in the atlas.");
}
if(unreferencedDirs.length > 0)
askToDeleteUnreferencedFolders(unreferencedDirs, owner);
}
/**
* Asks to delete unreferenced Folders and returns <code>true</code> if they
* have been deleted.
*
* @param unrefDirs
* @param owner
* @return
*/
private static boolean askToDeleteUnreferencedFolders(File[] unrefDirs,
Component owner) {
boolean askDelete = true;
if (owner != null) {
CleanUnreferencedFoldersDialog cufd = new CleanUnreferencedFoldersDialog(
unrefDirs, owner);
askDelete = cufd.isAccepted();
}
if (askDelete) {
for (File d : unrefDirs) {
if ((d.isDirectory() && new File(d, ".svn").exists())) {
LOGGER.info("Please use:\nsvn del \""
+ IOUtil.escapePath(d) + "\" && svn commit \""
+ IOUtil.escapePath(d)
+ "\" -m \"deleted an unused directory\"");
if (owner != null)
AVSwingUtil
.showMessageDialog(
owner,
GpSwingUtil
.R("UnreferencedDirectoryFoundInAtlasDataDir_WillNotBeDeletedDueToSvnButOfferTheCommand",
d.getName(),
IOUtil.escapePath(d)));
} else {
FileUtils.deleteQuietly(d);
}
}
return true;
}
return false;
}
// /**
// * Asks to delete a file or folder and returns <code>true</code> if the file
// * has been deleted.
// *
// * TODO MJ ST Obsolete?
// * Auskommentiert seit 26.5.2012
// */
// private static boolean askToDeleteUnreferencedFolder(File dir,
// final Component owner, File d) {
//
// boolean askDelete = true;
// if (owner != null)
// askDelete = AVSwingUtil
// .askOKCancel(
// owner,
// GpSwingUtil
// .R("UnreferencedDirectoryFoundInAtlasDataDir_AskIfItShouldBeDeleted",
// IOUtil.escapePath(dir), d.getName()));
// if (askDelete) {
// if (owner != null)
// LOGGER.info("User allowed to delete folder "
// + IOUtil.escapePath(d) + ".");
// else
// LOGGER.info("Automatically delete folder "
// + IOUtil.escapePath(d) + ".");
//
// if ((d.isDirectory() && new File(d, ".svn").exists())) {
// LOGGER.info("Please use:\nsvn del \"" + IOUtil.escapePath(d)
// + "\" && svn commit \"" + IOUtil.escapePath(d)
// + "\" -m \"deleted an unused directory\"");
//
// if (owner != null)
// AVSwingUtil
// .showMessageDialog(
// owner,
// GpSwingUtil
// .R("UnreferencedDirectoryFoundInAtlasDataDir_WillNotBeDeletedDueToSvnButOfferTheCommand",
// d.getName(),
// IOUtil.escapePath(d)));
// } else {
//
// // Just delete the directory!
//
// return FileUtils.deleteQuietly(d);
// }
// }
// return false;
// }
/**
* Save the {@link AtlasConfig} to its project directory
*
* @param parentGUI
* If not <code>null</code>, the user get's feedback message
* SaveAtlas.Success.Message
*
* @return false Only if there happened an error while saving. If there is
* nothing to save, returns true;
*/
public static boolean save(final AtlasConfigEditable ace,
final Component parentGUI, boolean confirm) {
SwingUtil.checkOnEDT();
AtlasSwingWorker<Boolean> swingWorker = new AtlasSwingWorker<Boolean>(
parentGUI) {
@Override
protected Boolean doInBackground() throws Exception {
AMLExporter amlExporter = new AMLExporter(ace);
if (amlExporter.saveAtlasConfigEditable(statusDialog)) {
ace.getProperties().save(
new File(ace.getAtlasDir(),
AVProps.PROPERTIESFILE_RESOURCE_NAME));
new File(ace.getAtlasDir(),
AtlasConfigEditable.ATLAS_GPA_FILENAME)
.createNewFile();
return true;
}
return false;
}
};
try {
Boolean saved = swingWorker.executeModal();
if (saved && confirm) {
JOptionPane.showMessageDialog(parentGUI,
GeopublisherGUI.R("SaveAtlas.Success.Message"));
}
return saved;
} catch (Exception e) {
ExceptionDialog.show(parentGUI, e);
return false;
}
}
/**
* Returns a {@link List} of {@link File}s that point to the HTML info files
* of a DpLayer. The order of the {@link File}s in the {@link List} is equal
* to the order of the languages.<br/>
* All HTML files returned to exist! If they don't exist they are being
* created with a default text.
*
* @param dpl
* {@link DpLayer} that the HTML files belong to.
*/
static public List<File> getHTMLFilesFor(
DpLayer<?, ? extends ChartStyle> dpl) {
List<File> htmlFiles = new ArrayList<File>();
AtlasConfigEditable ac = (AtlasConfigEditable) dpl.getAtlasConfig();
File dir = new File(ac.getDataDir(), dpl.getDataDirname());
for (String lang : ac.getLanguages()) {
try {
File htmlFile = new File(
(FilenameUtils.removeExtension(new File(dir, dpl
.getFilename()).getCanonicalPath())
+ "_"
+ lang + ".html"));
if (!htmlFile.exists()) {
LOGGER.info("Creating a default info HTML file for dpe "
+ dpl.getTitle() + "\n at "
+ htmlFile.getAbsolutePath());
/**
* Create a default HTML About window
*/
FileWriter fw = new FileWriter(htmlFile);
fw.write(GpUtil.R("DPLayer.HTMLInfo.DefaultHTMLFile",
I18NUtil.getFirstLocaleForLang(lang)
.getDisplayLanguage(), dpl.getTitle()));
fw.flush();
fw.close();
}
htmlFiles.add(htmlFile);
} catch (IOException e) {
LOGGER.error(e);
ExceptionDialog.show(GeopublisherGUI.getInstance().getJFrame(),
e);
}
}
return htmlFiles;
}
/**
* Returns a {@link List} of {@link File}s that point to the HTML info
* filesfor a {@link Map}. The order of the {@link File}s in the
* {@link List} is equal to the order of the languages.<br/>
* All HTML files returned to exist! If they don't exist they are being
* created with a default text.
*
* @param dpl
* {@link DpLayer} that the HTML files belong to.
*/
public static List<File> getHTMLFilesFor(Map map) {
List<File> htmlFiles = new ArrayList<File>();
AtlasConfigEditable ace = (AtlasConfigEditable) map.getAc();
File dir = new File(ace.getHtmlDir(), map.getId());
dir.mkdirs();
for (String lang : ace.getLanguages()) {
try {
File htmlFile = new File(new File(dir, "index" + "_" + lang
+ ".html").getCanonicalPath());
if (!htmlFile.exists()) {
LOGGER.info("Creating a default info HTML file for map "
+ map.getTitle() + "\n at "
+ htmlFile.getAbsolutePath());
/**
* Create a default HTML About window
*/
FileWriter fw = new FileWriter(htmlFile);
fw.write(GpUtil.R("Map.HTMLInfo.DefaultHTMLFile", I18NUtil
.getFirstLocaleForLang(lang).getDisplayLanguage(),
map.getTitle()));
fw.flush();
fw.close();
}
htmlFiles.add(htmlFile);
} catch (IOException e) {
LOGGER.error(e);
ExceptionDialog.show(GeopublisherGUI.getInstance().getJFrame(),
e);
}
}
return htmlFiles;
}
/**
* Factory method to create an design html viewport.
*
* @param map
* a Map
*/
public static DesignHTMLInfoPane createDesignHTMLInfoPane(
AtlasConfigEditable ace, Map map) {
// Note: although we now have 2 versions to display html...
// a) JEditorPane -> HTMLInfoJPane
// b) JWebBrowser -> HTMLInfoJWebBrowser
// c) LOBO -> HTMLInfoLoboBrowser
// ... we only have ONE version of DesignHTMLInfoPane, which
// uses (a), (b) or (c) according to the factory method
// AVUtil.createHTMLInfoPane(.)
return new DesignHTMLInfoPane(ace, map);
}
/**
* Factory method to create an design html editor.
*
* @param map
* a Map
*/
public static HTMLEditPaneInterface createHTMLEditPane(
AtlasConfigEditable ace) {
HTMLEditPaneInterface htmlEditPane = null;
// try to use an HTML view based on DJ project
htmlEditPane = (HTMLEditPaneInterface) LangUtil.instantiateObject(
"org.geopublishing.geopublisher.swing.HTMLEditPaneJHTMLEditor",
true, // fallback if class can not be
// loaded
"CK", ace);
if (htmlEditPane != null) {
LOGGER.info("Using " + LangUtil.getSimpleClassName(htmlEditPane)
+ " as HTML editor.");
return htmlEditPane;
}
//
// // use editor based on SimplyHTML
// htmlEditPane = new HTMLEditPaneSimplyHTML();
return htmlEditPane;
}
public static String openHTMLEditorsKey(List<File> htmlFiles) {
String key = "";
for (File f : htmlFiles) {
key += f;
}
return key;
}
/**
* This method should only be called by the {@link DialogManager}. All
* program points, where a HTML editor should be opened must should use the
* {@link DialogManager}.
*
* @param owner
* @param ace
* @param htmlFiles
* A {@link List} of {@link File}s that all will automatically be
* created if they don't exist! No matter if the user saves his
* changes.
* @param tabTitles
* @param windowTitle
* @param htmlListener
*/
public static Window openHTMLEditors(Component owner,
AtlasConfigEditable ace, List<File> htmlFiles,
List<String> tabTitles, String windowTitle,
PropertyChangeListener htmlListener) {
if (tabTitles.size() != htmlFiles.size())
throw new IllegalArgumentException(
"Number of HTML URLs and Titles must be equal.");
/**
* We open the HTML editor to edit the About information.
*/
final HTMLEditPaneInterface htmlEditor = createHTMLEditPane(ace);
if (htmlListener != null)
htmlEditor.addChangeListener(htmlListener);
JComponent htmlEditorPanel = htmlEditor.getComponent();
// JHTMLEditor has problems when not running in frame!!
// So we have to use JFrame for all implementations of
// HTMLEditPaneInterface.
// final JDialog editorDialog = new JDialog(SwingUtil
// .getParentWindow(owner), windowTitle);
final JFrame editorFrame = new JFrame(windowTitle);
// editorDialog.setModal(true);
// TODO: Stefan muss hier Frame-Caching einbauen, damit
// fuer eine Map nicht 2x ein Editor geƶffnet wird!
editorFrame
.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
editorFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
if (htmlEditor.performClosing(editorFrame))
editorFrame.dispose();
}
});
htmlEditorPanel.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("closing")) {
editorFrame.dispose();
}
}
});
Dimension size = htmlEditor.getPreferredSize();
if (size == null)
size = new Dimension(620, 400);
editorFrame.setSize(size);
if (!htmlEditor.hasScrollPane()) {
htmlEditorPanel = new JScrollPane(htmlEditorPanel);
}
editorFrame.getContentPane().add(htmlEditorPanel);
// String content = "<html> <body> <p> test </p> </body> </html>";
// htmlEditorPanel.setCurrentDocumentContent(content
htmlEditor.removeAllTabs();
/**
* Add one Tab for every language that is supported
*/
for (int i = 0; i < ace.getLanguages().size(); i++) {
try {
File htmlFile = htmlFiles.get(i);
if (!htmlFile.exists())
htmlFile.createNewFile();
// Sad but true, we have to use the depreciated way here
// URL htmlURL = htmlFile.toURL();
URL htmlURL = IOUtil.fileToURL(htmlFile);
LOGGER.info(htmlEditor.getClass().getSimpleName() + " for "
+ htmlURL + " (was file = "
+ htmlFile.getCanonicalPath() + ")");
htmlEditor.addEditorTab(tabTitles.get(i), htmlURL, i);
} catch (Exception ex) {
ExceptionDialog.show(owner, ex);
}
}
SwingUtil.centerFrameOnScreenRandom(editorFrame);
editorFrame.setVisible(true);
// // Because we can not use JDialog anymore, we "fake"
// // the modal property
// while ( editorDialog.isVisible() ) {
// LangUtil.sleepExceptionless(50);
// }
return editorFrame;
}
/**
* Finds all "img" occurrences with absolute file references in a html
* content and extracts the file information.
*
* @param htmlContent
* html content
* @return a map with the strings to replace as key and the corresponding
* file references as value
*/
public static java.util.Map<String, File> findFileReferencesToReplace(
String htmlContent) {
final java.util.Map<String, File> map = new HashMap<String, File>();
if (htmlContent == null)
return map;
// find all "img" occurrences in html
Pattern pattern = Pattern
.compile("<[iI][mM][gG].*?src=['\"](.*?)['\"].*?>");
Matcher matcher = pattern.matcher(htmlContent);
while (matcher.find()) {
try {
String fileURL = matcher.group(1);
File file = IOUtil.urlToFile(new URL(fileURL));
if (fileURL != null && file != null)
map.put(fileURL, file);
} catch (MalformedURLException err) {
// given image URL is not an absolute URL,
// so ignore this exception because the given URL
// already is a relative URL
}
}
return map;
}
/**
* Performs a file choose.
*
* @param parent
* component for the dialog (can be {@code null})
* @param startFolder
* start folder for the chooser (if {@code null} "/" is used)
* @param filter
* defines which files can be selected
* @return {@code null} if the dialog was not approved
*/
public static File chooseFileFallback(Component parent, File startFolder,
FileExtensionFilter filter) {
if (startFolder == null)
startFolder = new File("/");
JFileChooser chooser = new JFileChooser(startFolder);
if (filter != null) {
chooser.setAcceptAllFileFilterUsed(false);
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
chooser.setFileFilter(filter.toJFileChooserFilter());
}
int ret = chooser.showOpenDialog(parent);
if (ret == JFileChooser.APPROVE_OPTION)
return chooser.getSelectedFile();
return null;
}
/**
* Performs a file choose using the Native OSdialog via SWT
*
* @param parent
* component for the dialog (can be {@code null})
* @param startFolder
* start folder for the chooser (if {@code null} "/" is used)
* @param filter
* defines which files can be selected
* @return {@code null} if the dialog was not approved
*/
public static File chooseImageFile(Component parent, File startFolder,
FileExtensionFilter filter, String title) {
try {
JFileDialog fileDialog = new JFileDialog();
// fileDialog.setTitle(GpSwingUtil.R("CreateAtlas.Dialog.Title"));
fileDialog.setParentDirectory(startFolder.getAbsolutePath());
fileDialog.setDialogType(DialogType.OPEN_DIALOG_TYPE);
fileDialog.setExtensionFilters(
new String[] { filter.toNativeFileFilter()[0] },
new String[] { filter.toNativeFileFilter()[1] }, 0);
fileDialog.show(parent);
fileDialog.setTitle(title);
String selectedFileName = fileDialog.getSelectedFileName();
if (selectedFileName == null)
return null;
return new File(fileDialog.getParentDirectory(), selectedFileName);
} catch (Exception e) {
return chooseFileFallback(parent, startFolder, filter);
}
}
/**
* Copies a file to a relative path.
*
* @param parent
* parent component for info dialogs (if <code>null</code> no
* dialogs will be shown!)
* @param source
* source file
* @param basePath
* base path for the destination folder
* @param relDir
* directory (!) relative to {@code basePath} the file will be
* copied to
* @return the relative path (including the filename) in case of success
* (also when the copy was not necessary, because source and
* destination files are equal!); {@code null} if copy could not be
* processed.
*/
public static String copyFileToRelativeFolder(Component parent,
File source, File basePath, String relDir) {
// relative path should not start with "/"
if (relDir.length() > 1 && relDir.startsWith("/"))
relDir.substring(1);
// path should end with "/" to concat the filename
// to directory
if (!relDir.endsWith("/"))
relDir += "/";
String fileNameCleaned = IOUtil.cleanFilename(source.getName());
String relFilePath = relDir + fileNameCleaned;
File destFile = new File(basePath, relFilePath);
// if source file is equal to destination file
// do nothing, just return the relative path
if (destFile.equals(source))
return relFilePath;
try {
destFile.getParentFile().mkdirs();
// TODO Ask to overwrite one day
IOUtil.copyFile(null, source, destFile, true);
if (parent != null)
JOptionPane.showMessageDialog(parent, fileNameCleaned
+ " copied to map image folder", "File copied", // i8n
JOptionPane.INFORMATION_MESSAGE);
return relFilePath;
} catch (IOException err) {
if (parent != null)
ExceptionDialog.show(parent, err, "Error coping file",
fileNameCleaned + " could not be copied!");
else
LOGGER.error("Error coping file", err);
return null;
}
}
}