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