001: package tide.sources;
002:
003: import java.io.File;
004: import javax.swing.border.EmptyBorder;
005: import tide.editor.MainEditorFrame;
006: import java.awt.Color;
007: import java.awt.FlowLayout;
008: import java.util.*;
009: import snow.texteditor.*;
010: import tide.editor.Accelerators;
011: import tide.sources.FileItem;
012: import tide.sources.TypeLocator;
013: import java.awt.BorderLayout;
014: import java.awt.event.*;
015: import javax.swing.*;
016: import snow.utils.gui.*;
017:
018: /** An interactive class rename dialog.
019: */
020: public class RenameDialog extends JDialog {
021: final private String oldPackageName, oldJavaSimpleName;
022: private final JTextField nameTF = new JTextField(16);
023: public final JCheckBox renameInsourceCB = new JCheckBox(
024: "Rename in source", true);
025: public final JCheckBox renameInProjectCB = new JCheckBox(
026: "Rename in project", true);
027: //TODO...
028: public final JCheckBox changePackageCB = new JCheckBox(
029: "Change package", false);
030: private final JTextField newPackageName = new JTextField(16);
031:
032: private final SimpleDocument doc = new SimpleDocument();
033: private final JTextPane explainPane = new JTextPane(doc);
034:
035: final private JLabel warningLabel = new JLabel("");
036: final private JTextArea warningArea = new JTextArea("");
037: private boolean hasErrors = false;
038:
039: private CloseControlPanel ccp;
040:
041: public RenameDialog(JFrame owner, SourceFile sf) {
042: super (owner, "Rename sourcefile " + sf.getJavaName() + " in "
043: + sf.getPackageName(), true);
044: this .oldPackageName = sf.getPackageName();
045: this .oldJavaSimpleName = sf.getJavaPartName();
046:
047: JPanel inputPanel = new JPanel();
048: inputPanel.setBorder(new EmptyBorder(4, 4, 4, 4));
049: inputPanel
050: .setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS));
051: add(inputPanel, BorderLayout.NORTH);
052:
053: add(new JScrollPane(explainPane), BorderLayout.CENTER);
054: explainPane.setEditable(false);
055: explainPane.setBackground(getBackground());
056:
057: JPanel input1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
058: input1.setAlignmentX(0f);
059: input1.setAlignmentY(0f);
060: inputPanel.add(input1);
061: input1.add(new JLabel("New name: "));
062: input1.add(nameTF);
063: nameTF.setText(oldJavaSimpleName);
064: input1.add(renameInsourceCB);
065: input1.add(renameInProjectCB);
066:
067: JPanel input2 = new JPanel(new FlowLayout(FlowLayout.LEFT));
068: input2.setAlignmentX(0f);
069: input2.setAlignmentY(0f);
070: if (false && MainEditorFrame.enableExperimental) {
071: inputPanel.add(input2);
072: }
073: input2.add(changePackageCB);
074: input2.add(newPackageName);
075: newPackageName.setText(sf.getPackageName());
076: changePackageCB.addActionListener(new ActionListener() {
077: public void actionPerformed(ActionEvent ae) {
078: newPackageName.setEnabled(changePackageCB.isSelected());
079: }
080: });
081: newPackageName.setEnabled(changePackageCB.isSelected());
082:
083: final JPanel classOptPanel = new JPanel();
084: classOptPanel.setAlignmentX(0f);
085: classOptPanel.setAlignmentY(0f);
086: classOptPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
087: inputPanel.add(classOptPanel);
088:
089: warningLabel.setAlignmentX(0f);
090: warningLabel.setAlignmentY(0f);
091: inputPanel.add(warningLabel);
092: //warningLabel.setHorizontalAlignment(JLabel.LEFT);
093:
094: warningArea.setAlignmentX(0f);
095: warningArea.setAlignmentY(0f);
096: inputPanel.add(warningArea);
097: warningArea.setEditable(false);
098: warningArea.setBackground(getBackground());
099:
100: warningArea
101: .setText(" WARNING: the rename function is NOT 100% clean."
102: + "\n It simply replaces the occurences of *old* with *new* where * is a non java character."
103: + "\n In doubt, please proceed manually using the search/replace function (Ctrl + F)."
104: + "\n Make a case-sensitive regex search with #njc(ClassName)#njc and use the replace function."
105: + "\nIMPORTANT: compile (Shift+F9) before and after the rename operation. Even better: F9 after."
106: + "\n Please also create sometimes backups of your project. Use the backup function in the tIDE file menu.");
107:
108: ccp = new CloseControlPanel(this , true, true, "Rename");
109: ccp.getOkButton().setIcon(Icons.sharedWiz);
110: add(ccp, BorderLayout.SOUTH);
111:
112: nameTF.addKeyListener(new KeyAdapter() {
113: @Override
114: public void keyReleased(KeyEvent ke) {
115: checkNameValidity();
116:
117: if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
118: ccp.acceptAndClose();
119: }
120: }
121: });
122:
123: newPackageName.addKeyListener(new KeyAdapter() {
124: @Override
125: public void keyReleased(KeyEvent ke) {
126: checkNameValidity();
127: }
128: });
129:
130: analyseDependencies(sf);
131:
132: //this.pack();
133: this .setSize(600, 430);
134: // center it on the screen :
135: this .setLocationRelativeTo(owner);
136:
137: nameTF.requestFocusInWindow();
138:
139: ((JComponent) getContentPane()).registerKeyboardAction(
140: new ActionListener() {
141: public void actionPerformed(ActionEvent ae) {
142: ccp.cancelAndClose();
143: }
144: }, "Escape", Accelerators.escape,
145: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
146:
147: this .setVisible(true); // MODAL
148: }
149:
150: // if depending
151: public boolean getHasDependenciesErrors() {
152: return hasErrors;
153: }
154:
155: private void analyseDependencies(SourceFile sf) {
156: hasErrors = false;
157: Set<SourceFile> usedBy = sf.sourceFileDependencies
158: .getClassesUsingThis_REF_();
159: if (sf.sourceFileDependencies == null
160: || !sf.sourceFileDependencies.areDependenciesActual()) {
161: hasErrors = true;
162: doc
163: .appendError("Source dependencies are not actual, please update (F9 or Shift + F9) before renaming.\n");
164: if (sf.sourceFileDependencies == null)
165: return;
166: }
167:
168: if (usedBy.isEmpty()) {
169: doc
170: .appendLine("No dependencies, renaming will not be complicated...");
171: return;
172: }
173:
174: List<SourceFile> sfs = new ArrayList<SourceFile>(usedBy);
175: doc.appendLine("" + sfs.size() + " source"
176: + (sfs.size() == 1 ? " is" : "s are")
177: + " using the class to be renamed:");
178: boolean firstProblem = true;
179: for (SourceFile si : sfs) {
180: doc.append("\n " + si.getJavaName());
181: if (!si.isEditable()) {
182: doc.appendError(" not editable");
183: hasErrors = true;
184: if (firstProblem) {
185:
186: MainEditorFrame.instance.outputPanels
187: .selectToolsTab(true);
188: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
189: .appendErrorLine("\nRenaming temptative will fail due to:\n");
190: firstProblem = false;
191: }
192: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
193: .appendErrorLine(""
194: + si.getJavaName()
195: + ": is not editable. It should be to rename "
196: + sf.getJavaName());
197: }
198: }
199:
200: explainPane.setCaretPosition(0);
201: }
202:
203: public boolean wasAccepted() {
204: return ccp.getWasAccepted() && !ccp.getWasCancelled();
205: }
206:
207: public String getNewJavaSimpleName() {
208: return this .nameTF.getText().trim();
209: }
210:
211: public String getNewJavaFullName() {
212: String pn = newPackageName.getText().trim();
213: if (pn.length() > 0)
214: return pn + "." + getNewJavaSimpleName();
215: else
216: return getNewJavaSimpleName();
217: }
218:
219: /** Checks name and package validity.
220: */
221: public boolean checkNameValidity() {
222: warningLabel.setText("");
223: warningLabel.setForeground(Color.red);
224: nameTF
225: .setForeground(UIManager
226: .getColor("Textfield.foreground"));
227: newPackageName.setForeground(UIManager
228: .getColor("Textfield.foreground"));
229: String tf = nameTF.getText();
230: if (tf.length() == 0) {
231: nameTF.setForeground(Color.red);
232: return false;
233: }
234:
235: // avoid nil ops
236: if (tf.equals(oldJavaSimpleName)
237: && newPackageName.getText().equals(oldPackageName))
238: return false;
239:
240: //no, special case
241: // if(tf.equals("package-info")) return true;
242:
243: if (!Character.isJavaIdentifierStart(tf.charAt(0))) {
244: nameTF.setForeground(Color.red);
245: warningLabel.setText(" Error: Invalid Java first letter "
246: + tf.charAt(0));
247: return false;
248: }
249:
250: if (Character.isLowerCase(tf.charAt(0))) {
251: warningLabel
252: .setText(" Warning: First char of name should not be lowercase");
253: }
254:
255: for (int i = 1; i < tf.length(); i++) {
256: if (!Character.isJavaIdentifierPart(tf.charAt(i))) {
257: nameTF.setForeground(Color.red);
258: warningLabel.setText(" Error: Invalid Java letter "
259: + tf.charAt(i));
260: return false;
261: }
262: }
263:
264: FileItem fi = TypeLocator.locateQuick(getNewJavaFullName());
265: if (fi != null) {
266: nameTF.setForeground(Color.red);
267: warningLabel
268: .setText(" Error: a type with the same name already exists");
269: return false;
270: }
271:
272: File f = new File(MainEditorFrame.instance.sourcesTreePanel
273: .getTreeModel().getSourcesRoot(), getNewJavaFullName()
274: .replace('.', '/')
275: + ".java");
276:
277: if (f.exists()) {
278: nameTF.setForeground(Color.red);
279: warningLabel
280: .setText(" Error: a type with the same name (but other case) already exists");
281: return false;
282: }
283:
284: if (this .changePackageCB.isSelected()) {
285: //List<FileItem> ap = TypeLocator.locateAllPackages(newPackageName.getText());
286: FileItem pafi = MainEditorFrame.instance.sourcesTreePanel
287: .getTreeModel()
288: .getPackage(newPackageName.getText());
289: if (pafi == null) {
290: newPackageName.setForeground(Color.red);
291: warningLabel.setText(" Error: the package "
292: + newPackageName.getText()
293: + " doesn't exist. Please create it first.");
294: return false;
295: }
296: }
297:
298: return true;
299: }
300:
301: }
|