001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.io; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.BorderLayout; 007import java.awt.GridBagLayout; 008import java.awt.event.ActionEvent; 009import java.awt.event.ActionListener; 010import java.awt.event.FocusAdapter; 011import java.awt.event.FocusEvent; 012import java.awt.event.KeyEvent; 013import java.awt.event.KeyListener; 014import java.util.Collections; 015import java.util.LinkedList; 016import java.util.List; 017import java.util.Observable; 018import java.util.Observer; 019 020import javax.swing.Action; 021import javax.swing.BorderFactory; 022import javax.swing.JLabel; 023import javax.swing.JPanel; 024 025import org.openstreetmap.josm.Main; 026import org.openstreetmap.josm.data.osm.Changeset; 027import org.openstreetmap.josm.gui.widgets.HistoryComboBox; 028import org.openstreetmap.josm.tools.CheckParameterUtil; 029import org.openstreetmap.josm.tools.GBC; 030 031/** 032 * BasicUploadSettingsPanel allows to enter the basic parameters required for uploading 033 * data. 034 * 035 */ 036public class BasicUploadSettingsPanel extends JPanel { 037 public static final String HISTORY_KEY = "upload.comment.history"; 038 public static final String HISTORY_LAST_USED_KEY = "upload.comment.last-used"; 039 public static final String SOURCE_HISTORY_KEY = "upload.source.history"; 040 041 /** the history combo box for the upload comment */ 042 private final HistoryComboBox hcbUploadComment = new HistoryComboBox(); 043 private final HistoryComboBox hcbUploadSource = new HistoryComboBox(); 044 /** the panel with a summary of the upload parameters */ 045 private final UploadParameterSummaryPanel pnlUploadParameterSummary = new UploadParameterSummaryPanel(); 046 /** the changeset comment model */ 047 private final ChangesetCommentModel changesetCommentModel; 048 private final ChangesetCommentModel changesetSourceModel; 049 050 protected JPanel buildUploadCommentPanel() { 051 JPanel pnl = new JPanel(); 052 pnl.setLayout(new GridBagLayout()); 053 054 pnl.add(new JLabel(tr("Provide a brief comment for the changes you are uploading:")), GBC.eol().insets(0, 5, 10, 3)); 055 hcbUploadComment.setToolTipText(tr("Enter an upload comment")); 056 hcbUploadComment.setMaxTextLength(Changeset.MAX_COMMENT_LENGTH); 057 List<String> cmtHistory = new LinkedList<String>(Main.pref.getCollection(HISTORY_KEY, new LinkedList<String>())); 058 Collections.reverse(cmtHistory); // we have to reverse the history, because ComboBoxHistory will reverse it again in addElement() 059 hcbUploadComment.setPossibleItems(cmtHistory); 060 final CommentModelListener commentModelListener = new CommentModelListener(hcbUploadComment, changesetCommentModel); 061 hcbUploadComment.getEditor().addActionListener(commentModelListener); 062 hcbUploadComment.getEditor().getEditorComponent().addFocusListener(commentModelListener); 063 pnl.add(hcbUploadComment, GBC.eol().fill(GBC.HORIZONTAL)); 064 065 pnl.add(new JLabel(tr("Specify the data source for the changes:")), GBC.eol().insets(0, 8, 10, 3)); 066 hcbUploadSource.setToolTipText(tr("Enter a source")); 067 List<String> sourceHistory = new LinkedList<String>(Main.pref.getCollection(SOURCE_HISTORY_KEY, new LinkedList<String>())); 068 Collections.reverse(sourceHistory); // we have to reverse the history, because ComboBoxHistory will reverse it again in addElement() 069 hcbUploadSource.setPossibleItems(sourceHistory); 070 final CommentModelListener sourceModelListener = new CommentModelListener(hcbUploadSource, changesetSourceModel); 071 hcbUploadSource.getEditor().addActionListener(sourceModelListener); 072 hcbUploadSource.getEditor().getEditorComponent().addFocusListener(sourceModelListener); 073 pnl.add(hcbUploadSource, GBC.eol().fill(GBC.HORIZONTAL)); 074 return pnl; 075 } 076 077 protected void build() { 078 setLayout(new BorderLayout()); 079 setBorder(BorderFactory.createEmptyBorder(3,3,3,3)); 080 add(buildUploadCommentPanel(), BorderLayout.NORTH); 081 add(pnlUploadParameterSummary, BorderLayout.CENTER); 082 } 083 084 /** 085 * Creates the panel 086 * 087 * @param changesetCommentModel the model for the changeset comment. Must not be null 088 * @param changesetSourceModel the model for the changeset source. Must not be null. 089 * @throws IllegalArgumentException thrown if {@code changesetCommentModel} is null 090 */ 091 public BasicUploadSettingsPanel(ChangesetCommentModel changesetCommentModel, ChangesetCommentModel changesetSourceModel) { 092 CheckParameterUtil.ensureParameterNotNull(changesetCommentModel, "changesetCommentModel"); 093 CheckParameterUtil.ensureParameterNotNull(changesetSourceModel, "changesetSourceModel"); 094 this.changesetCommentModel = changesetCommentModel; 095 this.changesetSourceModel = changesetSourceModel; 096 changesetCommentModel.addObserver(new ChangesetCommentObserver(hcbUploadComment)); 097 changesetSourceModel.addObserver(new ChangesetCommentObserver(hcbUploadSource)); 098 build(); 099 } 100 101 public void setUploadTagDownFocusTraversalHandlers(final Action handler) { 102 setHistoryComboBoxDownFocusTraversalHandler(handler, hcbUploadComment); 103 setHistoryComboBoxDownFocusTraversalHandler(handler, hcbUploadSource); 104 } 105 106 public void setHistoryComboBoxDownFocusTraversalHandler(final Action handler, final HistoryComboBox hcb) { 107 hcb.getEditor().addActionListener(handler); 108 hcb.getEditor().getEditorComponent().addKeyListener( 109 new KeyListener() { 110 @Override 111 public void keyTyped(KeyEvent e) { 112 if (e.getKeyCode() == KeyEvent.VK_TAB) { 113 handler.actionPerformed(new ActionEvent(hcb, 0, "focusDown")); 114 } 115 } 116 @Override 117 public void keyReleased(KeyEvent e) {} 118 119 @Override 120 public void keyPressed(KeyEvent e) {} 121 } 122 ); 123 } 124 125 /** 126 * Remembers the user input in the preference settings 127 */ 128 public void rememberUserInput() { 129 // store the history of comments 130 hcbUploadComment.addCurrentItemToHistory(); 131 Main.pref.putCollection(HISTORY_KEY, hcbUploadComment.getHistory()); 132 Main.pref.putInteger(HISTORY_LAST_USED_KEY, (int) (System.currentTimeMillis() / 1000)); 133 // store the history of sources 134 hcbUploadSource.addCurrentItemToHistory(); 135 Main.pref.putCollection(SOURCE_HISTORY_KEY, hcbUploadSource.getHistory()); 136 } 137 138 /** 139 * Initializes the panel for user input 140 */ 141 public void startUserInput() { 142 List<String> history = hcbUploadComment.getHistory(); 143 int age = (int) (System.currentTimeMillis()/1000 - Main.pref.getInteger(HISTORY_LAST_USED_KEY, 0)); 144 // only pre-select latest entry if used less than 4 hours ago. 145 if (age < 4 * 3600 * 1000 && history != null && !history.isEmpty()) { 146 hcbUploadComment.setText(history.get(0)); 147 } 148 hcbUploadComment.requestFocusInWindow(); 149 hcbUploadComment.getEditor().getEditorComponent().requestFocusInWindow(); 150 } 151 152 public void initEditingOfUploadComment() { 153 hcbUploadComment.getEditor().selectAll(); 154 hcbUploadComment.requestFocusInWindow(); 155 } 156 157 public UploadParameterSummaryPanel getUploadParameterSummaryPanel() { 158 return pnlUploadParameterSummary; 159 } 160 161 /** 162 * Updates the changeset comment model upon changes in the input field. 163 */ 164 static class CommentModelListener extends FocusAdapter implements ActionListener { 165 166 final HistoryComboBox source; 167 final ChangesetCommentModel destination; 168 169 CommentModelListener(HistoryComboBox source, ChangesetCommentModel destination) { 170 this.source = source; 171 this.destination = destination; 172 } 173 174 @Override 175 public void actionPerformed(ActionEvent e) { 176 destination.setComment(source.getText()); 177 } 178 @Override 179 public void focusLost(FocusEvent e) { 180 destination.setComment(source.getText()); 181 } 182 } 183 184 /** 185 * Observes the changeset comment model and keeps the comment input field 186 * in sync with the current changeset comment 187 */ 188 static class ChangesetCommentObserver implements Observer { 189 190 private final HistoryComboBox destination; 191 192 ChangesetCommentObserver(HistoryComboBox destination) { 193 this.destination = destination; 194 } 195 196 @Override 197 public void update(Observable o, Object arg) { 198 if (!(o instanceof ChangesetCommentModel)) return; 199 String newComment = (String)arg; 200 if (!destination.getText().equals(newComment)) { 201 destination.setText(newComment); 202 } 203 } 204 } 205}