Skip to content

Commit 6fce3a1

Browse files
committed
GH-213 Ask the user to save modified OQL/R script when closing the heap viewer
1 parent 24c6618 commit 6fce3a1

File tree

12 files changed

+203
-17
lines changed

12 files changed

+203
-17
lines changed

visualvm/heapdump/nbproject/project.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<compile-dependency/>
2222
<run-dependency>
2323
<release-version>2</release-version>
24-
<specification-version>2.1</specification-version>
24+
<specification-version>2.2</specification-version>
2525
</run-dependency>
2626
</dependency>
2727
<dependency>
@@ -39,7 +39,7 @@
3939
<compile-dependency/>
4040
<run-dependency>
4141
<release-version>2</release-version>
42-
<specification-version>2.0</specification-version>
42+
<specification-version>2.2</specification-version>
4343
</run-dependency>
4444
</dependency>
4545
<dependency>

visualvm/heapdump/src/org/graalvm/visualvm/heapdump/impl/HeapDumpView.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ protected DataViewComponent createComponent() {
7575
return dvc;
7676
}
7777

78+
protected void willBeRemoved() {
79+
if (mvs != null) mvs.willBeRemoved();
80+
}
81+
7882
protected void removed() {
7983
SwingUtilities.invokeLater(new Runnable() {
8084
public void run() { if (mvs != null) mvs.closed(); }
@@ -103,6 +107,10 @@ public DataViewComponent.MasterView getMasterView() {
103107
}
104108

105109

110+
void willBeRemoved() {
111+
if (heapViewer != null) heapViewer.willBeRemoved();
112+
}
113+
106114
void closed() {
107115
if (heapViewer != null) heapViewer.closed();
108116
}

visualvm/heapviewer.console/nbproject/project.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<compile-dependency/>
1313
<run-dependency>
1414
<release-version>2</release-version>
15-
<specification-version>2.0</specification-version>
15+
<specification-version>2.2</specification-version>
1616
</run-dependency>
1717
</dependency>
1818
<dependency>
@@ -21,7 +21,7 @@
2121
<compile-dependency/>
2222
<run-dependency>
2323
<release-version>2</release-version>
24-
<specification-version>2.0</specification-version>
24+
<specification-version>2.2</specification-version>
2525
</run-dependency>
2626
</dependency>
2727
<dependency>

visualvm/heapviewer.console/src/org/graalvm/visualvm/heapviewer/console/r/RConsoleView.java

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -38,12 +38,15 @@
3838
import java.awt.BorderLayout;
3939
import java.awt.CardLayout;
4040
import java.awt.Color;
41+
import java.awt.Container;
42+
import java.awt.Dialog;
4143
import java.awt.Dimension;
4244
import java.awt.Graphics;
4345
import java.awt.Graphics2D;
4446
import java.awt.Image;
4547
import java.awt.RenderingHints;
4648
import java.awt.event.ActionEvent;
49+
import java.awt.event.ActionListener;
4750
import java.awt.event.ItemEvent;
4851
import java.net.URL;
4952
import java.util.HashSet;
@@ -67,6 +70,7 @@
6770
import javax.swing.JPanel;
6871
import javax.swing.JPopupMenu;
6972
import javax.swing.JProgressBar;
73+
import javax.swing.JTabbedPane;
7074
import javax.swing.JToggleButton;
7175
import javax.swing.JToolBar;
7276
import javax.swing.SwingUtilities;
@@ -86,9 +90,13 @@
8690
import org.graalvm.visualvm.lib.profiler.api.ProfilerDialogs;
8791
import org.graalvm.visualvm.lib.profiler.api.icons.GeneralIcons;
8892
import org.graalvm.visualvm.lib.profiler.api.icons.Icons;
93+
import org.openide.DialogDescriptor;
94+
import org.openide.DialogDisplayer;
95+
import org.openide.NotifyDescriptor;
8996
import org.openide.util.ImageUtilities;
9097
import org.openide.util.NbBundle;
9198
import org.openide.util.RequestProcessor;
99+
import org.openide.windows.TopComponent;
92100

93101
/**
94102
*
@@ -113,7 +121,11 @@
113121
"RConsoleView_SaveActionTooltip=Save R script",
114122
"RConsoleView_EditAction=Edit Scripts",
115123
"RConsoleView_EditActionTooltip=Edit Custom R scripts",
116-
"RConsoleView_ExecutingProgress=Executing..."
124+
"RConsoleView_ExecutingProgress=Executing...",
125+
"RConsoleView_ResultsLimit=Results Limit:",
126+
"RConsoleView_SaveOnClosingCaption=R Script Not Saved",
127+
"RConsoleView_SaveOnClosingMsg=<html><b>The R script has been modified.</b><br><br>Save it before closing the heap viewer?</html>",
128+
"RConsoleView_NoSaveOnCloseBtn=Close Without Saving"
117129
// "OQLConsoleView_Results=Results:",
118130
// "OQLConsoleView_ObjectsTooltip=Objects",
119131
// "OQLConsoleView_HTMLTooltip=Results:",
@@ -246,6 +258,46 @@ public ProfilerToolbar getToolbar() {
246258
}
247259

248260

261+
protected void willBeClosed(Runnable viewSelector) {
262+
if (editor != null && editor.isChanged() && !editor.getScript().isEmpty() && saveAction.isEnabled()) {
263+
viewSelector.run();
264+
265+
Container c = editor;
266+
while (c != null) {
267+
Container p = c.getParent();
268+
if (p instanceof JTabbedPane) {
269+
((JTabbedPane)p).setSelectedComponent(c);
270+
} else if (p instanceof TopComponent) {
271+
((TopComponent)p).requestActive();
272+
break;
273+
}
274+
c = p;
275+
}
276+
277+
278+
JButton saveButton = new JButton(saveAction) {
279+
public void addActionListener(ActionListener l) {
280+
if (l == saveAction) super.addActionListener(l);
281+
}
282+
public void removeActionListener(ActionListener l) {
283+
if (l == saveAction) super.removeActionListener(l);
284+
}
285+
};
286+
JButton closeButton = new JButton(Bundle.RConsoleView_NoSaveOnCloseBtn());
287+
DialogDescriptor dd = new DialogDescriptor(Bundle.RConsoleView_SaveOnClosingMsg(), Bundle.RConsoleView_SaveOnClosingCaption(), true, new Object[] { saveButton, closeButton }, saveButton, DialogDescriptor.DEFAULT_ALIGN, null, null);
288+
dd.setMessageType(NotifyDescriptor.QUESTION_MESSAGE);
289+
Dialog d = DialogDisplayer.getDefault().createDialog(dd);
290+
saveAction.putValue("NOTIFIER", new Runnable() { // NOI18N
291+
public void run() {
292+
saveAction.putValue("NOTIFIER", null); // NOI18N
293+
d.setVisible(false);
294+
}
295+
});
296+
d.setVisible(true);
297+
}
298+
}
299+
300+
249301
private void executeQuery() {
250302
SwingUtilities.invokeLater(new Runnable() {
251303
public void run() {
@@ -514,6 +566,10 @@ public void actionPerformed(ActionEvent e) {
514566
RQueries.instance().populateSaveQuery(p, currentQuery, editor.getScript(), new RQueries.Handler() {
515567
protected void querySelected(RQueries.Query query) {
516568
currentQuery = query;
569+
editor.clearChanged();
570+
571+
Object notifier = saveAction.getValue("NOTIFIER"); // NOI18N
572+
if (notifier instanceof Runnable) ((Runnable)notifier).run();
517573
}
518574
});
519575

visualvm/heapviewer.console/src/org/graalvm/visualvm/heapviewer/console/r/REditorComponent.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -79,6 +79,8 @@ class REditorComponent extends JPanel {
7979

8080
private Color lastBgColor;
8181
private Caret lastCaret;
82+
83+
private boolean changed;
8284

8385

8486
public REditorComponent(/*OQLEngine engine*/) {
@@ -89,6 +91,7 @@ public REditorComponent(/*OQLEngine engine*/) {
8991

9092
public void setScript(String script) {
9193
queryEditor.setText(script);
94+
clearChanged();
9295
try { queryEditor.setCaretPosition(0); } catch (IllegalArgumentException e) {}
9396
scrollRectToVisible(new Rectangle());
9497
}
@@ -99,6 +102,15 @@ public String getScript() {
99102

100103

101104
protected void validityChanged(boolean valid) {}
105+
106+
107+
final void clearChanged() {
108+
changed = false;
109+
}
110+
111+
public final boolean isChanged() {
112+
return changed;
113+
}
102114

103115

104116
public void setEnabled(boolean b) {
@@ -192,18 +204,28 @@ private void init() {
192204
public void removeUpdate(DocumentEvent e) { validateScript(); }
193205
public void changedUpdate(DocumentEvent e) { validateScript(); }
194206
};
207+
final DocumentListener editHandler = new DocumentListener() {
208+
public void insertUpdate(DocumentEvent e) { handleEdit(); }
209+
public void removeUpdate(DocumentEvent e) { handleEdit(); }
210+
public void changedUpdate(DocumentEvent e) { handleEdit(); }
211+
private void handleEdit() { changed = true; }
212+
};
195213

196214
queryEditor = new JEditorPane() {
197215
protected EditorKit createDefaultEditorKit() {
198216
return new OQLEditorKit();
199217
}
200218
public void setText(String text) {
201219
Document doc = getDocument();
202-
if (doc != null) doc.removeDocumentListener(listener);
220+
if (doc != null) {
221+
doc.removeDocumentListener(listener);
222+
doc.removeDocumentListener(editHandler);
223+
}
203224
setDocument(getEditorKit().createDefaultDocument());
204225
doc = getDocument();
205226
if (doc != null) doc.addDocumentListener(listener);
206227
super.setText(text);
228+
if (doc != null) doc.addDocumentListener(editHandler);
207229
}
208230
};
209231

visualvm/heapviewer/manifest.mf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ AutoUpdate-Show-In-Client: false
33
AutoUpdate-Essential-Module: true
44
OpenIDE-Module: org.graalvm.visualvm.heapviewer/2
55
OpenIDE-Module-Localizing-Bundle: org/graalvm/visualvm/heapviewer/Bundle.properties
6-
OpenIDE-Module-Specification-Version: 2.1
6+
OpenIDE-Module-Specification-Version: 2.2
77

visualvm/heapviewer/nbproject/project.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<compile-dependency/>
1313
<run-dependency>
1414
<release-version>2</release-version>
15-
<specification-version>2.0</specification-version>
15+
<specification-version>2.2</specification-version>
1616
</run-dependency>
1717
</dependency>
1818
<dependency>

visualvm/heapviewer/src/org/graalvm/visualvm/heapviewer/HeapViewer.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -97,6 +97,11 @@ public JComponent getComponent() {
9797
}
9898

9999

100+
public void willBeRemoved() {
101+
if (component instanceof HeapViewerComponent)
102+
((HeapViewerComponent)component).willBeClosed();
103+
}
104+
100105
public void closed() {
101106
if (component instanceof HeapViewerComponent)
102107
((HeapViewerComponent)component).closed();

visualvm/heapviewer/src/org/graalvm/visualvm/heapviewer/oql/OQLConsoleView.java

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -78,6 +78,8 @@
7878
import org.graalvm.visualvm.heapviewer.ui.TreeTableViewColumn;
7979
import org.graalvm.visualvm.heapviewer.utils.HeapUtils;
8080
import java.awt.Container;
81+
import java.awt.Dialog;
82+
import java.awt.event.ActionListener;
8183
import java.text.Format;
8284
import java.text.NumberFormat;
8385
import java.util.Set;
@@ -88,14 +90,19 @@
8890
import javax.swing.JComboBox;
8991
import javax.swing.JList;
9092
import javax.swing.JPopupMenu;
93+
import javax.swing.JTabbedPane;
9194
import javax.swing.JToolBar;
9295
import javax.swing.ListCellRenderer;
9396
import org.graalvm.visualvm.core.VisualVM;
9497
import org.graalvm.visualvm.lib.profiler.api.icons.LanguageIcons;
9598
import org.netbeans.api.options.OptionsDisplayer;
9699
import org.graalvm.visualvm.lib.profiler.heapwalk.OQLSupport;
97100
import org.graalvm.visualvm.lib.profiler.oql.engine.api.OQLEngine;
101+
import org.openide.DialogDescriptor;
102+
import org.openide.DialogDisplayer;
103+
import org.openide.NotifyDescriptor;
98104
import org.openide.util.NbBundle;
105+
import org.openide.windows.TopComponent;
99106

100107
/**
101108
*
@@ -129,7 +136,10 @@
129136
"OQLConsoleView_Classes=Classes",
130137
"OQLConsoleView_Instances=Instances",
131138
"OQLConsoleView_Aggregation=Aggregation:",
132-
"OQLConsoleView_ResultsLimit=Results Limit:"
139+
"OQLConsoleView_ResultsLimit=Results Limit:",
140+
"OQLConsoleView_SaveOnClosingCaption=OQL Script Not Saved",
141+
"OQLConsoleView_SaveOnClosingMsg=<html><b>The OQL script has been modified.</b><br><br>Save it before closing the heap viewer?</html>",
142+
"OQLConsoleView_NoSaveOnCloseBtn=Close Without Saving"
133143
})
134144
public class OQLConsoleView extends HeapViewerFeature {
135145

@@ -214,6 +224,45 @@ public ProfilerToolbar getToolbar() {
214224
}
215225

216226

227+
protected void willBeClosed(Runnable viewSelector) {
228+
if (editor != null && editor.isChanged() && !editor.getScript().isEmpty() && saveAction.isEnabled()) {
229+
viewSelector.run();
230+
231+
Container c = editor;
232+
while (c != null) {
233+
Container p = c.getParent();
234+
if (p instanceof JTabbedPane) {
235+
((JTabbedPane)p).setSelectedComponent(c);
236+
} else if (p instanceof TopComponent) {
237+
((TopComponent)p).requestActive();
238+
break;
239+
}
240+
c = p;
241+
}
242+
243+
244+
JButton saveButton = new JButton(saveAction) {
245+
public void addActionListener(ActionListener l) {
246+
if (l == saveAction) super.addActionListener(l);
247+
}
248+
public void removeActionListener(ActionListener l) {
249+
if (l == saveAction) super.removeActionListener(l);
250+
}
251+
};
252+
JButton closeButton = new JButton(Bundle.OQLConsoleView_NoSaveOnCloseBtn());
253+
DialogDescriptor dd = new DialogDescriptor(Bundle.OQLConsoleView_SaveOnClosingMsg(), Bundle.OQLConsoleView_SaveOnClosingCaption(), true, new Object[] { saveButton, closeButton }, saveButton, DialogDescriptor.DEFAULT_ALIGN, null, null);
254+
dd.setMessageType(NotifyDescriptor.QUESTION_MESSAGE);
255+
Dialog d = DialogDisplayer.getDefault().createDialog(dd);
256+
saveAction.putValue("NOTIFIER", new Runnable() { // NOI18N
257+
public void run() {
258+
saveAction.putValue("NOTIFIER", null); // NOI18N
259+
d.setVisible(false);
260+
}
261+
});
262+
d.setVisible(true);
263+
}
264+
}
265+
217266
@Override
218267
protected void closed() {
219268
if (objectsView != null) objectsView.closed();
@@ -362,6 +411,10 @@ public void actionPerformed(ActionEvent e) {
362411
OQLQueries.instance().populateSaveQuery(p, currentQuery, editor.getScript(), new OQLQueries.Handler() {
363412
protected void querySelected(OQLSupport.Query query) {
364413
currentQuery = query;
414+
editor.clearChanged();
415+
416+
Object notifier = saveAction.getValue("NOTIFIER"); // NOI18N
417+
if (notifier instanceof Runnable) ((Runnable)notifier).run();
365418
}
366419
});
367420

0 commit comments

Comments
 (0)