001 // License: GPL. For details, see LICENSE file. 002 package org.openstreetmap.josm.gui.dialogs.changeset.query; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.awt.BorderLayout; 007 import java.awt.Container; 008 import java.awt.Dialog; 009 import java.awt.Dimension; 010 import java.awt.FlowLayout; 011 import java.awt.Frame; 012 import java.awt.event.ActionEvent; 013 import java.awt.event.KeyEvent; 014 import java.awt.event.WindowAdapter; 015 import java.awt.event.WindowEvent; 016 017 import javax.swing.AbstractAction; 018 import javax.swing.JComponent; 019 import javax.swing.JDialog; 020 import javax.swing.JOptionPane; 021 import javax.swing.JPanel; 022 import javax.swing.JTabbedPane; 023 import javax.swing.KeyStroke; 024 025 import org.openstreetmap.josm.gui.HelpAwareOptionPane; 026 import org.openstreetmap.josm.gui.SideButton; 027 import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction; 028 import org.openstreetmap.josm.gui.help.HelpUtil; 029 import org.openstreetmap.josm.io.ChangesetQuery; 030 import org.openstreetmap.josm.tools.ImageProvider; 031 import org.openstreetmap.josm.tools.WindowGeometry; 032 033 /** 034 * This is a modal dialog for entering query criteria to search for changesets. 035 * 036 */ 037 public 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 (!visible && isShowing()){ 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 public void actionPerformed(ActionEvent arg0) { 179 try { 180 switch(tpQueryPanels.getSelectedIndex()) { 181 case 0: 182 // currently, query specifications can't be invalid in the basic query panel. 183 // We select from a couple of predefined queries and there is always a query 184 // selected 185 break; 186 case 1: 187 if (getChangesetQuery() == null) { 188 alertInvalidChangesetQuery(); 189 pnlUrlBasedQueries.startUserInput(); 190 return; 191 } 192 break; 193 194 case 2: 195 if (getChangesetQuery() == null) { 196 pnlAdvancedQueries.displayMessageIfInvalid(); 197 return; 198 } 199 } 200 setCanceled(false); 201 setVisible(false); 202 } catch (IllegalStateException e) { 203 JOptionPane.showMessageDialog(ChangesetQueryDialog.this, e.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE); 204 } 205 } 206 } 207 208 class CancelAction extends AbstractAction { 209 210 public CancelAction() { 211 putValue(NAME, tr("Cancel")); 212 putValue(SMALL_ICON, ImageProvider.get("cancel")); 213 putValue(SHORT_DESCRIPTION, tr("Close the dialog and abort querying of changesets")); 214 } 215 216 public void cancel() { 217 setCanceled(true); 218 setVisible(false); 219 } 220 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 }