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 public boolean isCanceled() { 099 return canceled; 100 } 101 102 public void initForUserInput() { 103 pnlBasicChangesetQueries.init(); 104 } 105 106 protected void setCanceled(boolean canceled) { 107 this.canceled = canceled; 108 } 109 110 public ChangesetQuery getChangesetQuery() { 111 if (isCanceled()) 112 return null; 113 switch(tpQueryPanels.getSelectedIndex()) { 114 case 0: 115 return pnlBasicChangesetQueries.buildChangesetQuery(); 116 case 1: 117 return pnlUrlBasedQueries.buildChangesetQuery(); 118 case 2: 119 return pnlAdvancedQueries.buildChangesetQuery(); 120 default: 121 // FIXME: extend with advanced queries 122 return null; 123 } 124 } 125 126 public void startUserInput() { 127 pnlUrlBasedQueries.startUserInput(); 128 pnlAdvancedQueries.startUserInput(); 129 } 130 131 @Override 132 public void setVisible(boolean visible) { 133 if (visible) { 134 new WindowGeometry( 135 getClass().getName() + ".geometry", 136 WindowGeometry.centerInWindow( 137 getParent(), 138 new Dimension(400, 400) 139 ) 140 ).applySafe(this); 141 setCanceled(false); 142 startUserInput(); 143 } else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775 144 new WindowGeometry(this).remember(getClass().getName() + ".geometry"); 145 pnlAdvancedQueries.rememberSettings(); 146 } 147 super.setVisible(visible); 148 } 149 150 class QueryAction extends AbstractAction { 151 QueryAction() { 152 putValue(NAME, tr("Query")); 153 new ImageProvider("dialogs", "search").getResource().attachImageIcon(this); 154 putValue(SHORT_DESCRIPTION, tr("Query and download changesets")); 155 } 156 157 protected void alertInvalidChangesetQuery() { 158 HelpAwareOptionPane.showOptionDialog( 159 ChangesetQueryDialog.this, 160 tr("Please enter a valid changeset query URL first."), 161 tr("Illegal changeset query URL"), 162 JOptionPane.WARNING_MESSAGE, 163 HelpUtil.ht("/Dialog/ChangesetQueryDialog#EnterAValidChangesetQueryUrlFirst") 164 ); 165 } 166 167 @Override 168 public void actionPerformed(ActionEvent arg0) { 169 try { 170 switch(tpQueryPanels.getSelectedIndex()) { 171 case 0: 172 // currently, query specifications can't be invalid in the basic query panel. 173 // We select from a couple of predefined queries and there is always a query 174 // selected 175 break; 176 case 1: 177 if (getChangesetQuery() == null) { 178 alertInvalidChangesetQuery(); 179 pnlUrlBasedQueries.startUserInput(); 180 return; 181 } 182 break; 183 case 2: 184 if (getChangesetQuery() == null) { 185 pnlAdvancedQueries.displayMessageIfInvalid(); 186 return; 187 } 188 } 189 setCanceled(false); 190 setVisible(false); 191 } catch (IllegalStateException e) { 192 Main.error(e); 193 JOptionPane.showMessageDialog(ChangesetQueryDialog.this, e.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE); 194 } 195 } 196 } 197 198 class CancelAction extends AbstractAction { 199 200 CancelAction() { 201 putValue(NAME, tr("Cancel")); 202 new ImageProvider("cancel").getResource().attachImageIcon(this); 203 putValue(SHORT_DESCRIPTION, tr("Close the dialog and abort querying of changesets")); 204 } 205 206 public void cancel() { 207 setCanceled(true); 208 setVisible(false); 209 } 210 211 @Override 212 public void actionPerformed(ActionEvent arg0) { 213 cancel(); 214 } 215 } 216 217 class WindowEventHandler extends WindowAdapter { 218 @Override 219 public void windowClosing(WindowEvent arg0) { 220 new CancelAction().cancel(); 221 } 222 } 223}