1
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
4
Part of the Processing project - http://processing.org
6
Copyright (c) 2004-08 Ben Fry and Casey Reas
7
Copyright (c) 2001-04 Massachusetts Institute of Technology
9
This program is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License as published by
11
the Free Software Foundation; either version 2 of the License, or
12
(at your option) any later version.
14
This program is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
GNU General Public License for more details.
19
You should have received a copy of the GNU General Public License
20
along with this program; if not, write to the Free Software Foundation,
21
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
package processing.app;
27
import java.awt.event.*;
32
* Find & Replace window for the Processing editor.
34
* One major annoyance in this is that the window is re-created each time
35
* that "Find" is called. This is because Mac OS X has a strange focus
36
* issue with windows that are re-shown with setVisible() or show().
37
* requestFocusInWindow() properly sets the focus to the find field,
38
* however, just a short moment later, the focus is set to null. Even
39
* trying to catch this scenario and request it again doesn't seem to work.
40
* Most likely this is some annoyance buried deep in one of Apple's docs,
41
* or in the doc for the focus stuff (I tend to think the former because
42
* Windows doesn't seem to be quite so beligerent). Filed as
43
* <A HREF="http://dev.processing.org/bugs/show_bug.cgi?id=244"> Bug 244</A>
44
* should anyone have clues about how to fix.
46
public class FindReplace extends JFrame implements ActionListener {
48
static final int BIG = 13;
49
static final int SMALL = 6;
54
JTextField replaceField;
55
static String findString;
56
static String replaceString;
58
JButton replaceButton;
59
JButton replaceAllButton;
60
JButton replaceFindButton;
63
JCheckBox ignoreCaseBox;
64
static boolean ignoreCase = true;
66
/// true when there's something selected in the editor
70
public FindReplace(Editor editor) {
75
Container pain = getContentPane();
78
JLabel findLabel = new JLabel("Find:");
79
Dimension d0 = findLabel.getPreferredSize();
80
JLabel replaceLabel = new JLabel("Replace with:");
81
Dimension d1 = replaceLabel.getPreferredSize();
84
pain.add(replaceLabel);
86
pain.add(findField = new JTextField(20));
87
pain.add(replaceField = new JTextField(20));
88
Dimension d2 = findField.getPreferredSize();
90
if (findString != null) findField.setText(findString);
91
if (replaceString != null) replaceField.setText(replaceString);
92
//System.out.println("setting find str to " + findString);
93
//findField.requestFocusInWindow();
97
findField.addFocusListener(new FocusListener() {
98
public void focusGained(FocusEvent e) {
99
System.out.println("Focus gained " + e.getOppositeComponent());
102
public void focusLost(FocusEvent e) {
103
System.out.println("Focus lost "); // + e.getOppositeComponent());
104
if (e.getOppositeComponent() == null) {
105
requestFocusInWindow();
111
// +1 since it's better to tend downwards
112
int yoff = (1 + d2.height - d1.height) / 2;
114
findLabel.setBounds(BIG + (d1.width-d0.width) + yoff, BIG,
115
d1.width, d1.height);
116
replaceLabel.setBounds(BIG, BIG + d2.height + SMALL + yoff,
117
d1.width, d1.height);
120
ignoreCaseBox = new JCheckBox("Ignore Case");
121
ignoreCaseBox.addActionListener(new ActionListener() {
122
public void actionPerformed(ActionEvent e) {
123
ignoreCase = ignoreCaseBox.isSelected();
126
ignoreCaseBox.setSelected(ignoreCase);
127
pain.add(ignoreCaseBox);
131
JPanel buttons = new JPanel();
132
buttons.setLayout(new FlowLayout());
134
// ordering is different on mac versus pc
135
if (Base.isMacOS()) {
136
buttons.add(replaceAllButton = new JButton("Replace All"));
137
buttons.add(replaceButton = new JButton("Replace"));
138
buttons.add(replaceFindButton = new JButton("Replace & Find"));
139
buttons.add(findButton = new JButton("Find"));
142
buttons.add(findButton = new JButton("Find"));
143
buttons.add(replaceFindButton = new JButton("Replace & Find"));
144
buttons.add(replaceButton = new JButton("Replace"));
145
buttons.add(replaceAllButton = new JButton("Replace All"));
149
// to fix ugliness.. normally macosx java 1.3 puts an
150
// ugly white border around this object, so turn it off.
151
if (Base.isMacOS()) {
152
buttons.setBorder(null);
155
Dimension d3 = buttons.getPreferredSize();
156
//buttons.setBounds(BIG, BIG + d2.height*2 + SMALL + BIG,
157
buttons.setBounds(BIG, BIG + d2.height*3 + SMALL*2 + BIG,
158
d3.width, d3.height);
162
findField.setBounds(BIG + d1.width + SMALL, BIG,
163
d3.width - (d1.width + SMALL), d2.height);
164
replaceField.setBounds(BIG + d1.width + SMALL, BIG + d2.height + SMALL,
165
d3.width - (d1.width + SMALL), d2.height);
167
ignoreCaseBox.setBounds(BIG + d1.width + SMALL,
168
BIG + d2.height*2 + SMALL*2,
169
d3.width, d2.height);
173
replaceButton.addActionListener(this);
174
replaceAllButton.addActionListener(this);
175
replaceFindButton.addActionListener(this);
176
findButton.addActionListener(this);
178
// you mustn't replace what you haven't found, my son
179
replaceButton.setEnabled(false);
180
replaceFindButton.setEnabled(false);
182
// so that typing will go straight to this field
183
//findField.requestFocus();
185
// make the find button the blinky default
186
getRootPane().setDefaultButton(findButton);
188
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
190
int wide = d3.width + BIG*2;
191
Rectangle butt = buttons.getBounds(); // how big is your butt?
192
int high = butt.y + butt.height + BIG*2 + SMALL;
194
setBounds((screen.width - wide) / 2,
195
(screen.height - high) / 2, wide, high);
197
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
198
addWindowListener(new WindowAdapter() {
199
public void windowClosing(WindowEvent e) {
203
Base.registerWindowCloseKeys(getRootPane(), new ActionListener() {
204
public void actionPerformed(ActionEvent actionEvent) {
211
// hack to to get first field to focus properly on osx
212
addWindowListener(new WindowAdapter() {
213
public void windowActivated(WindowEvent e) {
214
//System.out.println("activating");
215
/*boolean ok =*/ findField.requestFocusInWindow();
216
//System.out.println("got " + ok);
217
findField.selectAll();
223
public void handleClose() {
224
//System.out.println("handling close now");
225
findString = findField.getText();
226
replaceString = replaceField.getText();
228
// this object should eventually become dereferenced
235
findField.requestFocusInWindow();
237
//findField.selectAll();
238
//findField.requestFocus();
243
public void actionPerformed(ActionEvent e) {
244
Object source = e.getSource();
246
if (source == findButton) {
249
} else if (source == replaceFindButton) {
253
} else if (source == replaceButton) {
256
} else if (source == replaceAllButton) {
262
// look for the next instance of the find string
263
// to be found later than the current caret selection
265
// once found, select it (and go to that line)
267
public void find(boolean wrap) {
268
// in case search len is zero,
269
// otherwise replace all will go into an infinite loop
272
String search = findField.getText();
273
//System.out.println("finding for " + search + " " + findString);
274
// this will catch "find next" being called when no search yet
275
if (search.length() == 0) return;
277
String text = editor.getText();
280
search = search.toLowerCase();
281
text = text.toLowerCase();
284
//int selectionStart = editor.textarea.getSelectionStart();
285
int selectionEnd = editor.getSelectionStop();
287
int nextIndex = text.indexOf(search, selectionEnd);
288
if (nextIndex == -1) {
290
// if wrapping, a second chance is ok, start from beginning
291
nextIndex = text.indexOf(search, 0);
294
if (nextIndex == -1) {
296
replaceButton.setEnabled(false);
297
replaceFindButton.setEnabled(false);
298
//Toolkit.getDefaultToolkit().beep();
303
replaceButton.setEnabled(true);
304
replaceFindButton.setEnabled(true);
305
editor.setSelection(nextIndex, nextIndex + search.length());
310
* Replace the current selection with whatever's in the
311
* replacement text field.
313
public void replace() {
314
if (!found) return; // don't replace if nothing found
316
// check to see if the document has wrapped around
317
// otherwise this will cause an infinite loop
318
String sel = editor.getSelectedText();
319
if (sel.equals(replaceField.getText())) {
321
replaceButton.setEnabled(false);
322
replaceFindButton.setEnabled(false);
326
editor.setSelectedText(replaceField.getText());
327
//editor.setSketchModified(true);
328
//editor.sketch.setCurrentModified(true);
329
editor.getSketch().setModified(true); // TODO is this necessary?
331
// don't allow a double replace
332
replaceButton.setEnabled(false);
333
replaceFindButton.setEnabled(false);
338
* Replace everything that matches by doing find and replace
339
* alternately until nothing more found.
341
public void replaceAll() {
342
// move to the beginning
343
editor.setSelection(0, 0);