001    package nl.cwi.sen1.gui.plugin.editor;
002    
003    import java.awt.BorderLayout;
004    import java.awt.Frame;
005    import java.awt.GridBagConstraints;
006    import java.awt.GridBagLayout;
007    import java.awt.Insets;
008    import java.awt.event.ActionEvent;
009    import java.awt.event.ActionListener;
010    import java.awt.event.KeyEvent;
011    import java.awt.event.WindowAdapter;
012    import java.awt.event.WindowEvent;
013    import java.util.ArrayList;
014    import java.util.List;
015    
016    import javax.swing.AbstractAction;
017    import javax.swing.ActionMap;
018    import javax.swing.ButtonGroup;
019    import javax.swing.InputMap;
020    import javax.swing.JButton;
021    import javax.swing.JCheckBox;
022    import javax.swing.JComboBox;
023    import javax.swing.JComponent;
024    import javax.swing.JLabel;
025    import javax.swing.JPanel;
026    import javax.swing.JRadioButton;
027    import javax.swing.KeyStroke;
028    
029    public class SearchReplaceDialog extends BaseDialog {
030        private EditorPane editor;
031    
032        private JRadioButton backwardRadioButton;
033    
034        private JCheckBox caseSensitiveCheck;
035    
036        private JButton closeButton;
037    
038        private ButtonGroup directionButtonGroup;
039    
040        private JPanel directionPanel;
041    
042        private JButton findButton;
043    
044        private JComboBox findCombo;
045    
046        private JLabel findLabel;
047    
048        private JRadioButton forwardRadioButton;
049    
050        private JPanel jPanel1;
051    
052        private JPanel mainPanel;
053    
054        private JPanel optionsPanel;
055    
056        private JButton replaceAllButton;
057    
058        private JButton replaceButton;
059    
060        private JButton replaceFindButton;
061    
062        private JLabel replaceLabel;
063    
064        private JComboBox replaceWithCombo;
065    
066        private JCheckBox wrapSearchCheck;
067    
068        public String getFindText() {
069            String findText = findCombo.getEditor().getItem().toString();
070            return findText;
071        }
072    
073        public void setFindText(String findText) {
074            updateComboBox(findCombo, findText);
075        }
076    
077        public boolean getFindDirection() {
078            return forwardRadioButton.isSelected();
079        }
080    
081        public boolean isCaseSensitiveSearch() {
082            return caseSensitiveCheck.isSelected();
083        }
084    
085        public boolean isWrappedSearch() {
086            return wrapSearchCheck.isSelected();
087        }
088    
089        public void setVisible(boolean b) {
090            if (b) {
091                String newSearch = editor.getSelectedText();
092                if (newSearch != null && newSearch.length() != 0) {
093                    findCombo.insertItemAt(newSearch, 0);
094                    findCombo.setSelectedIndex(0);
095                }
096                findCombo.getEditor().selectAll();
097                findCombo.requestFocus();
098            }
099            super.setVisible(b);
100        }
101    
102        public SearchReplaceDialog(EditorPane editor, Frame frame) {
103            super(frame);
104            setTitle("Find/Replace");
105            this.editor = editor;
106            initComponents();
107            forwardRadioButton.setSelected(true);
108            wrapSearchCheck.setSelected(true);
109    
110            initBindings();
111        }
112    
113        private void initBindings() {
114            InputMap inputMap = this.getRootPane().getInputMap(
115                    JComponent.WHEN_IN_FOCUSED_WINDOW);
116            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escape");
117            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "enter");
118    
119            ActionMap actionMap = this.getRootPane().getActionMap();
120            actionMap.put("escape", new AbstractAction() {
121                public void actionPerformed(ActionEvent evt) {
122                    closeButtonActionPerformed();
123                }
124            });
125            actionMap.put("enter", new AbstractAction() {
126                public void actionPerformed(ActionEvent evt) {
127                    System.err.println("Enter action performed");
128                    findButtonActionPerformed();
129                }
130            });
131    
132            findCombo.getEditor().getEditorComponent().addKeyListener(
133                    new java.awt.event.KeyAdapter() {
134                        public void keyPressed(java.awt.event.KeyEvent e) {
135                            if (e.getKeyCode() == KeyEvent.VK_ENTER) {
136                                findButtonActionPerformed();
137                                e.consume();
138                            }
139                        }
140                    });
141            
142            replaceWithCombo.getEditor().getEditorComponent().addKeyListener(
143                    new java.awt.event.KeyAdapter() {
144                        public void keyPressed(java.awt.event.KeyEvent e) {
145                            if (e.getKeyCode() == KeyEvent.VK_ENTER) {
146                                findButtonActionPerformed();
147                                e.consume();
148                            }
149                        }
150                    });
151        }
152    
153        private void initComponents() {
154            GridBagConstraints gridBagConstraints;
155    
156            directionButtonGroup = new ButtonGroup();
157            jPanel1 = new JPanel();
158            findButton = new JButton();
159            replaceFindButton = new JButton();
160            replaceButton = new JButton();
161            replaceAllButton = new JButton();
162            closeButton = new JButton();
163            mainPanel = new JPanel();
164            findLabel = new JLabel();
165            replaceLabel = new JLabel();
166            findCombo = new JComboBox();
167            replaceWithCombo = new JComboBox();
168            directionPanel = new JPanel();
169            forwardRadioButton = new JRadioButton();
170            backwardRadioButton = new JRadioButton();
171            optionsPanel = new JPanel();
172            caseSensitiveCheck = new JCheckBox();
173            wrapSearchCheck = new JCheckBox();
174    
175            addWindowListener(new WindowAdapter() {
176                public void windowClosing(WindowEvent evt) {
177                    closeDialog();
178                }
179            });
180    
181            jPanel1.setLayout(new GridBagLayout());
182    
183            findButton.setMnemonic('n');
184            findButton.setText("Find");
185            findButton.addActionListener(new ActionListener() {
186                public void actionPerformed(ActionEvent evt) {
187                    findButtonActionPerformed();
188                }
189            });
190    
191            gridBagConstraints = new GridBagConstraints();
192            gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
193            gridBagConstraints.anchor = GridBagConstraints.EAST;
194            gridBagConstraints.weightx = 0.5;
195            gridBagConstraints.insets = new Insets(2, 2, 2, 2);
196            jPanel1.add(findButton, gridBagConstraints);
197    
198            replaceFindButton.setMnemonic('d');
199            replaceFindButton.setText("Replace/Find");
200            replaceFindButton.addActionListener(new ActionListener() {
201                public void actionPerformed(ActionEvent evt) {
202                    replaceFindButtonActionPerformed();
203                }
204            });
205    
206            gridBagConstraints = new GridBagConstraints();
207            gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
208            gridBagConstraints.anchor = GridBagConstraints.WEST;
209            gridBagConstraints.weightx = 0.5;
210            gridBagConstraints.insets = new Insets(2, 2, 2, 2);
211            jPanel1.add(replaceFindButton, gridBagConstraints);
212    
213            replaceButton.setMnemonic('R');
214            replaceButton.setText("Replace");
215            replaceButton.addActionListener(new ActionListener() {
216                public void actionPerformed(ActionEvent evt) {
217                    replaceButtonActionPerformed();
218                }
219            });
220    
221            gridBagConstraints = new GridBagConstraints();
222            gridBagConstraints.gridx = 0;
223            gridBagConstraints.gridy = 1;
224            gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
225            gridBagConstraints.anchor = GridBagConstraints.EAST;
226            gridBagConstraints.weightx = 0.5;
227            gridBagConstraints.insets = new Insets(2, 2, 2, 2);
228            jPanel1.add(replaceButton, gridBagConstraints);
229    
230            replaceAllButton.setMnemonic('A');
231            replaceAllButton.setText("Replace All");
232            replaceAllButton.addActionListener(new ActionListener() {
233                public void actionPerformed(ActionEvent evt) {
234                    replaceAllButtonActionPerformed();
235                }
236            });
237    
238            gridBagConstraints = new GridBagConstraints();
239            gridBagConstraints.gridx = 1;
240            gridBagConstraints.gridy = 1;
241            gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
242            gridBagConstraints.anchor = GridBagConstraints.WEST;
243            gridBagConstraints.weightx = 0.5;
244            gridBagConstraints.insets = new Insets(2, 2, 2, 2);
245            jPanel1.add(replaceAllButton, gridBagConstraints);
246    
247            closeButton.setText("Close");
248            closeButton.addActionListener(new ActionListener() {
249                public void actionPerformed(ActionEvent evt) {
250                    closeButtonActionPerformed();
251                }
252            });
253    
254            gridBagConstraints = new GridBagConstraints();
255            gridBagConstraints.gridx = 1;
256            gridBagConstraints.gridy = 2;
257            gridBagConstraints.anchor = GridBagConstraints.NORTHEAST;
258            gridBagConstraints.insets = new Insets(2, 2, 2, 2);
259            jPanel1.add(closeButton, gridBagConstraints);
260    
261            getContentPane().add(jPanel1, BorderLayout.SOUTH);
262    
263            mainPanel.setLayout(new GridBagLayout());
264    
265            findLabel.setText("Find:");
266            gridBagConstraints = new GridBagConstraints();
267            gridBagConstraints.anchor = GridBagConstraints.EAST;
268            gridBagConstraints.insets = new Insets(2, 0, 2, 2);
269            mainPanel.add(findLabel, gridBagConstraints);
270    
271            replaceLabel.setText("Replace with:");
272            gridBagConstraints = new GridBagConstraints();
273            gridBagConstraints.gridx = 0;
274            gridBagConstraints.gridy = 1;
275            gridBagConstraints.anchor = GridBagConstraints.EAST;
276            gridBagConstraints.insets = new Insets(2, 0, 2, 2);
277            mainPanel.add(replaceLabel, gridBagConstraints);
278    
279            findCombo.setEditable(true);
280            gridBagConstraints = new GridBagConstraints();
281            gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
282            gridBagConstraints.anchor = GridBagConstraints.WEST;
283            gridBagConstraints.weightx = 1.0;
284            gridBagConstraints.insets = new Insets(2, 2, 2, 2);
285            mainPanel.add(findCombo, gridBagConstraints);
286    
287            replaceWithCombo.setEditable(true);
288            gridBagConstraints = new GridBagConstraints();
289            gridBagConstraints.gridx = 1;
290            gridBagConstraints.gridy = 1;
291            gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
292            gridBagConstraints.anchor = GridBagConstraints.WEST;
293            gridBagConstraints.weightx = 1.0;
294            gridBagConstraints.insets = new Insets(2, 2, 2, 2);
295            mainPanel.add(replaceWithCombo, gridBagConstraints);
296    
297            directionPanel.setLayout(new GridBagLayout());
298    
299            directionPanel.setBorder(new javax.swing.border.TitledBorder(
300                    "Direction"));
301            forwardRadioButton.setText("Forward");
302            directionButtonGroup.add(forwardRadioButton);
303            gridBagConstraints = new GridBagConstraints();
304            gridBagConstraints.anchor = GridBagConstraints.WEST;
305            gridBagConstraints.weightx = 0.5;
306            directionPanel.add(forwardRadioButton, gridBagConstraints);
307    
308            backwardRadioButton.setText("Backward");
309            directionButtonGroup.add(backwardRadioButton);
310            gridBagConstraints = new GridBagConstraints();
311            gridBagConstraints.anchor = GridBagConstraints.EAST;
312            gridBagConstraints.weightx = 0.5;
313            directionPanel.add(backwardRadioButton, gridBagConstraints);
314    
315            gridBagConstraints = new GridBagConstraints();
316            gridBagConstraints.gridx = 0;
317            gridBagConstraints.gridy = 2;
318            gridBagConstraints.gridwidth = 2;
319            gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
320            gridBagConstraints.insets = new Insets(2, 2, 2, 2);
321            mainPanel.add(directionPanel, gridBagConstraints);
322    
323            optionsPanel.setLayout(new GridBagLayout());
324    
325            optionsPanel.setBorder(new javax.swing.border.TitledBorder("Options"));
326            caseSensitiveCheck.setText("Case Sensitive");
327            gridBagConstraints = new GridBagConstraints();
328            gridBagConstraints.anchor = GridBagConstraints.WEST;
329            gridBagConstraints.weightx = 0.5;
330            optionsPanel.add(caseSensitiveCheck, gridBagConstraints);
331    
332            wrapSearchCheck.setText("Wrap Search");
333            gridBagConstraints = new GridBagConstraints();
334            gridBagConstraints.anchor = GridBagConstraints.EAST;
335            gridBagConstraints.weightx = 0.5;
336            optionsPanel.add(wrapSearchCheck, gridBagConstraints);
337    
338            gridBagConstraints = new GridBagConstraints();
339            gridBagConstraints.gridx = 0;
340            gridBagConstraints.gridy = 3;
341            gridBagConstraints.gridwidth = 2;
342            gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
343            gridBagConstraints.insets = new Insets(2, 2, 2, 2);
344            mainPanel.add(optionsPanel, gridBagConstraints);
345    
346            getContentPane().add(mainPanel, BorderLayout.CENTER);
347    
348            pack();
349        }
350    
351        private void closeButtonActionPerformed() {
352            this.setVisible(false);
353        }
354    
355        private void replaceAllButtonActionPerformed() {
356            String textToFind = getFindText();
357            updateComboBox(findCombo, textToFind);
358            String textToReplaceWith = (String) replaceWithCombo.getSelectedItem();
359            updateComboBox(replaceWithCombo, textToReplaceWith);
360            editor.replaceAll(textToFind, textToReplaceWith,
361                    !isCaseSensitiveSearch());
362        }
363    
364        private void replaceButtonActionPerformed() {
365            String textToFind = getFindText();
366            String selectedText = editor.getSelectedText();
367    
368            if ((isCaseSensitiveSearch() && textToFind.equals(selectedText))
369                    || (!isCaseSensitiveSearch() && textToFind
370                            .equalsIgnoreCase(selectedText))) {
371                String textToReplaceWith = (String) replaceWithCombo
372                        .getSelectedItem();
373    
374                if (textToReplaceWith != null) {
375                    updateComboBox(replaceWithCombo, textToReplaceWith);
376                    int selectionStart = editor.getSelectionStart();
377                    editor.replaceSelection(textToReplaceWith);
378                    editor.setSelectionStart(selectionStart);
379                    editor.setSelectionEnd(selectionStart
380                            + textToReplaceWith.length());
381                }
382            }
383        }
384    
385        private void findButtonActionPerformed() {
386            String textToFind = getFindText();
387            updateComboBox(findCombo, textToFind);
388            editor.find(textToFind, !isCaseSensitiveSearch(), isWrappedSearch(),
389                    getFindDirection());
390        }
391    
392        private void replaceFindButtonActionPerformed() {
393            replaceButtonActionPerformed();
394            findButtonActionPerformed();
395        }
396    
397        private void updateComboBox(JComboBox combo, String latestEntry) {
398            int numItems = combo.getItemCount();
399            List<String> items = new ArrayList<String>();
400            for (int i = 0; i < numItems; i++) {
401                String current = (String) combo.getItemAt(i);
402                if ((current != null) && !current.equals(latestEntry)) {
403                    items.add(current);
404                }
405            }
406            numItems = items.size();
407            combo.removeAllItems();
408            combo.addItem(latestEntry);
409            for (int i = 0; i < numItems; i++) {
410                combo.addItem(items.get(i));
411            }
412        }
413    }