label.420=Ignore the first node of segment 'trkseg'
label.430=Also make the generated GPX file (the one whose filename ends with '_.gpx') as the target of conversion
+tab.restamp.400=4. Perform RESTAMP
+
tab.500=4. perform EXIF conversion
label.500=Select whether to perform EXIF conversion
label.501=When performing EXIF conversion, you also need to specify the folder to output the converted file.
label.560=\u30bd\u30fc\u30b9GPX\u306e<MAGVAR>\u3092\u7121\u8996\u3059\u308b
label.570=\u51fa\u529bGPX\u306b<SPEED>\u3092\u4e0a\u66f8\u304d\u3059\u308b
+tab.restamp.400=4. \u5909\u63db\u306e\u5b9f\u884c
+
msg.100=GPX\u30d5\u30a1\u30a4\u30eb\u307e\u305f\u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u304c\u5b58\u5728\u3057\u307e\u305b\u3093\u3002('%s')
msg.110=\u5bfe\u8c61\u3068\u306a\u308bGPX\u30d5\u30a1\u30a4\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093('%s')
msg.120=\u8907\u6570\u306eGPX\u30d5\u30a1\u30a4\u30eb\u304c\u3042\u308b\u3068\u304d\u306b\u306f\u3001'IMG.OUTPUT_ALL'\u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093\u3002
* @author yuu\r
*/\r
public class Restamp extends Thread {\r
+ static public final String TIME_PATTERN = "yyyy-MM-dd HH:mm:ss z";\r
+\r
/**\r
* 実行中に発生したExceptionを保持する場所\r
*/\r
* @param argv\r
* argv[0] = 画像ファイルが格納されているディレクトリ --> imgDir\r
* argv[1] = 時刻補正の基準とする画像ファイル --> baseFile\r
- * argv[2] = 基準画像ファイルの精確な撮影日時 "yyyy-MM-dd_HH:mm:ss" --> baseTime\r
+ * argv[2] = 基準画像ファイルの精確な撮影日時 "yyyy-MM-dd HH:mm:ss z" --> baseTime\r
* argv[3] = 時刻補正の基準とする画像ファイル --> baseFile\r
- * argv[4] = 基準画像ファイルの精確な撮影日時 "yyyy-MM-dd_HH:mm:ss" --> baseTime\r
+ * argv[4] = 基準画像ファイルの精確な撮影日時 "yyyy-MM-dd HH:mm:ss z" --> baseTime\r
* \r
* @throws IOException\r
* @throws ImageReadException \r
return;\r
}\r
\r
- DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'_'HH:mm:ss");\r
+ DateFormat df1 = new SimpleDateFormat(TIME_PATTERN);\r
Date baseTime1 = df1.parse(argv[2]);\r
\r
File baseFile2 = new File(imgDir, argv[3]);\r
return;\r
}\r
\r
- DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd'_'HH:mm:ss");\r
+ DateFormat df2 = new SimpleDateFormat(TIME_PATTERN);\r
Date baseTime2 = df2.parse(argv[4]);\r
\r
Restamp obj = new Restamp();\r
// 3.GPXファイル設定画面
cardNo++;
{
+ // 3. GPXファイルを選択
Card card = new Card(cardPanel, i18n.getString("tab.400"), 2, 4);
cardPanel.addTab(card.getTitle(), card);
cards[cardNo] = card;
e.printStackTrace();
}
- (new DoDialog(this, argv)).setVisible(true);
+ (new DoDialog(argv)).setVisible(true);
doButton.setEnabled(true);
}
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
-class Command extends Thread {
+public class Command extends Thread {
String[] args; // コマンドパラメータ
private String commandName = ""; // コマンド名
@SuppressWarnings({ "rawtypes" })
String[] args;
//{{DECLARE_CONTROLS
- JFrame parentFrame; // MatchTime.class
JPanel buttonPanel; // ボタン配置パネル (下部)
JButton closeButton; // [クローズ]ボタン
JButton doButton; // [実行]ボタン
//}}
@SuppressWarnings("OverridableMethodCallInConstructor")
- public DoDialog(JFrame parentFrame, String[] args) {
- super(parentFrame, true); // モーダルダイアログを基盤にする
- this.parentFrame = parentFrame;
+ public DoDialog(String[] args) {
+ super(); // モーダルダイアログを基盤にする
this.args = args;
// INIT_CONTROLS
@SuppressWarnings("OverridableMethodCallInConstructor")
Container container = getContentPane();
container.setLayout(new BorderLayout());
- parentFrame.setVisible(false);
+ //parentFrame.setVisible(false);
setSize(getInsets().left + getInsets().right + 980, getInsets().top + getInsets().bottom + 480);
setTitle(DoDialog.TITLE);
}
// JFrameの表示
- parentFrame.setVisible(true);
+ //parentFrame.setVisible(true);
}
/**
super(label, text);
// "選択..."
- openButton = new JButton(
- i18n.getString("button.select"),
- AdjustTime.createImageIcon("images/Open16.gif")
- );
+ openButton = new JButton(i18n.getString("button.select"), AdjustTime.createImageIcon("images/Open16.gif"));
openButton.addActionListener(this);
this.add(openButton);
}
- public void setEnable(boolean f) {
- super.setEnabled(f);
- openButton.setEnabled(f);
- }
-
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == openButton){
}
}
+ public File getGpxFile() {
+ if (isEnable()) {
+ return new File(getText());
+ }
+ return null;
+ }
+
/**
* このフィールドに有効な値が設定されているかどうか
* @return
*/
@Override
public boolean isEnable() {
- throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ String text = this.argField.getText();
+ if (text != null) {
+ File file = new File(text);
+ if (file.exists()) {
+ if (file.isFile()) {
+ String name = file.getName().toUpperCase();
+ if (name.endsWith(".GPX")) {
+ return true;
+ }
+ }
+ else if (file.isDirectory()) {
+ return true;
+ }
+ }
+ }
+ return false;
}
}
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JButton;
+import osm.jp.gpx.Restamp;
import osm.jp.gpx.matchtime.gui.restamp.DialogCorectTime;
/**
* この1インスタンスで、1パラメータをあらわす。
*/
public class ParameterPanelTime extends ParameterPanel {
- static final String TIME_PATTERN = "yyyy.MM.dd HH:mm:ss z";
SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateTimeInstance();
ParameterPanelImageFile imageFile;
public JButton updateButton;
if (param.imageFile.isEnable()) {
File file = param.imageFile.getImageFile();
long lastModified = file.lastModified();
- sdf.applyPattern(TIME_PATTERN);
+ sdf.applyPattern(Restamp.TIME_PATTERN);
param.argField.setText(sdf.format(new Date(lastModified)));
}
else {
String text = this.argField.getText();
if (text != null) {
try {
- sdf.applyPattern(TIME_PATTERN);
+ sdf.applyPattern(Restamp.TIME_PATTERN);
sdf.parse(text);
return true;
}
--- /dev/null
+package osm.jp.gpx.matchtime.gui.restamp;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import javax.swing.BoxLayout;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import osm.jp.gpx.matchtime.gui.AdjustTime;
+import static osm.jp.gpx.matchtime.gui.AdjustTime.i18n;
+import osm.jp.gpx.matchtime.gui.Card;
+import osm.jp.gpx.matchtime.gui.PanelAction;
+import osm.jp.gpx.matchtime.gui.ParameterPanelGpx;
+
+/**
+ * [GPXファイル]選択パネル
+ * @author yuu
+ */
+public class CardGpxFile extends Card implements PanelAction {
+ //JPanel argsPanel; // パラメータ設定パネル (上部)
+ ParameterPanelGpx arg_gpxFile;
+ JCheckBox noFirstNode; // GPX: <trkseg>セグメントの最初の1ノードは無視する。 {ON | OFF}
+ JCheckBox gpxReuse; // 生成されたGPXファイル(ファイル名が'_.gpx'で終わるもの)も対象にする。 {ON | OFF}
+ private final boolean gpxReuseV;
+
+ /**
+ * コンストラクタ
+ * @param tabbe parent panel
+ * @param arg_gpxFile // 開始画像の基準時刻:
+ * @param noFirstNodeV
+ * @param gpxReuseV
+ */
+ public CardGpxFile(
+ JTabbedPane tabbe,
+ ParameterPanelGpx arg_gpxFile,
+ boolean noFirstNodeV,
+ boolean gpxReuseV
+ ) {
+ super(tabbe, AdjustTime.i18n.getString("tab.400"), 2, 4);
+ this.arg_gpxFile = arg_gpxFile;
+
+ JPanel argsPanel = new JPanel();
+ argsPanel.setLayout(new BoxLayout(argsPanel, BoxLayout.PAGE_AXIS));
+ argsPanel.add(packLine(new JLabel(i18n.getString("label.400")), new JPanel()));
+ argsPanel.add(arg_gpxFile);
+
+ // "セグメント'trkseg'の最初の1ノードは無視する。"
+ noFirstNode = new JCheckBox(
+ i18n.getString("label.420"),
+ noFirstNodeV
+ );
+ argsPanel.add(noFirstNode);
+
+ // "生成されたGPXファイル(ファイル名が'_.gpx'で終わるもの)も変換の対象にする"
+ gpxReuse = new JCheckBox(i18n.getString("label.430"), gpxReuseV);
+ gpxReuse.setEnabled(true);
+ argsPanel.add(gpxReuse);
+
+ JPanel space = new JPanel();
+ space.setMinimumSize(new Dimension(40, 20));
+ space.setMaximumSize(new Dimension(40, Short.MAX_VALUE));
+ argsPanel.add(space);
+
+ this.mainPanel.add(argsPanel, BorderLayout.CENTER);
+ this.gpxReuseV = gpxReuseV;
+ }
+
+ /**
+ * "セグメント'trkseg'の最初の1ノードは無視する。"
+ * @return
+ */
+ public boolean getNoFirstNode() {
+ return noFirstNode.isSelected();
+ }
+
+ /**
+ * 入力条件が満たされているかどうか
+ * @return
+ */
+ @Override
+ public boolean isEnable() {
+ return (arg_gpxFile.isEnable());
+ }
+
+ @Override
+ @SuppressWarnings("empty-statement")
+ public void openAction() {
+ ; // 何もしない
+ }
+}
--- /dev/null
+package osm.jp.gpx.matchtime.gui.restamp;
+
+import java.awt.BorderLayout;
+import java.awt.Dialog;
+import java.io.File;
+import java.util.ArrayList;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import osm.jp.gpx.matchtime.gui.AdjustTime;
+import static osm.jp.gpx.matchtime.gui.AdjustTime.i18n;
+import osm.jp.gpx.matchtime.gui.Card;
+import osm.jp.gpx.matchtime.gui.DoDialog;
+import osm.jp.gpx.matchtime.gui.PanelAction;
+import osm.jp.gpx.matchtime.gui.ParameterPanelImageFile;
+import osm.jp.gpx.matchtime.gui.ParameterPanelTime;
+
+/**
+ * [基準画像(開始/終了)]選択パネル
+ * @author yuu
+ */
+public class CardPerformFile extends Card implements PanelAction {
+ //JPanel argsPanel; // パラメータ設定パネル (上部)
+ ParameterPanelTime arg1_basetime;
+ ParameterPanelTime arg2_basetime;
+ JButton doButton; // [処理実行]ボタン
+
+ /**
+ * コンストラクタ
+ * @param tabbe parent panel
+ * @param arg1_basetime // 開始画像の基準時刻:
+ * @param arg2_basetime // 開始画像の基準時刻:
+ */
+ public CardPerformFile(
+ JTabbedPane tabbe,
+ ParameterPanelTime arg1_basetime,
+ ParameterPanelTime arg2_basetime
+ ) {
+ super(tabbe, AdjustTime.i18n.getString("tab.restamp.400"), 2, 4);
+ this.arg1_basetime = arg1_basetime;
+ this.arg2_basetime = arg2_basetime;
+
+ JPanel argsPanel = new JPanel();
+ argsPanel.setLayout(new BoxLayout(argsPanel, BoxLayout.PAGE_AXIS));
+ argsPanel.add(packLine(new JLabel(i18n.getString("label.200")), new JPanel()));
+
+ // [処理実行]ボタン
+ doButton = new JButton(
+ i18n.getString("button.execute"),
+ AdjustTime.createImageIcon("images/media_playback_start.png")
+ );
+ argsPanel.add(doButton);
+
+ this.mainPanel.add(argsPanel, BorderLayout.CENTER);
+
+ //{{REGISTER_LISTENERS
+ SymAction lSymAction = new SymAction();
+ doButton.addActionListener(lSymAction);
+ //}}
+ }
+
+ class SymAction implements java.awt.event.ActionListener {
+ @Override
+ public void actionPerformed(java.awt.event.ActionEvent event) {
+ Object object = event.getSource();
+ if (object == doButton) {
+ doButton_Action(event);
+ }
+ }
+ }
+
+ /**
+ * [実行]ボタンをクリックしたときの動作
+ * @param event
+ */
+ @SuppressWarnings("UseSpecificCatch")
+ void doButton_Action(java.awt.event.ActionEvent event) {
+ doButton.setEnabled(false);
+
+ ArrayList<String> arry = new ArrayList<>();
+ File file = arg1_basetime.getImageFile().getImageFile();
+ File dir = file.getParentFile();
+ arry.add(dir.getAbsolutePath());
+ arry.add(file.getName());
+ arry.add(arg1_basetime.argField.getText());
+ file = arg2_basetime.getImageFile().getImageFile();
+ arry.add(file.getName());
+ arry.add(arg2_basetime.argField.getText());
+ String[] argv = arry.toArray(new String[arry.size()]);
+ (new DoRestamp(argv)).setVisible(true);
+
+ doButton.setEnabled(true);
+ }
+
+ /**
+ * 入力条件が満たされているかどうか
+ * @return
+ */
+ @Override
+ public boolean isEnable() {
+ return (arg1_basetime.isEnable() && arg2_basetime.isEnable());
+ }
+
+ @Override
+ @SuppressWarnings("empty-statement")
+ public void openAction() {
+ ; // 何もしない
+ }
+}
--- /dev/null
+package osm.jp.gpx.matchtime.gui.restamp;
+import osm.jp.gpx.matchtime.gui.Command;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.io.*;
+import javax.swing.*;
+
+/**
+ * 処理
+ */
+@SuppressWarnings("serial")
+public class DoRestamp extends JDialog {
+ public static final String TITLE = "Do Command";
+
+ // Used for addNotify check.
+ boolean fComponentsAdjusted = false;
+ String[] args;
+
+ //{{DECLARE_CONTROLS
+ JPanel buttonPanel; // ボタン配置パネル (下部)
+ JButton closeButton; // [クローズ]ボタン
+ JButton doButton; // [実行]ボタン
+ JTextArea textArea; // 実行結果を表示するJTextArea (中央)
+ //}}
+
+ @SuppressWarnings("OverridableMethodCallInConstructor")
+ public DoRestamp(String[] args) {
+ super(); // モーダルダイアログを基盤にする
+ this.args = args;
+
+ // INIT_CONTROLS
+ @SuppressWarnings("OverridableMethodCallInConstructor")
+ Container container = getContentPane();
+ container.setLayout(new BorderLayout());
+ //parentFrame.setVisible(false);
+ setSize(getInsets().left + getInsets().right + 980, getInsets().top + getInsets().bottom + 480);
+ setTitle(DoRestamp.TITLE);
+
+ // コントロールパネル
+ buttonPanel = new JPanel();
+
+ doButton = new JButton("実行");
+ doButton.setToolTipText("処理を実行します.");
+ doButton.setEnabled(true);
+ doButton.addActionListener((ActionEvent event) -> {
+ // 処理中であることを示すため
+ // ボタンの文字列を変更し,使用不可にする
+ doButton.setText("処理中...");
+ doButton.setEnabled(false);
+
+ // SwingWorker を生成し,実行する
+ LongTaskWorker worker = new LongTaskWorker(doButton);
+ worker.execute();
+ });
+ buttonPanel.add(doButton);
+
+ closeButton = new JButton("閉じる");
+ closeButton.setToolTipText("処理を終了します.");
+ closeButton.addActionListener((ActionEvent event) -> {
+ dispose();
+ });
+ buttonPanel.add(closeButton);
+
+ this.getContentPane().add("South", buttonPanel);
+
+ // 説明文
+ textArea = new JTextArea();
+ JScrollPane sc=new JScrollPane(textArea);
+ textArea.setFont(new Font(Font.MONOSPACED,Font.PLAIN,12));
+ textArea.setTabSize(4);
+ this.getContentPane().add("Center", sc);
+
+ try {
+ textArea.append("> java -cp import.jar osm.jp.gpx.Restamp");
+ for (String arg : args) {
+ textArea.append(" '" + arg + "'");
+ }
+ textArea.append("\n\n");
+ }
+ catch (Exception e) {
+ System.out.println(e.toString());
+ }
+
+ // JFrameの表示
+ //parentFrame.setVisible(true);
+ }
+
+ /**
+ * Shows or hides the component depending on the boolean flag b.
+ * @param b trueのときコンポーネントを表示; その他のとき, componentを隠す.
+ * @see java.awt.Component#isVisible
+ */
+ @Override
+ public void setVisible(boolean b) {
+ if(b) {
+ setLocation(80, 80);
+ }
+ super.setVisible(b);
+ }
+
+ @Override
+ public void addNotify() {
+ // Record the size of the window prior to calling parents addNotify.
+ Dimension d = getSize();
+
+ super.addNotify();
+
+ if (fComponentsAdjusted) {
+ return;
+ }
+
+ // Adjust components according to the insets
+ setSize(getInsets().left + getInsets().right + d.width, getInsets().top + getInsets().bottom + d.height);
+ Component components[] = getComponents();
+ for (Component component : components) {
+ Point p = component.getLocation();
+ p.translate(getInsets().left, getInsets().top);
+ component.setLocation(p);
+ }
+ fComponentsAdjusted = true;
+ }
+
+
+ /**
+ * JTextAreaに書き出すOutputStream
+ */
+ public static class JTextAreaOutputStream extends OutputStream {
+ private final ByteArrayOutputStream os;
+
+ /** 書き出し対象 */
+ private final JTextArea textArea;
+ private final String encode;
+
+ public JTextAreaOutputStream(JTextArea textArea, String encode) {
+ this.textArea = textArea;
+ this.encode = encode;
+ this.os = new ByteArrayOutputStream();
+ }
+
+ /**
+ * OutputStream#write(byte[])のオーバーライド
+ * @param arg
+ * @throws java.io.IOException
+ */
+ @Override
+ public void write(int arg) throws IOException {
+ this.os.write(arg);
+ }
+
+ /**
+ * flush()でJTextAreaに書き出す
+ * @throws java.io.IOException
+ */
+ @Override
+ public void flush() throws IOException {
+ // 文字列のエンコード
+ final String str = new String(this.os.toByteArray(), this.encode);
+ // 実際の書き出し処理
+ SwingUtilities.invokeLater(
+ new Runnable(){
+ @Override
+ public void run() {
+ JTextAreaOutputStream.this.textArea.append(str);
+ }
+ }
+ );
+ // 書き出した内容はクリアする
+ this.os.reset();
+ }
+ }
+
+ // 非同期に行う処理を記述するためのクラス
+ class LongTaskWorker extends SwingWorker<Object, Object> {
+ private final JButton button;
+
+ public LongTaskWorker(JButton button) {
+ this.button = button;
+ }
+
+ // 非同期に行われる処理
+ @Override
+ @SuppressWarnings("SleepWhileInLoop")
+ public Object doInBackground() {
+ // ながーい処理
+ PrintStream defOut = System.out;
+ PrintStream defErr = System.err;
+
+ OutputStream os = new JTextAreaOutputStream(textArea, "UTF-8");
+ PrintStream stdout = new PrintStream(os, true); // 自動flushをtrueにしておく
+
+ // System.out にJTextAreaOutputStreamに書き出すPrintStreamを設定
+ System.setOut(stdout);
+ System.setErr(stdout);
+
+ try {
+ Command command = new Command(osm.jp.gpx.Restamp.class);
+ command.setArgs(args);
+ command.start(); // コマンドを実行
+ while (command.isAlive()) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {}
+ }
+ }
+ catch(Exception e) {
+ e.printStackTrace(stdout);
+ }
+ finally {
+ System.setOut(defOut);
+ System.setErr(defErr);
+ doButton.setEnabled(true);
+ }
+
+ return null;
+ }
+
+ // 非同期処理後に実行
+ @Override
+ protected void done() {
+ // 処理が終了したので,文字列を元に戻し
+ // ボタンを使用可能にする
+ button.setText("実行");
+ button.setEnabled(true);
+ }
+ }
+}
//---------------------------------------------------------------------
params = new AppParameters();
- cards = new Card[3];
+ cards = new Card[4];
cardPanel = new JTabbedPane(JTabbedPane.LEFT);
mainPanel.add(cardPanel, BorderLayout.CENTER);
int cardNo = 0;
cardNo++;
}
+ //---------------------------------------------------------------------
+ // 4. 実行画面
+ {
+ CardPerformFile card = new CardPerformFile(
+ cardPanel,
+ arg2_basetime,
+ arg3_basetime
+ );
+ cardPanel.addTab(card.getTitle(), card);
+ cardPanel.setEnabledAt(cardNo, false);
+ cards[cardNo] = card;
+ cardNo++;
+ }
+
//{{REGISTER_LISTENERS
SymWindow aSymWindow = new SymWindow();
this.addWindowListener(aSymWindow);