X-Git-Url: https://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Fsave%2FExifSaver.java;h=bc8d220c41ac7559f7695e107272bd04b71f49a1;hb=140e9d165f85c3d4f0435a311e091209313faa2a;hp=1e597201d5f2842197531159ec3452f542fb428c;hpb=5625a1abadb5f2ca5f017fe7dbda1d5141cb637b;p=GpsPrune.git diff --git a/tim/prune/save/ExifSaver.java b/tim/prune/save/ExifSaver.java index 1e59720..bc8d220 100644 --- a/tim/prune/save/ExifSaver.java +++ b/tim/prune/save/ExifSaver.java @@ -8,6 +8,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; +import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -21,12 +22,13 @@ import javax.swing.JTable; import tim.prune.ExternalTools; import tim.prune.I18nManager; +import tim.prune.UpdateMessageBroker; +import tim.prune.config.Config; import tim.prune.data.Altitude; import tim.prune.data.Coordinate; import tim.prune.data.DataPoint; import tim.prune.data.Photo; import tim.prune.data.PhotoList; -import tim.prune.data.PhotoStatus; /** * Class to call Exiftool to save coordinate information in jpg files @@ -35,9 +37,12 @@ public class ExifSaver implements Runnable { private Frame _parentFrame = null; private JDialog _dialog = null; + private JButton _okButton = null; private JCheckBox _overwriteCheckbox = null; + private JCheckBox _forceCheckbox = null; private JProgressBar _progressBar = null; private PhotoTableModel _photoTableModel = null; + private boolean _saveCancelled = false; // To preserve timestamps of file use parameter -P @@ -72,11 +77,12 @@ public class ExifSaver implements Runnable * Save exif information to all photos in the list * whose coordinate information has changed since loading * @param inPhotoList list of photos to save + * @return true if saved */ public boolean saveExifInformation(PhotoList inPhotoList) { // Check if external exif tool can be called - boolean exifToolInstalled = ExternalTools.isExiftoolInstalled(); + boolean exifToolInstalled = ExternalTools.isToolInstalled(ExternalTools.TOOL_EXIFTOOL); if (!exifToolInstalled) { // show warning @@ -111,7 +117,7 @@ public class ExifSaver implements Runnable _dialog.pack(); // set progress bar and show dialog _progressBar.setVisible(false); - _dialog.show(); + _dialog.setVisible(true); return true; } @@ -124,7 +130,10 @@ public class ExifSaver implements Runnable { JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); - panel.add(new JLabel(I18nManager.getText("dialog.saveexif.intro")), BorderLayout.NORTH); + // Label at top + JLabel topLabel = new JLabel(I18nManager.getText("dialog.saveexif.intro")); + topLabel.setBorder(BorderFactory.createEmptyBorder(8, 6, 5, 6)); + panel.add(topLabel, BorderLayout.NORTH); // centre panel with most controls JPanel centrePanel = new JPanel(); centrePanel.setLayout(new BorderLayout()); @@ -135,9 +144,16 @@ public class ExifSaver implements Runnable JScrollPane scrollPane = new JScrollPane(photoTable); scrollPane.setPreferredSize(new Dimension(300, 160)); tablePanel.add(scrollPane, BorderLayout.CENTER); + // Pair of checkboxes + JPanel checkPanel = new JPanel(); + checkPanel.setLayout(new BoxLayout(checkPanel, BoxLayout.Y_AXIS)); _overwriteCheckbox = new JCheckBox(I18nManager.getText("dialog.saveexif.overwrite")); _overwriteCheckbox.setSelected(false); - tablePanel.add(_overwriteCheckbox, BorderLayout.SOUTH); + checkPanel.add(_overwriteCheckbox); + _forceCheckbox = new JCheckBox(I18nManager.getText("dialog.saveexif.force")); + _forceCheckbox.setSelected(false); + checkPanel.add(_forceCheckbox); + tablePanel.add(checkPanel, BorderLayout.SOUTH); centrePanel.add(tablePanel, BorderLayout.CENTER); // progress bar below main controls _progressBar = new JProgressBar(0, 100); @@ -166,19 +182,22 @@ public class ExifSaver implements Runnable // Lower panel with ok and cancel buttons JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT)); - JButton okButton = new JButton(I18nManager.getText("button.ok")); - okButton.addActionListener(new ActionListener() { + _okButton = new JButton(I18nManager.getText("button.ok")); + _okButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { + // disable ok button + _okButton.setEnabled(false); // start new thread to do save new Thread(ExifSaver.this).start(); } }); - buttonPanel.add(okButton); + buttonPanel.add(_okButton); JButton cancelButton = new JButton(I18nManager.getText("button.cancel")); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { + _saveCancelled = true; _dialog.dispose(); } }); @@ -208,6 +227,7 @@ public class ExifSaver implements Runnable */ public void run() { + _saveCancelled = false; PhotoTableEntry entry = null; Photo photo = null; int numPhotos = _photoTableModel.getRowCount(); @@ -215,32 +235,53 @@ public class ExifSaver implements Runnable _progressBar.setValue(0); _progressBar.setVisible(true); boolean overwriteFlag = _overwriteCheckbox.isSelected(); - int numSaved = 0; + int numSaved = 0, numFailed = 0, numForced = 0; // Loop over all photos in list for (int i=0; i 0) + { + JOptionPane.showMessageDialog(_parentFrame, + I18nManager.getText("error.saveexif.failed1") + " " + numFailed + " " + + I18nManager.getText("error.saveexif.failed2"), + I18nManager.getText("dialog.saveexif.title"), JOptionPane.ERROR_MESSAGE); + } + if (numForced > 0) + { + JOptionPane.showMessageDialog(_parentFrame, + I18nManager.getText("error.saveexif.forced1") + " " + numForced + " " + + I18nManager.getText("error.saveexif.forced2"), + I18nManager.getText("dialog.saveexif.title"), JOptionPane.WARNING_MESSAGE); + } // close dialog, all finished _dialog.dispose(); } @@ -250,9 +291,10 @@ public class ExifSaver implements Runnable * Save the details for the given photo * @param inPhoto Photo object * @param inOverwriteFlag true to overwrite file, false otherwise + * @param inForceFlag true to force write, ignoring minor errors * @return true if details saved ok */ - private boolean savePhoto(Photo inPhoto, boolean inOverwriteFlag) + private boolean savePhoto(Photo inPhoto, boolean inOverwriteFlag, boolean inForceFlag) { // Check whether photo file still exists if (!inPhoto.getFile().exists()) @@ -284,7 +326,7 @@ public class ExifSaver implements Runnable } } String[] command = null; - if (inPhoto.getCurrentStatus() == PhotoStatus.NOT_CONNECTED) + if (inPhoto.getCurrentStatus() == Photo.Status.NOT_CONNECTED) { // Photo is no longer connected, so delete gps tags command = getDeleteGpsExifTagsCommand(inPhoto.getFile(), inOverwriteFlag); @@ -292,21 +334,27 @@ public class ExifSaver implements Runnable else { // Photo is now connected, so write new gps tags - command = getWriteGpsExifTagsCommand(inPhoto.getFile(), inPhoto.getDataPoint(), inOverwriteFlag); + command = getWriteGpsExifTagsCommand(inPhoto.getFile(), inPhoto.getDataPoint(), inOverwriteFlag, inForceFlag); } // Execute exif command + boolean saved = false; try { - Runtime.getRuntime().exec(command); + Process process = Runtime.getRuntime().exec(command); + // Wait for process to finish so not too many run in parallel + try { + process.waitFor(); + } + catch (InterruptedException ie) {} + saved = (process.exitValue() == 0); } catch (Exception e) { // show error message JOptionPane.showMessageDialog(_parentFrame, "Exception: '" + e.getClass().getName() + "' : " + e.getMessage(), I18nManager.getText("dialog.saveexif.title"), JOptionPane.ERROR_MESSAGE); - return false; } - return true; + return saved; } @@ -320,7 +368,7 @@ public class ExifSaver implements Runnable { // Make a string array to construct the command and its parameters String[] result = new String[inOverwrite?5:4]; - result[0] = "exiftool"; + result[0] = Config.getConfigString(Config.KEY_EXIFTOOL_PATH); result[1] = "-P"; if (inOverwrite) {result[2] = " -overwrite_original_in_place";} // remove all gps tags @@ -336,16 +384,22 @@ public class ExifSaver implements Runnable * @param inFile file to which to write the tags * @param inPoint DataPoint object containing coordinate information * @param inOverwrite true to overwrite file, false to create copy + * @param inForce true to force write, ignoring minor errors * @return external command to write gps tags */ - private static String[] getWriteGpsExifTagsCommand(File inFile, DataPoint inPoint, boolean inOverwrite) + private static String[] getWriteGpsExifTagsCommand(File inFile, DataPoint inPoint, + boolean inOverwrite, boolean inForce) { // Make a string array to construct the command and its parameters - String[] result = new String[inOverwrite?10:9]; - result[0] = "exiftool"; + String[] result = new String[(inOverwrite?10:9) + (inForce?1:0)]; + result[0] = Config.getConfigString(Config.KEY_EXIFTOOL_PATH); result[1] = "-P"; if (inOverwrite) {result[2] = "-overwrite_original_in_place";} int paramOffset = inOverwrite?3:2; + if (inForce) { + result[paramOffset] = "-m"; + paramOffset++; + } // To set latitude : -GPSLatitude='12 34 56.78' -GPSLatitudeRef='N' // (latitude as space-separated deg min sec, reference as either N or S) result[paramOffset] = "-GPSLatitude='" + inPoint.getLatitude().output(Coordinate.FORMAT_DEG_MIN_SEC_WITH_SPACES) @@ -357,7 +411,7 @@ public class ExifSaver implements Runnable result[paramOffset + 3] = "-GPSLongitudeRef=" + inPoint.getLongitude().output(Coordinate.FORMAT_CARDINAL); // add altitude if it has it result[paramOffset + 4] = "-GPSAltitude=" - + (inPoint.hasAltitude()?inPoint.getAltitude().getValue(Altitude.FORMAT_METRES):0); + + (inPoint.hasAltitude()?inPoint.getAltitude().getValue(Altitude.Format.METRES):0); result[paramOffset + 5] = "-GPSAltitudeRef='Above Sea Level'"; // add the filename to modify result[paramOffset + 6] = inFile.getAbsolutePath();