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