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/ChangesetQueryDialog")))); 076 077 return pnl; 078 } 079 080 081 protected void build() { 082 setTitle(tr("Query changesets")); 083 Container cp = getContentPane(); 084 cp.setLayout(new BorderLayout()); 085 cp.add(buildContentPanel(), BorderLayout.CENTER); 086 cp.add(buildButtonPanel(), BorderLayout.SOUTH); 087 088 // cancel on ESC 089 getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel"); 090 getRootPane().getActionMap().put("cancel", new CancelAction()); 091 092 // context sensitive help 093 HelpUtil.setHelpContext(getRootPane(), HelpUtil.ht("/Dialog/ChangesetQueryDialog")); 094 095 addWindowListener(new WindowEventHandler()); 096 } 097 098 099 public ChangesetQueryDialog(Dialog parent) { 100 super(parent, ModalityType.DOCUMENT_MODAL); 101 build(); 102 } 103 104 public ChangesetQueryDialog(Frame parent) { 105 super(parent, ModalityType.DOCUMENT_MODAL); 106 build(); 107 } 108 109 public boolean isCanceled() { 110 return canceled; 111 } 112 113 public void initForUserInput() { 114 pnlBasicChangesetQueries.init(); 115 } 116 117 protected void setCanceled(boolean canceled) { 118 this.canceled = canceled; 119 } 120 121 public ChangesetQuery getChangesetQuery() { 122 if (isCanceled()) 123 return null; 124 switch(tpQueryPanels.getSelectedIndex()) { 125 case 0: 126 return pnlBasicChangesetQueries.buildChangesetQuery(); 127 case 1: 128 return pnlUrlBasedQueries.buildChangesetQuery(); 129 case 2: 130 return pnlAdvancedQueries.buildChangesetQuery(); 131 default: 132 // FIXME: extend with advanced queries 133 return null; 134 } 135 } 136 137 public void startUserInput() { 138 pnlUrlBasedQueries.startUserInput(); 139 pnlAdvancedQueries.startUserInput(); 140 } 141 142 @Override 143 public void setVisible(boolean visible) { 144 if (visible) { 145 new WindowGeometry( 146 getClass().getName() + ".geometry", 147 WindowGeometry.centerInWindow( 148 getParent(), 149 new Dimension(400,400) 150 ) 151 ).applySafe(this); 152 setCanceled(false); 153 startUserInput(); 154 } else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775 155 new WindowGeometry(this).remember(getClass().getName() + ".geometry"); 156 pnlAdvancedQueries.rememberSettings(); 157 } 158 super.setVisible(visible); 159 } 160 161 class QueryAction extends AbstractAction { 162 public QueryAction() { 163 putValue(NAME, tr("Query")); 164 putValue(SMALL_ICON, ImageProvider.get("dialogs", "search")); 165 putValue(SHORT_DESCRIPTION, tr("Query and download changesets")); 166 } 167 168 protected void alertInvalidChangesetQuery() { 169 HelpAwareOptionPane.showOptionDialog( 170 ChangesetQueryDialog.this, 171 tr("Please enter a valid changeset query URL first."), 172 tr("Illegal changeset query URL"), 173 JOptionPane.WARNING_MESSAGE, 174 HelpUtil.ht("/Dialog/ChangesetQueryDialog#EnterAValidChangesetQueryUrlFirst") 175 ); 176 } 177 178 @Override 179 public void actionPerformed(ActionEvent arg0) { 180 try { 181 switch(tpQueryPanels.getSelectedIndex()) { 182 case 0: 183 // currently, query specifications can't be invalid in the basic query panel. 184 // We select from a couple of predefined queries and there is always a query 185 // selected 186 break; 187 case 1: 188 if (getChangesetQuery() == null) { 189 alertInvalidChangesetQuery(); 190 pnlUrlBasedQueries.startUserInput(); 191 return; 192 } 193 break; 194 195 case 2: 196 if (getChangesetQuery() == null) { 197 pnlAdvancedQueries.displayMessageIfInvalid(); 198 return; 199 } 200 } 201 setCanceled(false); 202 setVisible(false); 203 } catch (IllegalStateException e) { 204 JOptionPane.showMessageDialog(ChangesetQueryDialog.this, e.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE); 205 } 206 } 207 } 208 209 class CancelAction extends AbstractAction { 210 211 public CancelAction() { 212 putValue(NAME, tr("Cancel")); 213 putValue(SMALL_ICON, ImageProvider.get("cancel")); 214 putValue(SHORT_DESCRIPTION, tr("Close the dialog and abort querying of changesets")); 215 } 216 217 public void cancel() { 218 setCanceled(true); 219 setVisible(false); 220 } 221 222 @Override 223 public void actionPerformed(ActionEvent arg0) { 224 cancel(); 225 } 226 } 227 228 class WindowEventHandler extends WindowAdapter { 229 @Override 230 public void windowClosing(WindowEvent arg0) { 231 new CancelAction().cancel(); 232 } 233 } 234}