/*
* Copyright 2013 Serdar.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.fub.maps.project.datasource.actions;
import de.fub.maps.project.MapsProject;
import de.fub.maps.project.datasource.MapsDatasourceNodeFactory;
import de.fub.maps.project.datasource.service.DataImportService;
import de.fub.maps.project.xml.Maps;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.filechooser.FileFilter;
import javax.xml.bind.JAXBException;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.NotifyDescriptor.InputLine;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionRegistration;
import org.openide.filesystems.FileChooserBuilder;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.ContextAwareAction;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.Lookup.Result;
import org.openide.util.NbBundle.Messages;
import org.openide.util.Utilities;
import org.openide.util.actions.Presenter;
import org.openide.util.lookup.ServiceProvider;
@ActionID(
category = "Project",
id = "de.fub.maps.project.ImportGPX")
@ActionRegistration(
displayName = "#CTL_ImportGPX", lazy = false)
@ActionReference(path = "Projects/org-maps-project/GPXDataSource/Actions", position = 0)
@Messages({"CTL_ImportGPX=Import GPX Data",
"CLT_Import_From_Disk=From Disk...",
"CLT_GPX_File_Import=GPX File Import",
"CLT_File_Filter_Description=GPX Files",
"CLT_Folder_Creator_Title=New Folder Name",
"CLT_Folder_Creator_Message=Please specify a folder name for the to be imported GPX-Files."})
public final class ImportGPXAction extends AbstractAction implements ContextAwareAction, Presenter.Popup {
private static final long serialVersionUID = 1L;
private JMenu contextMenu = new JMenu(Bundle.CTL_ImportGPX(), false);
private transient MapsProject project;
private final Lookup context;
public ImportGPXAction() {
this(Utilities.actionsGlobalContext());
}
public ImportGPXAction(Lookup context) {
assert context != null;
this.context = context;
init();
}
private void init() {
project = context.lookup(MapsProject.class);
contextMenu.setEnabled(project != null);
putValue(Action.NAME, Bundle.CTL_ImportGPX());
FileObject gpxDataSourceFolder;
try {
if (project != null) {
gpxDataSourceFolder = getGPXDataSourceFolder();
if (gpxDataSourceFolder != null) {
for (DataImportService service : getImportServiceProviderClasses()) {
contextMenu.add(new DelegateAction(service, gpxDataSourceFolder));
}
}
}
} catch (JAXBException ex) {
Exceptions.printStackTrace(ex);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
private FileObject getGPXDataSourceFolder() throws JAXBException, IOException {
Maps projectData = project.getProjectData();
FileObject datasourceFolder = null;
if (projectData.getProjectFolders() != null) {
datasourceFolder = project.getProjectDirectory().getFileObject(projectData.getProjectFolders().getFolderPath(MapsDatasourceNodeFactory.DATASOURCE_FILENAME));
}
return datasourceFolder;
}
private ArrayList<DataImportService> getImportServiceProviderClasses() {
ArrayList<DataImportService> list = new ArrayList<DataImportService>();
Result<DataImportService> result = Lookup.getDefault().lookupResult(DataImportService.class);
for (DataImportService service : result.allInstances()) {
list.add(service);
}
return list;
}
@Override
public void actionPerformed(ActionEvent ev) {
// Do nothing
}
private static NotifyDescriptor.InputLine createFolderNameDialog() {
return new NotifyDescriptor.InputLine(
Bundle.CLT_Folder_Creator_Message(),
Bundle.CLT_Folder_Creator_Title(),
NotifyDescriptor.InputLine.OK_CANCEL_OPTION,
NotifyDescriptor.PLAIN_MESSAGE);
}
@Override
public JMenuItem getPopupPresenter() {
return contextMenu;
}
@Override
public Action createContextAwareInstance(Lookup actionContext) {
return new ImportGPXAction(actionContext);
}
private static class DelegateAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private final DataImportService delegate;
private final FileObject dataSourceFileObject;
private DelegateAction(DataImportService delegate, FileObject dataSourceFileObject) {
assert delegate != null;
this.delegate = delegate;
putValue(NAME, delegate.getName());
this.dataSourceFileObject = dataSourceFileObject;
}
@Override
public void actionPerformed(ActionEvent e) {
try {
DataImportService service = this.delegate.getClass().newInstance();
service.setDestinationFolder(dataSourceFileObject);
service.actionPerformed(e);
} catch (InstantiationException ex) {
Exceptions.printStackTrace(ex);
} catch (IllegalAccessException ex) {
Exceptions.printStackTrace(ex);
}
}
}
@ServiceProvider(service = DataImportService.class)
public static class ImportFormDiskAction implements DataImportService {
private FileObject gpxDataSourceFolder;
public ImportFormDiskAction() {
}
@Messages({"CLT_Copy_Files_Start_Message=Copying Files",
"# {0} - fileName",
"CLT_Copy_File_Message=Copying File {0}"})
@Override
public void actionPerformed(ActionEvent e) {
boolean repeat = true;
NotifyDescriptor.InputLine nd = createFolderNameDialog();
// repeat procedure as long repeat equals true.
while (repeat) {
Object notify = DialogDisplayer.getDefault().notify(nd);
if (NotifyDescriptor.OK_OPTION.equals(notify)) {
try {
if (gpxDataSourceFolder != null) {
final String folderName = nd.getInputText();
FileObject gpxFolderFileObject = gpxDataSourceFolder.getFileObject(folderName);
// check if folfer name already exists.
if (gpxFolderFileObject == null) {
gpxFolderFileObject = gpxDataSourceFolder.createFolder(folderName);
JFileChooser fileChooser = createGPXFileChooser();
int result = fileChooser.showOpenDialog(null);
if (JFileChooser.APPROVE_OPTION == result && fileChooser.getSelectedFiles().length > 0) {
// start copy/import procedure.
copyProcedure(fileChooser.getSelectedFiles(), gpxFolderFileObject);
}
// doesn't matter what the user selects. either way the
// import process finished.
repeat = false;
} else {
// create error message, because there already is a folder with the
// specified name. repeat process.
nd = createErrorDialog(folderName);
}
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
repeat = false;
}
} else {
// user aborted import process.
repeat = false;
}
}
}
private JFileChooser createGPXFileChooser() {
JFileChooser fileChooser = new FileChooserBuilder(ImportGPXAction.class).setTitle(Bundle.CLT_GPX_File_Import()).addFileFilter(new GPXFileFilter()).createFileChooser();
fileChooser.setMultiSelectionEnabled(true);
return fileChooser;
}
@Messages({"# {0} - folderName",
"CLT_Folder_Creator_Error_Message=Folder {0} exists already!"})
private NotifyDescriptor.InputLine createErrorDialog(String folderName) {
InputLine notifyDescriptor = createFolderNameDialog();
notifyDescriptor.setInputText(folderName);
notifyDescriptor.setMessageType(InputLine.ERROR_MESSAGE);
notifyDescriptor.setMessage(Bundle.CLT_Folder_Creator_Error_Message(folderName));
return notifyDescriptor;
}
private void copyProcedure(File[] selectedFiles, FileObject gpxFolderFileObject) throws IOException {
ProgressHandle handler = ProgressHandleFactory.createHandle(Bundle.CLT_Copy_Files_Start_Message());
try {
handler.switchToDeterminate(selectedFiles.length);
int i = 0;
for (File file : selectedFiles) {
FileObject sourceFile = FileUtil.toFileObject(file);
if (sourceFile != null) {
handler.setDisplayName(Bundle.CLT_Copy_File_Message(sourceFile.getNameExt()));
FileUtil.copyFile(sourceFile, gpxFolderFileObject, sourceFile.getName());
}
handler.progress(++i);
}
} finally {
handler.finish();
}
}
@Override
public void setDestinationFolder(FileObject destinationFoldert) {
this.gpxDataSourceFolder = destinationFoldert;
}
@Override
public String getName() {
return Bundle.CLT_Import_From_Disk();
}
private static class GPXFileFilter extends FileFilter {
public GPXFileFilter() {
}
@Override
public boolean accept(File f) {
FileObject fileObject = FileUtil.toFileObject(f);
return fileObject != null && "gpx".equalsIgnoreCase(fileObject.getExt());
}
@Override
public String getDescription() {
return Bundle.CLT_File_Filter_Description();
}
}
}
}