Line 0
Link Here
|
|
|
1 |
/* |
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
3 |
* |
4 |
* Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. |
5 |
* |
6 |
* Oracle and Java are registered trademarks of Oracle and/or its affiliates. |
7 |
* Other names may be trademarks of their respective owners. |
8 |
* |
9 |
* The contents of this file are subject to the terms of either the GNU |
10 |
* General Public License Version 2 only ("GPL") or the Common |
11 |
* Development and Distribution License("CDDL") (collectively, the |
12 |
* "License"). You may not use this file except in compliance with the |
13 |
* License. You can obtain a copy of the License at |
14 |
* http://www.netbeans.org/cddl-gplv2.html |
15 |
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the |
16 |
* specific language governing permissions and limitations under the |
17 |
* License. When distributing the software, include this License Header |
18 |
* Notice in each file and include the License file at |
19 |
* nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this |
20 |
* particular file as subject to the "Classpath" exception as provided |
21 |
* by Oracle in the GPL Version 2 section of the License file that |
22 |
* accompanied this code. If applicable, add the following below the |
23 |
* License Header, with the fields enclosed by brackets [] replaced by |
24 |
* your own identifying information: |
25 |
* "Portions Copyrighted [year] [name of copyright owner]" |
26 |
* |
27 |
* If you wish your version of this file to be governed by only the CDDL |
28 |
* or only the GPL Version 2, indicate your decision by adding |
29 |
* "[Contributor] elects to include this software in this distribution |
30 |
* under the [CDDL or GPL Version 2] license." If you do not indicate a |
31 |
* single choice of license, a recipient has the option to distribute |
32 |
* your version of this file under either the CDDL, the GPL Version 2 or |
33 |
* to extend the choice of license to its licensees as provided above. |
34 |
* However, if you add GPL Version 2 code and therefore, elected the GPL |
35 |
* Version 2 license, then the option applies only if the new code is |
36 |
* made subject to such option by the copyright holder. |
37 |
* |
38 |
* Contributor(s): |
39 |
*/ |
40 |
package org.netbeans.modules.php.dbgp.ui; |
41 |
|
42 |
import java.beans.PropertyChangeListener; |
43 |
import java.beans.PropertyChangeSupport; |
44 |
import java.io.File; |
45 |
import javax.swing.DefaultComboBoxModel; |
46 |
import javax.swing.JPanel; |
47 |
import javax.swing.SwingUtilities; |
48 |
import javax.swing.event.DocumentEvent; |
49 |
import javax.swing.event.DocumentListener; |
50 |
import org.netbeans.api.debugger.DebuggerManager; |
51 |
import org.netbeans.api.debugger.Properties; |
52 |
import org.netbeans.modules.php.dbgp.breakpoints.LineBreakpoint; |
53 |
import org.netbeans.modules.php.dbgp.breakpoints.Utils; |
54 |
import org.netbeans.spi.debugger.ui.Controller; |
55 |
import org.openide.DialogDisplayer; |
56 |
import org.openide.NotifyDescriptor; |
57 |
import org.openide.filesystems.FileObject; |
58 |
import org.openide.filesystems.FileUtil; |
59 |
import org.openide.text.Line; |
60 |
import org.openide.util.NbBundle; |
61 |
|
62 |
public class DbgpLineBreakpointCustomizerPanel extends JPanel implements ControllerProvider { |
63 |
|
64 |
private static final int MAX_SAVED_CONDITIONS = 10; |
65 |
private static final String BP_CONDITIONS = "BPConditions"; // NOI18N |
66 |
private static final String DEBUGGER_PHP = "debugger.php"; // NOI18N |
67 |
private static final long serialVersionUID = 6364512868561614302L; |
68 |
|
69 |
private final LineBreakpoint lineBreakpoint; |
70 |
private final Controller controller; |
71 |
private boolean createBreakpoint; |
72 |
|
73 |
private static LineBreakpoint createLineBreakpoint() { |
74 |
Line currentLine = Utils.getCurrentLine(); |
75 |
return createLineBreakpoint(currentLine); |
76 |
} |
77 |
|
78 |
private static LineBreakpoint createLineBreakpoint(Line line) { |
79 |
if (line != null) { |
80 |
return new LineBreakpoint(line); |
81 |
} |
82 |
return null; |
83 |
} |
84 |
|
85 |
public DbgpLineBreakpointCustomizerPanel() { |
86 |
this(createLineBreakpoint(), true); |
87 |
createBreakpoint = true; |
88 |
} |
89 |
|
90 |
public DbgpLineBreakpointCustomizerPanel(Line line) { |
91 |
this(createLineBreakpoint(line), true); |
92 |
createBreakpoint = true; |
93 |
} |
94 |
|
95 |
public DbgpLineBreakpointCustomizerPanel(LineBreakpoint lineBreakpoint) { |
96 |
this(lineBreakpoint, false); |
97 |
} |
98 |
|
99 |
private DbgpLineBreakpointCustomizerPanel(LineBreakpoint lineBreakpoint, boolean isEditable) { |
100 |
this.lineBreakpoint = lineBreakpoint; |
101 |
controller = createController(); |
102 |
initComponents(); |
103 |
|
104 |
DocumentListener defaultDocumentListener = new DocumentListener() { |
105 |
@Override |
106 |
public void insertUpdate(DocumentEvent e) { |
107 |
processUpdate(); |
108 |
} |
109 |
|
110 |
@Override |
111 |
public void removeUpdate(DocumentEvent e) { |
112 |
processUpdate(); |
113 |
} |
114 |
|
115 |
@Override |
116 |
public void changedUpdate(DocumentEvent e) { |
117 |
processUpdate(); |
118 |
} |
119 |
|
120 |
private void processUpdate() { |
121 |
((CustomizerController) controller).firePropertyChange(); |
122 |
} |
123 |
}; |
124 |
fileTextField.setEditable(isEditable); |
125 |
fileTextField.getDocument().addDocumentListener(defaultDocumentListener); |
126 |
lineNumberTextField.setEditable(isEditable); |
127 |
lineNumberTextField.getDocument().addDocumentListener(defaultDocumentListener); |
128 |
Object[] conditions = getSavedConditions(); |
129 |
conditionComboBox.setModel(new DefaultComboBoxModel(conditions)); |
130 |
|
131 |
if (lineBreakpoint != null) { |
132 |
Line line = lineBreakpoint.getLine(); |
133 |
FileObject fo = line.getLookup().lookup(FileObject.class); |
134 |
updateComponents(fo, line.getLineNumber() + 1, lineBreakpoint.getCondition()); |
135 |
} |
136 |
} |
137 |
|
138 |
private void updateComponents(FileObject fileObject, int lineNumber, String condition) { |
139 |
assert SwingUtilities.isEventDispatchThread(); |
140 |
if (fileObject != null) { |
141 |
File file = FileUtil.toFile(fileObject); |
142 |
if (file != null) { |
143 |
fileTextField.setText(file.getAbsolutePath()); |
144 |
} else { |
145 |
fileTextField.setText(fileObject.toURL().toExternalForm()); |
146 |
} |
147 |
} |
148 |
|
149 |
lineNumberTextField.setText(Integer.toString(lineNumber)); |
150 |
|
151 |
if (condition != null && !condition.isEmpty()) { |
152 |
conditionCheckBox.setSelected(true); |
153 |
conditionComboBox.setEnabled(true); |
154 |
conditionComboBox.getEditor().setItem(condition); |
155 |
} else { |
156 |
conditionCheckBox.setSelected(false); |
157 |
conditionComboBox.setEnabled(false); |
158 |
} |
159 |
} |
160 |
|
161 |
private static Object[] getSavedConditions() { |
162 |
return Properties.getDefault() |
163 |
.getProperties(DEBUGGER_PHP) |
164 |
.getArray(BP_CONDITIONS, new Object[0]); |
165 |
} |
166 |
|
167 |
private static void saveCondition(String condition) { |
168 |
Object[] savedConditions = getSavedConditions(); |
169 |
Object[] conditions = null; |
170 |
boolean containsCondition = false; |
171 |
for (int i = 0; i < savedConditions.length; i++) { |
172 |
Object c = savedConditions[i]; |
173 |
if (condition.equals(c)) { |
174 |
containsCondition = true; |
175 |
conditions = savedConditions; |
176 |
if (i > 0) { |
177 |
System.arraycopy(conditions, 0, conditions, 1, i); |
178 |
conditions[0] = condition; |
179 |
} |
180 |
break; |
181 |
} |
182 |
} |
183 |
if (!containsCondition) { |
184 |
if (savedConditions.length < MAX_SAVED_CONDITIONS) { |
185 |
conditions = new Object[savedConditions.length + 1]; |
186 |
conditions[0] = condition; |
187 |
System.arraycopy(savedConditions, 0, conditions, 1, savedConditions.length); |
188 |
} else { |
189 |
conditions = savedConditions; |
190 |
System.arraycopy(conditions, 0, conditions, 1, conditions.length - 1); |
191 |
conditions[0] = condition; |
192 |
} |
193 |
} |
194 |
Properties.getDefault() |
195 |
.getProperties(DEBUGGER_PHP) |
196 |
.setArray(BP_CONDITIONS, conditions); |
197 |
} |
198 |
|
199 |
private Controller createController() { |
200 |
return new CustomizerController(); |
201 |
} |
202 |
|
203 |
@Override |
204 |
public Controller getController() { |
205 |
return controller; |
206 |
} |
207 |
|
208 |
/** |
209 |
* This method is called from within the constructor to initialize the form. |
210 |
* WARNING: Do NOT modify this code. The content of this method is always |
211 |
* regenerated by the Form Editor. |
212 |
*/ |
213 |
@SuppressWarnings("unchecked") |
214 |
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents |
215 |
private void initComponents() { |
216 |
|
217 |
settingsPanel = new javax.swing.JPanel(); |
218 |
fileLabel = new javax.swing.JLabel(); |
219 |
lineNumberLabel = new javax.swing.JLabel(); |
220 |
fileTextField = new javax.swing.JTextField(); |
221 |
lineNumberTextField = new javax.swing.JTextField(); |
222 |
conditionPanel = new javax.swing.JPanel(); |
223 |
conditionCheckBox = new javax.swing.JCheckBox(); |
224 |
conditionComboBox = new javax.swing.JComboBox<>(); |
225 |
|
226 |
settingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(DbgpLineBreakpointCustomizerPanel.class, "LBL_Settings"))); // NOI18N |
227 |
|
228 |
org.openide.awt.Mnemonics.setLocalizedText(fileLabel, org.openide.util.NbBundle.getMessage(DbgpLineBreakpointCustomizerPanel.class, "DbgpLineBreakpointCustomizerPanel.fileLabel.text")); // NOI18N |
229 |
|
230 |
org.openide.awt.Mnemonics.setLocalizedText(lineNumberLabel, org.openide.util.NbBundle.getMessage(DbgpLineBreakpointCustomizerPanel.class, "DbgpLineBreakpointCustomizerPanel.lineNumberLabel.text")); // NOI18N |
231 |
|
232 |
fileTextField.setText(org.openide.util.NbBundle.getMessage(DbgpLineBreakpointCustomizerPanel.class, "DbgpLineBreakpointCustomizerPanel.fileTextField.text")); // NOI18N |
233 |
|
234 |
lineNumberTextField.setText(org.openide.util.NbBundle.getMessage(DbgpLineBreakpointCustomizerPanel.class, "DbgpLineBreakpointCustomizerPanel.lineNumberTextField.text")); // NOI18N |
235 |
|
236 |
javax.swing.GroupLayout settingsPanelLayout = new javax.swing.GroupLayout(settingsPanel); |
237 |
settingsPanel.setLayout(settingsPanelLayout); |
238 |
settingsPanelLayout.setHorizontalGroup( |
239 |
settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
240 |
.addGroup(settingsPanelLayout.createSequentialGroup() |
241 |
.addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
242 |
.addComponent(lineNumberLabel) |
243 |
.addComponent(fileLabel)) |
244 |
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) |
245 |
.addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
246 |
.addComponent(fileTextField) |
247 |
.addComponent(lineNumberTextField))) |
248 |
); |
249 |
settingsPanelLayout.setVerticalGroup( |
250 |
settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
251 |
.addGroup(settingsPanelLayout.createSequentialGroup() |
252 |
.addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) |
253 |
.addComponent(fileLabel) |
254 |
.addComponent(fileTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) |
255 |
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) |
256 |
.addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) |
257 |
.addComponent(lineNumberLabel) |
258 |
.addComponent(lineNumberTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) |
259 |
); |
260 |
|
261 |
conditionPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(DbgpLineBreakpointCustomizerPanel.class, "LBL_Condition"))); // NOI18N |
262 |
|
263 |
org.openide.awt.Mnemonics.setLocalizedText(conditionCheckBox, org.openide.util.NbBundle.getMessage(DbgpLineBreakpointCustomizerPanel.class, "DbgpLineBreakpointCustomizerPanel.conditionCheckBox.text")); // NOI18N |
264 |
conditionCheckBox.addActionListener(new java.awt.event.ActionListener() { |
265 |
public void actionPerformed(java.awt.event.ActionEvent evt) { |
266 |
conditionCheckBoxActionPerformed(evt); |
267 |
} |
268 |
}); |
269 |
|
270 |
conditionComboBox.setEditable(true); |
271 |
conditionComboBox.setToolTipText(org.openide.util.NbBundle.getMessage(DbgpLineBreakpointCustomizerPanel.class, "DbgpLineBreakpointCustomizerPanel.conditionComboBox.toolTipText")); // NOI18N |
272 |
|
273 |
javax.swing.GroupLayout conditionPanelLayout = new javax.swing.GroupLayout(conditionPanel); |
274 |
conditionPanel.setLayout(conditionPanelLayout); |
275 |
conditionPanelLayout.setHorizontalGroup( |
276 |
conditionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
277 |
.addGroup(conditionPanelLayout.createSequentialGroup() |
278 |
.addComponent(conditionCheckBox) |
279 |
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) |
280 |
.addComponent(conditionComboBox, 0, 281, Short.MAX_VALUE)) |
281 |
); |
282 |
conditionPanelLayout.setVerticalGroup( |
283 |
conditionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
284 |
.addGroup(conditionPanelLayout.createSequentialGroup() |
285 |
.addGap(0, 0, 0) |
286 |
.addGroup(conditionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) |
287 |
.addComponent(conditionCheckBox) |
288 |
.addComponent(conditionComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) |
289 |
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) |
290 |
); |
291 |
|
292 |
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); |
293 |
this.setLayout(layout); |
294 |
layout.setHorizontalGroup( |
295 |
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
296 |
.addComponent(settingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) |
297 |
.addComponent(conditionPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) |
298 |
); |
299 |
layout.setVerticalGroup( |
300 |
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
301 |
.addGroup(layout.createSequentialGroup() |
302 |
.addComponent(settingsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) |
303 |
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) |
304 |
.addComponent(conditionPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) |
305 |
); |
306 |
}// </editor-fold>//GEN-END:initComponents |
307 |
|
308 |
private void conditionCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_conditionCheckBoxActionPerformed |
309 |
conditionComboBox.setEnabled(conditionCheckBox.isSelected()); |
310 |
if (conditionCheckBox.isSelected()) { |
311 |
conditionComboBox.requestFocusInWindow(); |
312 |
} |
313 |
}//GEN-LAST:event_conditionCheckBoxActionPerformed |
314 |
|
315 |
// Variables declaration - do not modify//GEN-BEGIN:variables |
316 |
private javax.swing.JCheckBox conditionCheckBox; |
317 |
private javax.swing.JComboBox<String> conditionComboBox; |
318 |
private javax.swing.JPanel conditionPanel; |
319 |
private javax.swing.JLabel fileLabel; |
320 |
private javax.swing.JTextField fileTextField; |
321 |
private javax.swing.JLabel lineNumberLabel; |
322 |
private javax.swing.JTextField lineNumberTextField; |
323 |
private javax.swing.JPanel settingsPanel; |
324 |
// End of variables declaration//GEN-END:variables |
325 |
|
326 |
//~ Inner classes |
327 |
private class CustomizerController implements Controller { |
328 |
|
329 |
private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); |
330 |
private String errorMessage; |
331 |
|
332 |
@Override |
333 |
public boolean ok() { |
334 |
if (!isValid()) { |
335 |
final String message = getErrorMessage(); |
336 |
if (message != null) { |
337 |
if (SwingUtilities.isEventDispatchThread()) { |
338 |
showMessageDialog(message); |
339 |
} else { |
340 |
SwingUtilities.invokeLater(() -> { |
341 |
showMessageDialog(message); |
342 |
}); |
343 |
} |
344 |
} |
345 |
return false; |
346 |
} |
347 |
|
348 |
String condition = null; |
349 |
if (conditionCheckBox.isSelected()) { |
350 |
condition = conditionComboBox.getSelectedItem().toString().trim(); |
351 |
} |
352 |
|
353 |
if (createBreakpoint) { |
354 |
String fileName = fileTextField.getText(); |
355 |
String lineNumberString = lineNumberTextField.getText(); |
356 |
if (fileName == null) { |
357 |
return false; |
358 |
} |
359 |
File file = new File(fileName.trim()); |
360 |
FileObject fileObject = FileUtil.toFileObject(file); |
361 |
if (fileObject == null) { |
362 |
return false; |
363 |
} |
364 |
Line line = Utils.getLine(fileObject, Integer.parseInt(lineNumberString) - 1); |
365 |
LineBreakpoint lb = createLineBreakpoint(line); |
366 |
setCondition(lb, condition); |
367 |
DebuggerManager.getDebuggerManager().addBreakpoint(lb); |
368 |
} else { |
369 |
setCondition(lineBreakpoint, condition); |
370 |
} |
371 |
|
372 |
return true; |
373 |
} |
374 |
|
375 |
private void setCondition(LineBreakpoint lb, String condition) { |
376 |
if (condition != null && !condition.isEmpty()) { |
377 |
lb.setCondition(condition); |
378 |
saveCondition(condition); |
379 |
} else { |
380 |
lb.setCondition(null); |
381 |
} |
382 |
} |
383 |
|
384 |
@Override |
385 |
public boolean cancel() { |
386 |
return true; |
387 |
} |
388 |
|
389 |
@NbBundle.Messages({ |
390 |
"CustomizerController.invalid.file=Existing file must be set.", |
391 |
"CustomizerController.invalid.line=Valid line number must be set." |
392 |
}) |
393 |
@Override |
394 |
public boolean isValid() { |
395 |
boolean isValid = true; |
396 |
// file |
397 |
String fileName = fileTextField.getText(); |
398 |
if (fileName == null || fileName.trim().length() == 0) { |
399 |
setErrorMessage(Bundle.CustomizerController_invalid_file()); |
400 |
return false; |
401 |
} |
402 |
File file = new File(fileName.trim()); |
403 |
if (!file.exists()) { |
404 |
setErrorMessage(Bundle.CustomizerController_invalid_file()); |
405 |
return false; |
406 |
} |
407 |
FileObject fileObject = FileUtil.toFileObject(file); |
408 |
if (fileObject == null) { |
409 |
setErrorMessage(Bundle.CustomizerController_invalid_file()); |
410 |
return false; |
411 |
} |
412 |
|
413 |
// line number |
414 |
String lineNumberString = lineNumberTextField.getText(); |
415 |
if (lineNumberString == null || lineNumberString.trim().length() == 0) { |
416 |
setErrorMessage(Bundle.CustomizerController_invalid_line()); |
417 |
return false; |
418 |
} |
419 |
try { |
420 |
int lineNumber = Integer.parseInt(lineNumberTextField.getText()); |
421 |
if (lineNumber <= 0) { |
422 |
setErrorMessage(Bundle.CustomizerController_invalid_line()); |
423 |
return false; |
424 |
} |
425 |
} catch (NumberFormatException nfe) { |
426 |
setErrorMessage(Bundle.CustomizerController_invalid_line()); |
427 |
isValid = false; |
428 |
} |
429 |
|
430 |
if (isValid) { |
431 |
setErrorMessage(null); |
432 |
} |
433 |
return isValid; |
434 |
} |
435 |
|
436 |
@Override |
437 |
public void addPropertyChangeListener(PropertyChangeListener l) { |
438 |
propertyChangeSupport.addPropertyChangeListener(l); |
439 |
} |
440 |
|
441 |
@Override |
442 |
public void removePropertyChangeListener(PropertyChangeListener l) { |
443 |
propertyChangeSupport.removePropertyChangeListener(l); |
444 |
} |
445 |
|
446 |
void firePropertyChange() { |
447 |
propertyChangeSupport.firePropertyChange(Controller.PROP_VALID, null, null); |
448 |
} |
449 |
|
450 |
void setErrorMessage(String message) { |
451 |
errorMessage = message; |
452 |
propertyChangeSupport.firePropertyChange(NotifyDescriptor.PROP_ERROR_NOTIFICATION, null, message); |
453 |
} |
454 |
|
455 |
String getErrorMessage() { |
456 |
return errorMessage; |
457 |
} |
458 |
|
459 |
private void showMessageDialog(String message) { |
460 |
NotifyDescriptor descr = new NotifyDescriptor.Message(message); |
461 |
DialogDisplayer.getDefault().notify(descr); |
462 |
} |
463 |
|
464 |
} |
465 |
|
466 |
} |