diff --git a/app/src/cc/arduino/view/findreplace/FindReplace.form b/app/src/cc/arduino/view/findreplace/FindReplace.form new file mode 100644 index 000000000..3c89f59b0 --- /dev/null +++ b/app/src/cc/arduino/view/findreplace/FindReplace.form @@ -0,0 +1,196 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/app/src/cc/arduino/view/findreplace/FindReplace.java b/app/src/cc/arduino/view/findreplace/FindReplace.java new file mode 100644 index 000000000..881774e24 --- /dev/null +++ b/app/src/cc/arduino/view/findreplace/FindReplace.java @@ -0,0 +1,460 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.view.findreplace; + +import processing.app.Base; +import processing.app.Editor; +import processing.app.Sketch; +import processing.app.helpers.OSUtils; + +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.HashMap; +import java.util.Map; + +import static processing.app.I18n._; + +public class FindReplace extends javax.swing.JFrame { + + private static final String FIND_TEXT = "findText"; + private static final String REPLACE_TEXT = "replaceText"; + private static final String IGNORE_CASE = "ignoreCase"; + private static final String SEARCH_ALL_FILES = "searchAllFiles"; + private static final String WRAP_AROUND = "wrapAround"; + + private final Editor editor; + + public FindReplace(Editor editor, Map state) { + this.editor = editor; + + initComponents(); + + if (OSUtils.isMacOS()) { + buttonsContainer.removeAll(); + buttonsContainer.add(replaceAllButton); + buttonsContainer.add(replaceButton); + buttonsContainer.add(replaceFindButton); + buttonsContainer.add(previousButton); + buttonsContainer.add(findButton); + } + + getRootPane().setDefaultButton(findButton); + + Base.registerWindowCloseKeys(getRootPane(), new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setVisible(false); + Base.FIND_DIALOG_STATE = findDialogState(); + } + }); + + Base.setIcon(this); + + addWindowListener(new WindowAdapter() { + public void windowActivated(WindowEvent e) { + findField.requestFocusInWindow(); + findField.selectAll(); + } + }); + + restoreFindDialogState(state); + } + + private Map findDialogState() { + Map state = new HashMap(); + state.put(FIND_TEXT, findField.getText()); + state.put(REPLACE_TEXT, replaceField.getText()); + state.put(IGNORE_CASE, ignoreCaseBox.isSelected()); + state.put(WRAP_AROUND, wrapAroundBox.isSelected()); + state.put(SEARCH_ALL_FILES, searchAllFilesBox.isSelected()); + return state; + } + + private void restoreFindDialogState(Map state) { + if (state.containsKey(FIND_TEXT)) { + findField.setText((String) state.get(FIND_TEXT)); + } + if (state.containsKey(REPLACE_TEXT)) { + replaceField.setText((String) state.get(REPLACE_TEXT)); + } + if (state.containsKey(IGNORE_CASE)) { + ignoreCaseBox.setSelected((Boolean) state.get(IGNORE_CASE)); + } + if (state.containsKey(SEARCH_ALL_FILES)) { + searchAllFilesBox.setSelected((Boolean) state.get(SEARCH_ALL_FILES)); + } + if (state.containsKey(WRAP_AROUND)) { + wrapAroundBox.setSelected((Boolean) state.get(WRAP_AROUND)); + } + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.JLabel findLabel = new javax.swing.JLabel(); + findField = new javax.swing.JTextField(); + javax.swing.JLabel replaceLabel = new javax.swing.JLabel(); + replaceField = new javax.swing.JTextField(); + ignoreCaseBox = new javax.swing.JCheckBox(); + wrapAroundBox = new javax.swing.JCheckBox(); + searchAllFilesBox = new javax.swing.JCheckBox(); + buttonsContainer = new javax.swing.JPanel(); + findButton = new javax.swing.JButton(); + previousButton = new javax.swing.JButton(); + replaceFindButton = new javax.swing.JButton(); + replaceButton = new javax.swing.JButton(); + replaceAllButton = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setTitle(_("Find")); + + findLabel.setText(_("Find:")); + + findField.setColumns(20); + + replaceLabel.setText(_("Replace with:")); + + replaceField.setColumns(20); + + ignoreCaseBox.setSelected(true); + ignoreCaseBox.setText(_("Ignore Case")); + + wrapAroundBox.setSelected(true); + wrapAroundBox.setText(_("Wrap Around")); + + searchAllFilesBox.setText(_("Search all Sketch Tabs")); + + findButton.setText(_("Find")); + findButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + findButtonActionPerformed(evt); + } + }); + buttonsContainer.add(findButton); + + previousButton.setText(_("Previous")); + previousButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + previousButtonActionPerformed(evt); + } + }); + buttonsContainer.add(previousButton); + + replaceFindButton.setText(_("Replace & Find")); + replaceFindButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + replaceFindButtonActionPerformed(evt); + } + }); + buttonsContainer.add(replaceFindButton); + + replaceButton.setText(_("Replace")); + replaceButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + replaceButtonActionPerformed(evt); + } + }); + buttonsContainer.add(replaceButton); + + replaceAllButton.setText(_("Replace All")); + replaceAllButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + replaceAllButtonActionPerformed(evt); + } + }); + buttonsContainer.add(replaceAllButton); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(replaceLabel) + .addComponent(findLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(findField) + .addComponent(replaceField) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(searchAllFilesBox) + .addComponent(wrapAroundBox) + .addComponent(ignoreCaseBox)) + .addGap(0, 0, Short.MAX_VALUE)))) + .addComponent(buttonsContainer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(findLabel) + .addComponent(findField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(replaceLabel) + .addComponent(replaceField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ignoreCaseBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(wrapAroundBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(searchAllFilesBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonsContainer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void findButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_findButtonActionPerformed + findNext(); + }//GEN-LAST:event_findButtonActionPerformed + + private void previousButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_previousButtonActionPerformed + findPrevious(); + }//GEN-LAST:event_previousButtonActionPerformed + + private void replaceFindButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_replaceFindButtonActionPerformed + replaceAndFindNext(); + }//GEN-LAST:event_replaceFindButtonActionPerformed + + private void replaceButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_replaceButtonActionPerformed + replace(); + }//GEN-LAST:event_replaceButtonActionPerformed + + private void replaceAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_replaceAllButtonActionPerformed + replaceAll(); + }//GEN-LAST:event_replaceAllButtonActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel buttonsContainer; + private javax.swing.JButton findButton; + private javax.swing.JTextField findField; + private javax.swing.JCheckBox ignoreCaseBox; + private javax.swing.JButton previousButton; + private javax.swing.JButton replaceAllButton; + private javax.swing.JButton replaceButton; + private javax.swing.JTextField replaceField; + private javax.swing.JButton replaceFindButton; + private javax.swing.JCheckBox searchAllFilesBox; + private javax.swing.JCheckBox wrapAroundBox; + // End of variables declaration//GEN-END:variables + + private boolean find(boolean wrap, boolean backwards, boolean searchTabs, int originTab) { + boolean wrapNeeded = false; + String search = findField.getText(); + + if (search.length() == 0) { + return false; + } + + String text = editor.getText(); + + if (ignoreCaseBox.isSelected()) { + search = search.toLowerCase(); + text = text.toLowerCase(); + } + + int nextIndex; + if (!backwards) { + // int selectionStart = editor.textarea.getSelectionStart(); + int selectionEnd = editor.getSelectionStop(); + + nextIndex = text.indexOf(search, selectionEnd); + if (wrap && nextIndex == -1) { + // if wrapping, a second chance is ok, start from beginning + wrapNeeded = true; + } + } else { + // int selectionStart = editor.textarea.getSelectionStart(); + int selectionStart = editor.getSelectionStart() - 1; + + if (selectionStart >= 0) { + nextIndex = text.lastIndexOf(search, selectionStart); + } else { + nextIndex = -1; + } + if (wrap && nextIndex == -1) { + // if wrapping, a second chance is ok, start from the end + wrapNeeded = true; + } + } + + if (nextIndex == -1) { + // Nothing found on this tab: Search other tabs if required + if (searchTabs) { + // editor. + Sketch sketch = editor.getSketch(); + if (sketch.getCodeCount() > 1) { + int realCurrentTab = sketch.getCodeIndex(sketch.getCurrentCode()); + + if (originTab != realCurrentTab) { + if (originTab < 0) { + originTab = realCurrentTab; + } + + if (!wrap) { + if ((!backwards && realCurrentTab + 1 >= sketch.getCodeCount()) || (backwards && realCurrentTab - 1 < 0)) { + return false; // Can't continue without wrap + } + } + + if (backwards) { + sketch.handlePrevCode(); + this.setVisible(true); + int l = editor.getText().length() - 1; + editor.setSelection(l, l); + } else { + sketch.handleNextCode(); + this.setVisible(true); + editor.setSelection(0, 0); + } + + return find(wrap, backwards, true, originTab); + } + } + } + + if (wrapNeeded) { + nextIndex = backwards ? text.lastIndexOf(search) : text.indexOf(search, 0); + } + } + + if (nextIndex != -1) { + editor.setSelection(nextIndex, nextIndex + search.length()); + return true; + } + + return false; + } + + /** + * Replace the current selection with whatever's in the replacement text + * field. + */ + private void replace() { + if (findField.getText().length() == 0) { + return; + } + + int newpos = editor.getSelectionStart() - findField.getText().length(); + if (newpos < 0) { + newpos = 0; + } + editor.setSelection(newpos, newpos); + + boolean foundAtLeastOne = false; + + if (find(false, false, searchAllFilesBox.isSelected(), -1)) { + foundAtLeastOne = true; + editor.setSelectedText(replaceField.getText()); + editor.getSketch().setModified(true); // TODO is this necessary? + } + + if (!foundAtLeastOne) { + Toolkit.getDefaultToolkit().beep(); + } + + } + + /** + * Replace the current selection with whatever's in the replacement text + * field, and then find the next match + */ + private void replaceAndFindNext() { + replace(); + findNext(); + } + + /** + * Replace everything that matches by doing find and replace alternately until + * nothing more found. + */ + private void replaceAll() { + if (findField.getText().length() == 0) { + return; + } + + if (searchAllFilesBox.isSelected()) { + editor.getSketch().setCurrentCode(0); // select the first tab + } + + editor.setSelection(0, 0); // move to the beginning + + boolean foundAtLeastOne = false; + while (true) { + if (find(false, false, searchAllFilesBox.isSelected(), -1)) { + foundAtLeastOne = true; + editor.setSelectedText(replaceField.getText()); + editor.getSketch().setModified(true); // TODO is this necessary? + } else { + break; + } + } + if (!foundAtLeastOne) { + Toolkit.getDefaultToolkit().beep(); + } + } + + public void findNext() { + if (!find(wrapAroundBox.isSelected(), false, searchAllFilesBox.isSelected(), -1)) { + Toolkit.getDefaultToolkit().beep(); + } + } + + public void findPrevious() { + if (!find(wrapAroundBox.isSelected(), true, searchAllFilesBox.isSelected(), -1)) { + Toolkit.getDefaultToolkit().beep(); + } + } + + public void setFindText(String text) { + if (text == null) { + return; + } + findField.setText(text); + } +} diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index a6c635f5b..2b0cbadfa 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -92,6 +92,7 @@ public class Base { public static volatile Base INSTANCE; public static SplashScreenHelper splashScreenHelper = new SplashScreenHelper(SplashScreen.getSplashScreen()); + public static Map FIND_DIALOG_STATE = new HashMap(); // set to true after the first time the menu is built. // so that the errors while building don't show up again. diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index c774afbb5..f4cea1d3d 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -25,6 +25,7 @@ package processing.app; import cc.arduino.packages.MonitorFactory; import cc.arduino.view.StubMenuListener; +import cc.arduino.view.findreplace.FindReplace; import com.google.common.base.Predicate; import com.jcraft.jsch.JSchException; import jssc.SerialPortException; @@ -1446,7 +1447,7 @@ public class Editor extends JFrame implements RunnerListener { findItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (find == null) { - find = new FindReplace(Editor.this); + find = new FindReplace(Editor.this, Base.FIND_DIALOG_STATE); } if (!OSUtils.isMacOS()) { find.setFindText(getSelectedText()); @@ -1482,7 +1483,7 @@ public class Editor extends JFrame implements RunnerListener { useSelectionForFindItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (find == null) { - find = new FindReplace(Editor.this); + find = new FindReplace(Editor.this, Base.FIND_DIALOG_STATE); } find.setFindText(getSelectedText()); } diff --git a/app/src/processing/app/FindReplace.java b/app/src/processing/app/FindReplace.java deleted file mode 100644 index 116d8fa5c..000000000 --- a/app/src/processing/app/FindReplace.java +++ /dev/null @@ -1,465 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2004-08 Ben Fry and Casey Reas - Copyright (c) 2001-04 Massachusetts Institute of Technology - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -package processing.app; -import static processing.app.I18n._; - -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; -import javax.swing.border.Border; - -import processing.app.helpers.OSUtils; - - -/** - * Find & Replace window for the Processing editor. - *

- * One major annoyance in this is that the window is re-created each time - * that "Find" is called. This is because Mac OS X has a strange focus - * issue with windows that are re-shown with setVisible() or show(). - * requestFocusInWindow() properly sets the focus to the find field, - * however, just a short moment later, the focus is set to null. Even - * trying to catch this scenario and request it again doesn't seem to work. - * Most likely this is some annoyance buried deep in one of Apple's docs, - * or in the doc for the focus stuff (I tend to think the former because - * Windows doesn't seem to be quite so beligerent). Filed as - * Bug 244 - * should anyone have clues about how to fix. - */ -@SuppressWarnings("serial") -public class FindReplace extends JFrame implements ActionListener { - - private Editor editor; - - private JTextField findField; - private JTextField replaceField; - private static String findString; - private static String replaceString; - - private JButton replaceButton; - private JButton replaceAllButton; - private JButton replaceFindButton; - private JButton previousButton; - private JButton findButton; - - private JCheckBox ignoreCaseBox; - private static boolean ignoreCase = true; - - private JCheckBox wrapAroundBox; - private static boolean wrapAround = true; - - private JCheckBox searchAllFilesBox; - private static boolean searchAllFiles = false; - - public FindReplace(Editor editor) { - super(_("Find")); - this.editor = editor; - - JPanel contentPanel = new JPanel(); - Border padding = BorderFactory.createEmptyBorder(10, 10, 10, 10); - contentPanel.setBorder(padding); - setContentPane(contentPanel); - - JLabel findLabel = new JLabel(_("Find:")); - findField = new JTextField(20); - JLabel replaceLabel = new JLabel(_("Replace with:")); - replaceField = new JTextField(20); - - // Fill the findString with selected text if no previous value - if (editor.getSelectedText() != null - && editor.getSelectedText().length() > 0) - findString = editor.getSelectedText(); - - if (findString != null) - findField.setText(findString); - if (replaceString != null) - replaceField.setText(replaceString); - - ignoreCaseBox = new JCheckBox(_("Ignore Case")); - ignoreCaseBox.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - ignoreCase = ignoreCaseBox.isSelected(); - } - }); - ignoreCaseBox.setSelected(ignoreCase); - - wrapAroundBox = new JCheckBox(_("Wrap Around")); - wrapAroundBox.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - wrapAround = wrapAroundBox.isSelected(); - } - }); - wrapAroundBox.setSelected(wrapAround); - - searchAllFilesBox = new JCheckBox(_("Search all Sketch Tabs")); - searchAllFilesBox.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - searchAllFiles = searchAllFilesBox.isSelected(); - } - }); - searchAllFilesBox.setSelected(searchAllFiles); - - JPanel checkboxPanel = new JPanel(); - checkboxPanel.setLayout(new BoxLayout(checkboxPanel, BoxLayout.PAGE_AXIS)); - checkboxPanel.add(ignoreCaseBox); - checkboxPanel.add(Box.createRigidArea(new Dimension(8, 0))); - checkboxPanel.add(wrapAroundBox); - checkboxPanel.add(Box.createRigidArea(new Dimension(8, 0))); - checkboxPanel.add(searchAllFilesBox); - - replaceAllButton = new JButton(_("Replace All")); - replaceAllButton.addActionListener(this); - replaceButton = new JButton(_("Replace")); - replaceButton.addActionListener(this); - replaceFindButton = new JButton(_("Replace & Find")); - replaceFindButton.addActionListener(this); - previousButton = new JButton(_("Previous")); - previousButton.addActionListener(this); - findButton = new JButton(_("Find")); - findButton.addActionListener(this); - - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS)); - - // ordering of buttons is different on mac versus pc - if (OSUtils.isMacOS()) { - buttonPanel.add(replaceAllButton); - buttonPanel.add(Box.createRigidArea(new Dimension(8, 0))); - buttonPanel.add(replaceButton); - buttonPanel.add(Box.createRigidArea(new Dimension(8, 0))); - buttonPanel.add(replaceFindButton); - buttonPanel.add(Box.createRigidArea(new Dimension(8, 0))); - buttonPanel.add(previousButton); - buttonPanel.add(Box.createRigidArea(new Dimension(8, 0))); - buttonPanel.add(findButton); - - } else { - buttonPanel.add(findButton); - buttonPanel.add(Box.createRigidArea(new Dimension(8, 0))); - buttonPanel.add(previousButton); // is this the right position for - // non-Mac? - buttonPanel.add(Box.createRigidArea(new Dimension(8, 0))); - buttonPanel.add(replaceFindButton); - buttonPanel.add(Box.createRigidArea(new Dimension(8, 0))); - buttonPanel.add(replaceButton); - buttonPanel.add(Box.createRigidArea(new Dimension(8, 0))); - buttonPanel.add(replaceAllButton); - } - - // to fix ugliness.. normally macosx java 1.3 puts an - // ugly white border around this object, so turn it off. - if (OSUtils.isMacOS()) { - buttonPanel.setBorder(null); - } - - // Put all components onto the dialog window - GridBagLayout searchLayout = new GridBagLayout(); - GridBagConstraints gbc = new GridBagConstraints(); - Container pane = getContentPane(); - pane.setLayout(searchLayout); - - gbc.insets = new Insets(4, 4, 4, 4); - gbc.gridx = 0; - gbc.weightx = 0.0; - gbc.weighty = 0.0; - gbc.fill = GridBagConstraints.NONE; - gbc.anchor = GridBagConstraints.LINE_END; - pane.add(findLabel, gbc); - gbc.gridx = 1; - gbc.weightx = 1.0; - gbc.fill = GridBagConstraints.HORIZONTAL; - gbc.anchor = GridBagConstraints.LINE_START; - pane.add(findField, gbc); - gbc.gridx = 0; - gbc.gridy = 1; - gbc.weightx = 0.0; - gbc.fill = GridBagConstraints.NONE; - gbc.anchor = GridBagConstraints.LINE_END; - pane.add(replaceLabel, gbc); - gbc.gridx = 1; - gbc.weightx = 1.0; - gbc.fill = GridBagConstraints.HORIZONTAL; - gbc.anchor = GridBagConstraints.LINE_START; - pane.add(replaceField, gbc); - gbc.gridx = 1; - gbc.gridy = 2; - gbc.weighty = 0.0; - gbc.fill = GridBagConstraints.NONE; - pane.add(checkboxPanel, gbc); - gbc.anchor = GridBagConstraints.CENTER; - gbc.gridwidth = 2; - gbc.gridx = 0; - gbc.gridy = 3; - gbc.insets = new Insets(12, 4, 4, 4); - pane.add(buttonPanel, gbc); - - pack(); - setResizable(false); - // centers the dialog on thew screen - setLocationRelativeTo(null); - - // make the find button the blinky default - getRootPane().setDefaultButton(findButton); - - setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - handleClose(); - } - }); - Base.registerWindowCloseKeys(getRootPane(), new ActionListener() { - public void actionPerformed(ActionEvent actionEvent) { - // hide(); - handleClose(); - } - }); - Base.setIcon(this); - - // hack to to get first field to focus properly on osx - addWindowListener(new WindowAdapter() { - public void windowActivated(WindowEvent e) { - // System.out.println("activating"); - /* boolean ok = */findField.requestFocusInWindow(); - // System.out.println("got " + ok); - findField.selectAll(); - } - }); - } - - public void handleClose() { - // System.out.println("handling close now"); - findString = findField.getText(); - replaceString = replaceField.getText(); - - // this object should eventually become dereferenced - setVisible(false); - } - - /* - public void show() { - findField.requestFocusInWindow(); - super.show(); - //findField.selectAll(); - //findField.requestFocus(); - } - */ - - - public void actionPerformed(ActionEvent e) { - Object source = e.getSource(); - - if (source == findButton) { - findNext(); - - } else if (source == previousButton) { - findPrevious(); - - } else if (source == replaceFindButton) { - replaceAndFindNext(); - - } else if (source == replaceButton) { - replace(); - - } else if (source == replaceAllButton) { - replaceAll(); - } - } - - // look for the next instance of the find string to be found - // once found, select it (and go to that line) - - private boolean find(boolean wrap, boolean backwards, boolean searchTabs, - int originTab) { - // System.out.println("Find: " + originTab); - boolean wrapNeeded = false; - String search = findField.getText(); - // System.out.println("finding for " + search + " " + findString); - // this will catch "find next" being called when no search yet - if (search.length() == 0) - return false; - - String text = editor.getText(); - - if (ignoreCase) { - search = search.toLowerCase(); - text = text.toLowerCase(); - } - - int nextIndex; - if (!backwards) { - // int selectionStart = editor.textarea.getSelectionStart(); - int selectionEnd = editor.getSelectionStop(); - - nextIndex = text.indexOf(search, selectionEnd); - if (wrap && nextIndex == -1) { - // if wrapping, a second chance is ok, start from beginning - wrapNeeded = true; - } - } else { - // int selectionStart = editor.textarea.getSelectionStart(); - int selectionStart = editor.getSelectionStart() - 1; - - if (selectionStart >= 0) { - nextIndex = text.lastIndexOf(search, selectionStart); - } else { - nextIndex = -1; - } - if (wrap && nextIndex == -1) { - // if wrapping, a second chance is ok, start from the end - wrapNeeded = true; - } - } - - if (nextIndex == -1) { - // Nothing found on this tab: Search other tabs if required - if (searchTabs) { - // editor. - Sketch sketch = editor.getSketch(); - if (sketch.getCodeCount() > 1) { - int realCurrentTab = sketch.getCodeIndex(sketch.getCurrentCode()); - - if (originTab != realCurrentTab) { - if (originTab < 0) - originTab = realCurrentTab; - - if (!wrap) - if ((!backwards && realCurrentTab + 1 >= sketch.getCodeCount()) - || (backwards && realCurrentTab - 1 < 0)) - return false; // Can't continue without wrap - - if (backwards) { - sketch.handlePrevCode(); - this.setVisible(true); - int l = editor.getText().length() - 1; - editor.setSelection(l, l); - } else { - sketch.handleNextCode(); - this.setVisible(true); - editor.setSelection(0, 0); - } - - return find(wrap, backwards, searchTabs, originTab); - } - } - } - - if (wrapNeeded) - nextIndex = backwards ? text.lastIndexOf(search) : text.indexOf(search, - 0); - } - - if (nextIndex != -1) { - editor.setSelection(nextIndex, nextIndex + search.length()); - return true; - } - - return false; - } - - /** - * Replace the current selection with whatever's in the replacement text - * field. - */ - public void replace() { - if (findField.getText().length() == 0) - return; - - int newpos = editor.getSelectionStart() - findField.getText().length(); - if (newpos < 0) - newpos = 0; - editor.setSelection(newpos, newpos); - - boolean foundAtLeastOne = false; - - if (find(false, false, searchAllFiles, -1)) { - foundAtLeastOne = true; - editor.setSelectedText(replaceField.getText()); - editor.getSketch().setModified(true); // TODO is this necessary? - } - - if (!foundAtLeastOne) { - Toolkit.getDefaultToolkit().beep(); - } - - } - - /** - * Replace the current selection with whatever's in the replacement text - * field, and then find the next match - */ - public void replaceAndFindNext() { - replace(); - findNext(); - } - - /** - * Replace everything that matches by doing find and replace alternately until - * nothing more found. - */ - public void replaceAll() { - if (findField.getText().length() == 0) - return; - - if (searchAllFiles) - editor.getSketch().setCurrentCode(0); // select the first tab - - editor.setSelection(0, 0); // move to the beginning - - boolean foundAtLeastOne = false; - while (true) { - if (find(false, false, searchAllFiles, -1)) { - foundAtLeastOne = true; - editor.setSelectedText(replaceField.getText()); - editor.getSketch().setModified(true); // TODO is this necessary? - } else { - break; - } - } - if (!foundAtLeastOne) { - Toolkit.getDefaultToolkit().beep(); - } - } - - public void setFindText(String text) { - if (text == null) { - return; - } - findField.setText(text); - findString = text; - } - - public void findNext() { - if (!find(wrapAround, false, searchAllFiles, -1)) { - Toolkit.getDefaultToolkit().beep(); - } - } - - public void findPrevious() { - if (!find(wrapAround, true, searchAllFiles, -1)) { - Toolkit.getDefaultToolkit().beep(); - } - } - -}