001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.dialogs.changeset.query; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.BorderLayout; 007import java.awt.Container; 008import java.awt.Dialog; 009import java.awt.Dimension; 010import java.awt.FlowLayout; 011import java.awt.Frame; 012import java.awt.event.ActionEvent; 013import java.awt.event.KeyEvent; 014import java.awt.event.WindowAdapter; 015import java.awt.event.WindowEvent; 016 017import javax.swing.AbstractAction; 018import javax.swing.JComponent; 019import javax.swing.JDialog; 020import javax.swing.JOptionPane; 021import javax.swing.JPanel; 022import javax.swing.JTabbedPane; 023import javax.swing.KeyStroke; 024 025import org.openstreetmap.josm.gui.HelpAwareOptionPane; 026import org.openstreetmap.josm.gui.SideButton; 027import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction; 028import org.openstreetmap.josm.gui.help.HelpUtil; 029import org.openstreetmap.josm.io.ChangesetQuery; 030import org.openstreetmap.josm.tools.ImageProvider; 031import org.openstreetmap.josm.tools.WindowGeometry; 032 033/** 034 * This is a modal dialog for entering query criteria to search for changesets. 035 * 036 */ 037public class ChangesetQueryDialog extends JDialog { 038 039 private JTabbedPane tpQueryPanels; 040 private BasicChangesetQueryPanel pnlBasicChangesetQueries; 041 private UrlBasedQueryPanel pnlUrlBasedQueries; 042 private AdvancedChangesetQueryPanel pnlAdvancedQueries; 043 private boolean canceled; 044 045 protected JPanel buildContentPanel() { 046 tpQueryPanels = new JTabbedPane(); 047 tpQueryPanels.add(pnlBasicChangesetQueries = new BasicChangesetQueryPanel()); 048 tpQueryPanels.add(pnlUrlBasedQueries = new UrlBasedQueryPanel()); 049 tpQueryPanels.add(pnlAdvancedQueries = new AdvancedChangesetQueryPanel()); 050 051 tpQueryPanels.setTitleAt(0, tr("Basic")); 052 tpQueryPanels.setToolTipTextAt(0, tr("Download changesets using predefined queries")); 053 054 tpQueryPanels.setTitleAt(1, tr("From URL")); 055 tpQueryPanels.setToolTipTextAt(1, tr("Query changesets from a server URL")); 056 057 tpQueryPanels.setTitleAt(2, tr("Advanced")); 058 tpQueryPanels.setToolTipTextAt(2, tr("Use a custom changeset query")); 059 060 JPanel pnl = new JPanel(new BorderLayout()); 061 pnl.add(tpQueryPanels, BorderLayout.CENTER); 062 return pnl; 063 } 064 065 protected JPanel buildButtonPanel() { 066 JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER)); 067 068 // -- query action 069 pnl.add(new SideButton(new QueryAction())); 070 071 // -- cancel action 072 pnl.add(new SideButton(new CancelAction())); 073 074 // -- help action 075 pnl.add(new SideButton(new ContextSensitiveHelpAction(HelpUtil.ht("/Dialog/ChangesetQuery")))); 076 077 return pnl; 078 } 079 080 protected final void build() { 081 setTitle(tr("Query changesets")); 082 Container cp = getContentPane(); 083 cp.setLayout(new BorderLayout()); 084 cp.add(buildContentPanel(), BorderLayout.CENTER); 085 cp.add(buildButtonPanel(), BorderLayout.SOUTH); 086 087 // cancel on ESC 088 getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel"); 089 getRootPane().getActionMap().put("cancel", new CancelAction()); 090 091 // context sensitive help 092 HelpUtil.setHelpContext(getRootPane(), HelpUtil.ht("/Dialog/ChangesetQueryDialog")); 093 094 addWindowListener(new WindowEventHandler()); 095 } 096 097 public ChangesetQueryDialog(Dialog parent) { 098 super(parent, ModalityType.DOCUMENT_MODAL); 099 build(); 100 } 101 102 public ChangesetQueryDialog(Frame parent) { 103 super(parent, ModalityType.DOCUMENT_MODAL); 104 build(); 105 } 106 107 public boolean isCanceled() { 108 return canceled; 109 } 110 111 public void initForUserInput() { 112 pnlBasicChangesetQueries.init(); 113 } 114 115 protected void setCanceled(boolean canceled) { 116 this.canceled = canceled; 117 } 118 119 public ChangesetQuery getChangesetQuery() { 120 if (isCanceled()) 121 return null; 122 switch(tpQueryPanels.getSelectedIndex()) { 123 case 0: 124 return pnlBasicChangesetQueries.buildChangesetQuery(); 125 case 1: 126 return pnlUrlBasedQueries.buildChangesetQuery(); 127 case 2: 128 return pnlAdvancedQueries.buildChangesetQuery(); 129 default: 130 // FIXME: extend with advanced queries 131 return null; 132 } 133 } 134 135 public void startUserInput() { 136 pnlUrlBasedQueries.startUserInput(); 137 pnlAdvancedQueries.startUserInput(); 138 } 139 140 @Override 141 public void setVisible(boolean visible) { 142 if (visible) { 143 new WindowGeometry( 144 getClass().getName() + ".geometry", 145 WindowGeometry.centerInWindow( 146 getParent(), 147 new Dimension(400,400) 148 ) 149 ).applySafe(this); 150 setCanceled(false); 151 startUserInput(); 152 } else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775 153 new WindowGeometry(this).remember(getClass().getName() + ".geometry"); 154 pnlAdvancedQueries.rememberSettings(); 155 } 156 super.setVisible(visible); 157 } 158 159 class QueryAction extends AbstractAction { 160 public QueryAction() { 161 putValue(NAME, tr("Query")); 162 putValue(SMALL_ICON, ImageProvider.get("dialogs", "search")); 163 putValue(SHORT_DESCRIPTION, tr("Query and download changesets")); 164 } 165 166 protected void alertInvalidChangesetQuery() { 167 HelpAwareOptionPane.showOptionDialog( 168 ChangesetQueryDialog.this, 169 tr("Please enter a valid changeset query URL first."), 170 tr("Illegal changeset query URL"), 171 JOptionPane.WARNING_MESSAGE, 172 HelpUtil.ht("/Dialog/ChangesetQueryDialog#EnterAValidChangesetQueryUrlFirst") 173 ); 174 } 175 176 @Override 177 public void actionPerformed(ActionEvent arg0) { 178 try { 179 switch(tpQueryPanels.getSelectedIndex()) { 180 case 0: 181 // currently, query specifications can't be invalid in the basic query panel. 182 // We select from a couple of predefined queries and there is always a query 183 // selected 184 break; 185 case 1: 186 if (getChangesetQuery() == null) { 187 alertInvalidChangesetQuery(); 188 pnlUrlBasedQueries.startUserInput(); 189 return; 190 } 191 break; 192 193 case 2: 194 if (getChangesetQuery() == null) { 195 pnlAdvancedQueries.displayMessageIfInvalid(); 196 return; 197 } 198 } 199 setCanceled(false); 200 setVisible(false); 201 } catch (IllegalStateException e) { 202 JOptionPane.showMessageDialog(ChangesetQueryDialog.this, e.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE); 203 } 204 } 205 } 206 207 class CancelAction extends AbstractAction { 208 209 public CancelAction() { 210 putValue(NAME, tr("Cancel")); 211 putValue(SMALL_ICON, ImageProvider.get("cancel")); 212 putValue(SHORT_DESCRIPTION, tr("Close the dialog and abort querying of changesets")); 213 } 214 215 public void cancel() { 216 setCanceled(true); 217 setVisible(false); 218 } 219 220 @Override 221 public void actionPerformed(ActionEvent arg0) { 222 cancel(); 223 } 224 } 225 226 class WindowEventHandler extends WindowAdapter { 227 @Override 228 public void windowClosing(WindowEvent arg0) { 229 new CancelAction().cancel(); 230 } 231 } 232}