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