001: /*
002: * ReplaceDialog.java
003: *
004: * Copyright (C) 1998-2003 Peter Graves
005: * $Id: ReplaceDialog.java,v 1.5 2003/10/13 23:51:19 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: import gnu.regexp.REException;
025: import java.awt.Dimension;
026: import java.awt.Point;
027: import java.awt.event.ActionEvent;
028: import java.awt.event.TextEvent;
029: import java.awt.event.TextListener;
030: import javax.swing.Box;
031: import javax.swing.BoxLayout;
032: import javax.swing.JPanel;
033: import javax.swing.undo.CompoundEdit;
034:
035: public final class ReplaceDialog extends AbstractDialog implements
036: Constants, TextListener {
037: private static final String FIND_PATTERN = "find.pattern";
038: private static final String REPLACE_REPLACEMENT = "replace.replacement";
039: private static final String REPLACE_IGNORE_CASE = "replace.ignoreCase";
040: private static final String REPLACE_REGULAR_EXPRESSION = "replace.regularExpression";
041: private static final String REPLACE_MULTILINE_PATTERN = "replace.multilinePattern";
042: private static final String REPLACE_CONFIRM_CHANGES = "replace.confirmChanges";
043: private static final String REPLACE_WHOLE_WORDS_ONLY = "replace.wholeWordsOnly";
044:
045: private final Editor editor;
046:
047: private Replacement replacement;
048:
049: private HistoryTextField patternControl;
050: private HistoryTextField replacementControl;
051:
052: private History patternHistory;
053: private History replacementHistory;
054:
055: // Options.
056: private CheckBox ignoreCaseCheckBox;
057: private CheckBox wholeWordsOnlyCheckBox;
058: private CheckBox regularExpressionCheckBox;
059: private CheckBox multilinePatternCheckBox;
060: private CheckBox restrictToSelectionCheckBox;
061: private CheckBox confirmChangesCheckBox;
062:
063: public ReplaceDialog() {
064: super (Editor.currentEditor(), "Replace", true);
065: editor = Editor.currentEditor();
066: replacement = new Replacement(editor);
067: patternControl = new HistoryTextField(20);
068: patternHistory = new History(FIND_PATTERN);
069: patternControl.setHistory(patternHistory);
070: // Pre-fill pattern control.
071: String s = editor.getCurrentText();
072: if (s != null)
073: patternControl.setText(s);
074: else
075: patternControl.recallLast();
076: patternControl.addTextListener(this );
077: replacementControl = new HistoryTextField(20);
078: replacementHistory = new History(REPLACE_REPLACEMENT);
079: replacementControl.setHistory(replacementHistory);
080: replacementControl.recallLast();
081: Label label = new Label("Pattern:");
082: label.setDisplayedMnemonic('P');
083: addLabelAndTextField(label, patternControl);
084: addVerticalStrut();
085: label = new Label("Replace with:");
086: label.setDisplayedMnemonic('E');
087: addLabelAndTextField(label, replacementControl);
088: addVerticalStrut();
089: SessionProperties sessionProperties = Editor
090: .getSessionProperties();
091: replacement.setIgnoreCase(sessionProperties.getBooleanProperty(
092: REPLACE_IGNORE_CASE, false));
093: ignoreCaseCheckBox = new CheckBox("Ignore case", replacement
094: .ignoreCase());
095: ignoreCaseCheckBox.setMnemonic('I');
096: addCheckBox(ignoreCaseCheckBox);
097: replacement.setWholeWordsOnly(sessionProperties
098: .getBooleanProperty(REPLACE_WHOLE_WORDS_ONLY, false));
099: wholeWordsOnlyCheckBox = new CheckBox("Whole words only",
100: replacement.wholeWordsOnly());
101: wholeWordsOnlyCheckBox.setMnemonic('W');
102: addCheckBox(wholeWordsOnlyCheckBox);
103: replacement.setRegularExpression(sessionProperties
104: .getBooleanProperty(REPLACE_REGULAR_EXPRESSION, false));
105: regularExpressionCheckBox = new CheckBox("Regular expression",
106: replacement.isRegularExpression());
107: regularExpressionCheckBox.setMnemonic('X');
108: regularExpressionCheckBox.addActionListener(this );
109: addCheckBox(regularExpressionCheckBox);
110: if (Editor.checkExperimental()) {
111: JPanel panel = new JPanel();
112: panel.setAlignmentX(LEFT_ALIGNMENT);
113: panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
114: panel.add(Box.createHorizontalStrut(17));
115: if (replacement.isRegularExpression()) {
116: replacement.setMultiline(sessionProperties
117: .getBooleanProperty(REPLACE_MULTILINE_PATTERN,
118: false));
119: } else
120: replacement.setMultiline(false);
121: multilinePatternCheckBox = new CheckBox(
122: "Multiline pattern (experimental)", replacement
123: .isMultilinePattern());
124: multilinePatternCheckBox.setMnemonic('M');
125: panel.add(multilinePatternCheckBox);
126: multilinePatternCheckBox.addKeyListener(this );
127: multilinePatternCheckBox
128: .setEnabled(regularExpressionCheckBox.isSelected());
129: mainPanel.add(panel);
130: }
131: restrictToSelectionCheckBox = new CheckBox(
132: "Restrict changes to selected text");
133: restrictToSelectionCheckBox.setMnemonic('R');
134: replacement.setConfirmChanges(sessionProperties
135: .getBooleanProperty(REPLACE_CONFIRM_CHANGES, true));
136: confirmChangesCheckBox = new CheckBox("Confirm changes",
137: replacement.confirmChanges());
138: confirmChangesCheckBox.setMnemonic('C');
139: if (restrictToSelectionCheckBox != null) {
140: setRestrictToSelectionDefault();
141: addCheckBox(restrictToSelectionCheckBox);
142: }
143: addCheckBox(confirmChangesCheckBox);
144: addVerticalStrut();
145: addOKCancel();
146: pack();
147: patternControl.requestFocus();
148: }
149:
150: public final Replacement getReplacement() {
151: return replacement;
152: }
153:
154: public void textValueChanged(TextEvent e) {
155: setRestrictToSelectionDefault();
156: }
157:
158: public void actionPerformed(ActionEvent e) {
159: final String cmd = e.getActionCommand();
160: if (cmd != null
161: && cmd.equals(regularExpressionCheckBox.getText())) {
162: if (multilinePatternCheckBox != null) {
163: boolean isRegExp = regularExpressionCheckBox
164: .isSelected();
165: if (!isRegExp)
166: multilinePatternCheckBox.setSelected(false);
167: multilinePatternCheckBox.setEnabled(isRegExp);
168: }
169: } else
170: super .actionPerformed(e);
171: }
172:
173: private void setRestrictToSelectionDefault() {
174: if (restrictToSelectionCheckBox == null)
175: return;
176: // Enable the checkbox if a selection is active.
177: boolean enabled = editor.getMark() != null
178: && !editor.isColumnSelection();
179: restrictToSelectionCheckBox.setEnabled(enabled);
180: // Normally the checkbox should be checked if a non-column selection
181: // is active.
182: boolean checked = enabled;
183: // But if the selection is on a single line, we try to be smarter...
184: if (checked) {
185: if (editor.getMark().getLine() == editor.getDot().getLine()) {
186: // Only handle the simple case; if the pattern is a regular
187: // expression, be conservative and leave the box checked.
188: if (!regularExpressionCheckBox.isSelected()) {
189: String pattern = patternControl.getText();
190: if (pattern != null) {
191: Region r = new Region(editor);
192: String selection = r.toString();
193: // If the pattern is identical to the selected text, or if
194: // the selected text isn't long enough to contain a match
195: // for the pattern, it makes no sense to restrict changes
196: // to the selected text, and we shouldn't check the box.
197: if (pattern.equals(selection))
198: checked = false;
199: else if (pattern.length() >= selection.length())
200: checked = false;
201: }
202: }
203: }
204: }
205: restrictToSelectionCheckBox.setSelected(checked);
206: }
207:
208: protected void ok() {
209: replacement.setPattern(patternControl.getText());
210: if (replacement.getPatternLength() == 0) {
211: editor.status("No pattern");
212: replacement = null;
213: dispose();
214: return;
215: }
216: replacement.setReplaceWith(replacementControl.getText());
217: replacement.setIgnoreCase(ignoreCaseCheckBox.isSelected());
218: replacement.setWholeWordsOnly(wholeWordsOnlyCheckBox
219: .isSelected());
220: replacement.setRegularExpression(regularExpressionCheckBox
221: .isSelected());
222: if (multilinePatternCheckBox != null) {
223: replacement.setMultiline(multilinePatternCheckBox
224: .isSelected());
225: // We don't allow the "Multiline pattern" checkbox to be checked
226: // unless the "Regular expression" checkbox is also checked.
227: if (multilinePatternCheckBox.isSelected())
228: if (!regularExpressionCheckBox.isSelected())
229: Debug.bug();
230: }
231: if (restrictToSelectionCheckBox != null)
232: replacement
233: .setRestrictToSelection(restrictToSelectionCheckBox
234: .isSelected());
235: replacement.setConfirmChanges(confirmChangesCheckBox
236: .isSelected());
237: if (replacement.isRegularExpression()) {
238: try {
239: replacement.setREFromPattern();
240: } catch (REException e) {
241: MessageDialog.showMessageDialog(editor, e.getMessage(),
242: "Error");
243: patternControl.requestFocus();
244: return;
245: }
246: }
247: patternHistory.append(replacement.getPattern());
248: patternHistory.save();
249: replacementHistory.append(replacement.getReplaceWith());
250: replacementHistory.save();
251: SessionProperties sessionProperties = Editor
252: .getSessionProperties();
253: sessionProperties.setBooleanProperty(REPLACE_IGNORE_CASE,
254: replacement.ignoreCase());
255: sessionProperties.setBooleanProperty(REPLACE_WHOLE_WORDS_ONLY,
256: replacement.wholeWordsOnly());
257: sessionProperties.setBooleanProperty(
258: REPLACE_REGULAR_EXPRESSION, replacement
259: .isRegularExpression());
260: sessionProperties.setBooleanProperty(REPLACE_MULTILINE_PATTERN,
261: replacement.isMultilinePattern());
262: sessionProperties.setBooleanProperty(REPLACE_CONFIRM_CHANGES,
263: replacement.confirmChanges());
264: sessionProperties.save();
265: dispose();
266: }
267:
268: protected void cancel() {
269: replacement = null;
270: dispose();
271: }
272:
273: public static void replace() {
274: final Editor editor = Editor.currentEditor();
275: if (!editor.checkReadOnly())
276: return;
277: if (editor.isColumnSelection()) {
278: editor.notSupportedForColumnSelections();
279: return;
280: }
281: ReplaceDialog d = new ReplaceDialog();
282: editor.centerDialog(d);
283: d.show();
284: if (d.cancelled())
285: return;
286: final Replacement replacement = d.getReplacement();
287: if (replacement == null)
288: return;
289: CompoundEdit compoundEdit = editor.beginCompoundEdit();
290: editor.addUndo(SimpleEdit.MOVE);
291: if (editor.getMark() != null) {
292: replacement.setRegion(new Region(editor));
293: editor.getDot().moveTo(replacement.getRegion().getBegin());
294: }
295: final Buffer buffer = editor.getBuffer();
296: if (replacement.confirmChanges()) {
297: Position pos = replacement.find(buffer, editor.getDot());
298: if (pos == null) {
299: editor.endCompoundEdit(compoundEdit);
300: editor.undo();
301: replacement.notFound(editor);
302: return;
303: }
304: editor.moveDotTo(pos);
305: editor.markFoundPattern(replacement);
306: editor.updateDisplay();
307: ConfirmReplacementDialog confirmDialog = new ConfirmReplacementDialog(
308: replacement, false);
309: // Center dialog at top of editor window.
310: Dimension parent = editor.getSize();
311: Dimension dialog = confirmDialog.getSize();
312: Point p = editor.getLocation();
313: p.translate((parent.width - dialog.width) / 2, 0);
314: confirmDialog.setLocation(p);
315: // Do all the replacements.
316: confirmDialog.show();
317: if (replacement.restrictToSelection()
318: && replacement.getRegion() != null) {
319: // Leave selection marked as before.
320: editor.addUndo(SimpleEdit.MOVE);
321: editor.setDot(replacement.getRegion().getBegin());
322: editor.moveCaretToDotCol();
323: editor.setMark(replacement.getRegion().getEnd());
324: editor.setUpdateFlag(REPAINT);
325: } else {
326: editor.unmark();
327: editor.moveCaretToDotCol();
328: }
329: } else {
330: // Not confirming changes.
331: Position saved = new Position(editor.getDot());
332: Position pos;
333: while ((pos = replacement.find(buffer, editor.getDot())) != null) {
334: editor.addUndo(SimpleEdit.MOVE);
335: editor.getDot().moveTo(pos);
336: if (replacement.isMultilinePattern())
337: editor.markFoundPattern(replacement);
338: replacement.replaceOccurrence();
339: }
340: if (replacement.restrictToSelection()
341: && replacement.getRegion() != null) {
342: editor.addUndo(SimpleEdit.MOVE);
343: editor.setDot(replacement.getRegion().getBegin());
344: editor.moveCaretToDotCol();
345: editor.setMark(replacement.getRegion().getEnd());
346: } else {
347: editor.addUndo(SimpleEdit.MOVE);
348: editor.setDot(saved);
349: editor.setMark(null);
350: editor.moveCaretToDotCol();
351: }
352: editor.getDisplay().setUpdateFlag(REPAINT);
353: if (replacement.getReplacementCount() == 0)
354: replacement.notFound(editor);
355: }
356: editor.endCompoundEdit(compoundEdit);
357: int replacementCount = replacement.getReplacementCount();
358: if (replacementCount == 0) {
359: editor.undo();
360: } else {
361: FastStringBuffer sb = new FastStringBuffer(String
362: .valueOf(replacementCount));
363: sb.append(" occurrence");
364: if (replacementCount > 1)
365: sb.append('s');
366: sb.append(" replaced");
367: editor.status(sb.toString());
368: }
369: }
370: }
|