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