001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: /**
043: * @author Ana von Klopp
044: */package org.netbeans.modules.web.monitor.client;
045:
046: import java.awt.BorderLayout;
047: import java.awt.Container;
048: import java.awt.Dimension;
049: import java.awt.FontMetrics;
050: import java.awt.Graphics;
051: import java.awt.event.ActionListener;
052: import java.awt.event.ActionEvent;
053: import java.beans.PropertyChangeListener;
054: import java.beans.PropertyChangeEvent;
055: import java.io.ObjectStreamException;
056: import java.io.Serializable;
057: import java.util.logging.Level;
058: import java.util.logging.Logger;
059: import javax.swing.ImageIcon;
060: import javax.swing.JButton;
061: import javax.swing.JFrame;
062: import javax.swing.JPanel;
063: import javax.swing.JScrollPane;
064: import javax.swing.JSplitPane;
065: import javax.swing.JTabbedPane;
066: import javax.swing.JToggleButton;
067: import javax.swing.JToolBar;
068: import javax.swing.border.CompoundBorder;
069: import javax.swing.border.EmptyBorder;
070: import javax.swing.border.EtchedBorder;
071: import javax.swing.event.ChangeListener;
072: import javax.swing.event.ChangeEvent;
073: import org.openide.explorer.ExplorerManager;
074: import org.openide.explorer.ExplorerUtils;
075: import org.openide.explorer.view.BeanTreeView;
076: import org.openide.nodes.Node;
077: import org.openide.nodes.Children;
078: import org.openide.nodes.AbstractNode;
079: import org.openide.windows.TopComponent;
080: import org.openide.util.HelpCtx;
081: import org.openide.util.NbBundle;
082: import org.openide.util.RequestProcessor;
083: import org.netbeans.modules.web.monitor.data.DataRecord;
084:
085: /**
086: * Update title does not work like it should. Maybe there is a getName
087: * method for this that I can override.
088: */
089: class TransactionView extends TopComponent implements
090: ExplorerManager.Provider, PropertyChangeListener,
091: ChangeListener {
092:
093: // Handles all the files etc.
094: private transient static TransactionView instance = null;
095: private transient static Controller controller = null;
096:
097: // Misc
098: private transient JToggleButton timeAButton, timeDButton,
099: alphaButton;
100:
101: private transient JToggleButton timestampButton;
102:
103: // Sizing and stuff...
104: private transient Dimension logD = new Dimension(250, 400);
105: private transient Dimension dataD = new Dimension(500, 400);
106: private transient Dimension tabD = new Dimension(500, 472);
107:
108: // Display stuff
109: private transient static ExplorerManager mgr = null;
110: private transient JPanel logPanel = null;
111: private transient JPanel dataPanel = null;
112: private transient JSplitPane splitPanel = null;
113: private transient double dividerRatio = .35;
114: private transient BeanTreeView tree = null;
115: private transient AbstractNode selected = null;
116:
117: private transient RequestDisplay requestDisplay = null;
118: private transient CookieDisplay cookieDisplay = null;
119: private transient SessionDisplay sessionDisplay = null;
120: private transient ContextDisplay contextDisplay = null;
121: private transient ClientDisplay clientDisplay = null;
122: private transient HeaderDisplay headerDisplay = null;
123:
124: // Handle resizing for larger fonts
125: boolean fontChanged = true;
126:
127: // Data display tables
128: private int displayType = 0;
129:
130: // Need to override requestFocusInWindow to call requestFocusInWindow
131: // on some internal component for F1 help to work correctly
132: public boolean requestFocusInWindow() {
133: if (tree != null) {
134: return tree.requestFocusInWindow();
135: } else {
136: return false;
137: }
138: }
139:
140: public HelpCtx getHelpCtx() {
141: String helpID = NbBundle.getBundle(TransactionView.class)
142: .getString("MON_Transaction_View_F1_Help_ID"); // NOI18N
143: return new HelpCtx(helpID);
144: }
145:
146: /**
147: * Creates the display and the nodes that are present all the
148: * time. Because all this is done at startup, we don't actually
149: * retrieve any data until the Monitor is opened.
150: */
151: private TransactionView() {
152: setIcon(new ImageIcon(
153: TransactionView.class
154: .getResource("/org/netbeans/modules/web/monitor/client/icons/menuitem.gif"))
155: .getImage());
156: setToolTipText(NbBundle.getMessage(TransactionView.class,
157: "MON_Window_Tooltip"));
158: controller = Controller.getInstance();
159: initialize();
160: this .getAccessibleContext().setAccessibleDescription(
161: NbBundle.getBundle(TransactionView.class).getString(
162: "ACS_MON_monitorDesc"));
163: this .getAccessibleContext().setAccessibleName(
164: NbBundle.getBundle(TransactionView.class).getString(
165: "ACS_MON_monitorName"));
166:
167: }
168:
169: static synchronized TransactionView getInstance() {
170: if (instance == null)
171: instance = new TransactionView();
172: return instance;
173: }
174:
175: private void initialize() {
176:
177: mgr = new ExplorerManager();
178: mgr.addPropertyChangeListener(this );
179: mgr.setRootContext(controller.getRoot());
180:
181: // following line tells the top component which lookup should be associated with it
182: associateLookup(ExplorerUtils.createLookup(mgr, getActionMap()));
183:
184: setLayout(new java.awt.BorderLayout());
185: tree = new BeanTreeView();
186: tree.setDefaultActionAllowed(true);
187: tree.getAccessibleContext().setAccessibleDescription(
188: NbBundle.getBundle(TransactionView.class).getString(
189: "ACS_MON_treeName"));
190: tree.getAccessibleContext().setAccessibleName(
191: NbBundle.getBundle(TransactionView.class).getString(
192: "ACS_MON_treeDesc"));
193:
194: createLogPanel();
195: createDataPanel();
196: splitPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
197: logPanel, dataPanel);
198: splitPanel.setDividerLocation((int) (logD.getWidth()));
199: splitPanel.setResizeWeight(dividerRatio);
200: splitPanel.setDividerSize(1);
201: splitPanel.setOneTouchExpandable(true);
202: this .add(splitPanel);
203: setName(NbBundle.getBundle(TransactionView.class).getString(
204: "MON_Title"));
205: }
206:
207: /**
208: * Open the transaction nodes (i.e. first level children of the root).
209: */
210: void openTransactionNodes() {
211:
212: // Post the request for later in case there are timing issues
213: // going on here.
214:
215: OpenTransactionNodesRequest req = new OpenTransactionNodesRequest();
216:
217: RequestProcessor.Task t = RequestProcessor
218: .postRequest(req, 500); // wait a sec...
219: }
220:
221: public int getPersistenceType() {
222: return TopComponent.PERSISTENCE_ONLY_OPENED;
223: }
224:
225: class OpenTransactionNodesRequest implements Runnable {
226:
227: public void run() {
228: openTransactionNodes();
229: }
230:
231: void openTransactionNodes() {
232: NavigateNode root = controller.getRoot();
233: Children ch = root.getChildren();
234: Node[] nodes = ch.getNodes();
235: CurrNode cn = (CurrNode) nodes[0];
236: SavedNode sn = (SavedNode) nodes[1];
237:
238: // If there are any current nodes, then select the most
239: // recent (i.e. the last?) one.
240:
241: Children currCh = cn.getChildren();
242: Node[] currChNodes = currCh.getNodes();
243: int numCN = currChNodes.length;
244: if (numCN > 0) {
245: int selectThisOne = 0;
246: if (timeAButton.isSelected()) {
247: selectThisOne = numCN - 1;
248: }
249: selectNode(currChNodes[selectThisOne]);
250: } else {
251: Children savedCh = sn.getChildren();
252: Node[] savedChNodes = savedCh.getNodes();
253: int numSN = savedChNodes.length;
254: if (numSN > 0) {
255: selectNode(savedChNodes[0]);
256: }
257: }
258: }
259: }
260:
261: void selectNode(Node n) {
262:
263: try {
264: mgr.setSelectedNodes(n != null ? new Node[] { n }
265: : new Node[] {});
266:
267: } catch (Exception exc) {
268: Logger.getLogger(TransactionView.class.getName()).log(
269: Level.INFO, "selectNode", exc);
270: } // safely ignored
271: }
272:
273: /**
274: * Loads the transactions into the monitor on opening. */
275: private boolean openedOnceAlready = false;
276:
277: public void open() {
278: super .open();
279: //setName(NbBundle.getBundle(TransactionView.class).getString("MON_Title"));
280: if (!openedOnceAlready) {
281: openedOnceAlready = true;
282: controller.getTransactions();
283: openTransactionNodes();
284: //this.revalidate();
285: //this.repaint();
286: }
287: //PENDING ...
288: controller.checkServer(false);
289: }
290:
291: /**
292: * Returns true if the monitor is already initialized - the old transactions
293: * were loaded from disk, false otherwise.
294: */
295: public boolean isInitialized() {
296: return openedOnceAlready;
297: }
298:
299: protected void updateTitle() {
300: setName(NbBundle.getBundle(TransactionView.class).getString(
301: "MON_Title"));
302: }
303:
304: /**
305: * Do not serialize this component, substitute null instead.
306: */
307: public Object writeReplace() throws ObjectStreamException {
308: return new ResolvableHelper();
309: }
310:
311: /**
312: * Invoked at startup, creates the display GUI.
313: */
314: private void createLogPanel() {
315:
316: JToolBar buttonPanel = new JToolBar();
317: buttonPanel.setBorder(new CompoundBorder(new EtchedBorder(
318: EtchedBorder.LOWERED), new EmptyBorder(4, 4, 4, 4)));
319: buttonPanel.setFloatable(false);
320:
321: JButton updateButton = new JButton(
322: new ImageIcon(
323: TransactionView.class
324: .getResource("/org/netbeans/modules/web/monitor/client/icons/update.gif")));
325: ; // NOI18N
326: updateButton.setToolTipText(NbBundle.getBundle(
327: TransactionView.class).getString("MON_Reload_all_17"));
328: updateButton.addActionListener(new ActionListener() {
329: public void actionPerformed(ActionEvent e) {
330: controller.getTransactions();
331: }
332: });
333:
334: timeAButton = new JToggleButton(
335: new ImageIcon(
336: TransactionView.class
337: .getResource("/org/netbeans/modules/web/monitor/client/icons/timesortA.gif")),
338: false);
339: timeAButton.setToolTipText(NbBundle.getBundle(
340: TransactionView.class).getString(
341: "MON_Order_transactions_15"));
342:
343: timeAButton.addActionListener(new ActionListener() {
344: public void actionPerformed(ActionEvent e) {
345:
346: if (!((JToggleButton) e.getSource()).isSelected())
347: return;
348: else {
349: timeDButton.setSelected(false);
350: alphaButton.setSelected(false);
351: controller.setComparator(controller.new CompTime(
352: false));
353: }
354: }
355: });
356:
357: timeDButton = new JToggleButton(
358: new ImageIcon(
359: TransactionView.class
360: .getResource("/org/netbeans/modules/web/monitor/client/icons/timesortB.gif")),
361: true);
362: timeDButton.setToolTipText(NbBundle.getBundle(
363: TransactionView.class).getString(
364: "MON_Order_transactions_16"));
365: timeDButton.addActionListener(new ActionListener() {
366: public void actionPerformed(ActionEvent e) {
367:
368: if (!((JToggleButton) e.getSource()).isSelected())
369: return;
370: else {
371: timeAButton.setSelected(false);
372: alphaButton.setSelected(false);
373: controller.setComparator(controller.new CompTime(
374: true));
375: }
376:
377: }
378: });
379:
380: alphaButton = new JToggleButton(
381: new ImageIcon(
382: TransactionView.class
383: .getResource("/org/netbeans/modules/web/monitor/client/icons/a2z.gif")),
384: false);
385: alphaButton.setToolTipText(NbBundle.getBundle(
386: TransactionView.class).getString(
387: "MON_Order_transactions_14"));
388: alphaButton.addActionListener(new ActionListener() {
389: public void actionPerformed(ActionEvent e) {
390:
391: if (!((JToggleButton) e.getSource()).isSelected())
392: return;
393: else {
394: timeAButton.setSelected(false);
395: timeDButton.setSelected(false);
396: controller
397: .setComparator(controller.new CompAlpha());
398: }
399:
400: }
401: });
402:
403: timestampButton = new JToggleButton(
404: new ImageIcon(
405: TransactionView.class
406: .getResource("/org/netbeans/modules/web/monitor/client/icons/timestamp.gif")),
407: TransactionNode.showTimeStamp());
408: timestampButton.setToolTipText(NbBundle.getBundle(
409: TransactionView.class).getString("MON_Show_time_25"));
410: timestampButton.addActionListener(new ActionListener() {
411: public void actionPerformed(ActionEvent e) {
412: TransactionNode.toggleTimeStamp();
413: // PENDING - should find a way to repaint
414: // the tree. tree.repaint() does not work.
415: controller.updateNodeNames();
416: }
417: });
418:
419: buttonPanel.add(updateButton);
420: buttonPanel.add(timeDButton);
421: buttonPanel.add(timeAButton);
422: buttonPanel.add(alphaButton);
423: JPanel sep = new JPanel() { // PENDING proper insets should do the same spacing job
424: public float getAlignmentX() {
425: return 0;
426: }
427:
428: public float getAlignmentY() {
429: return 0;
430: }
431: };
432: sep.setMaximumSize(new Dimension(10, 10));
433: buttonPanel.add(sep);
434: buttonPanel.add(timestampButton);
435:
436: logPanel = new JPanel();
437: logPanel.setLayout(new BorderLayout());
438:
439: JPanel p = new JPanel(new BorderLayout());
440: //p.setBorder (new EtchedBorder (EtchedBorder.LOWERED));
441: p.add(BorderLayout.NORTH, buttonPanel);
442: p.add(BorderLayout.CENTER, tree);
443: logPanel.add(BorderLayout.CENTER, p);
444: logPanel.setPreferredSize(logD);
445: }
446:
447: /**
448: * Invoked at startup, creates the display GUI.
449: */
450: private void createDataPanel() {
451:
452: JTabbedPane jtp = new JTabbedPane();
453: jtp.getAccessibleContext().setAccessibleName(
454: NbBundle.getBundle(TransactionView.class).getString(
455: "ACS_MON_Transaction_dataName"));
456: jtp.getAccessibleContext().setAccessibleDescription(
457: NbBundle.getBundle(TransactionView.class).getString(
458: "ACS_MON_Transaction_dataDesc"));
459:
460: jtp.setPreferredSize(tabD);
461: jtp.setMaximumSize(tabD);
462:
463: // compute scrolling unit increment
464: FontMetrics metrics = getFontMetrics(jtp.getFont());
465: int scrollingUnitIncrement = metrics.getHeight();
466:
467: requestDisplay = new RequestDisplay();
468: JScrollPane p = new JScrollPane(requestDisplay);
469: p.getVerticalScrollBar().setUnitIncrement(
470: scrollingUnitIncrement);
471: jtp.addTab(NbBundle.getBundle(TransactionView.class).getString(
472: "MON_Request_19"), p);
473:
474: cookieDisplay = new CookieDisplay();
475: p = new JScrollPane(cookieDisplay);
476: p.getVerticalScrollBar().setUnitIncrement(
477: scrollingUnitIncrement);
478: jtp.addTab(NbBundle.getBundle(TransactionView.class).getString(
479: "MON_Cookies_4"), p);
480:
481: sessionDisplay = new SessionDisplay();
482: p = new JScrollPane(sessionDisplay);
483: p.getVerticalScrollBar().setUnitIncrement(
484: scrollingUnitIncrement);
485: jtp.addTab(NbBundle.getBundle(TransactionView.class).getString(
486: "MON_Session_24"), p);
487:
488: contextDisplay = new ContextDisplay();
489: p = new JScrollPane(contextDisplay);
490: p.getVerticalScrollBar().setUnitIncrement(
491: scrollingUnitIncrement);
492: jtp.addTab(NbBundle.getBundle(TransactionView.class).getString(
493: "MON_Context_23"), p);
494:
495: clientDisplay = new ClientDisplay();
496: p = new JScrollPane(clientDisplay);
497: p.getVerticalScrollBar().setUnitIncrement(
498: scrollingUnitIncrement);
499: jtp.addTab(NbBundle.getBundle(TransactionView.class).getString(
500: "MON_Client_Server"), p);
501:
502: headerDisplay = new HeaderDisplay();
503: p = new JScrollPane(headerDisplay);
504: p.getVerticalScrollBar().setUnitIncrement(
505: scrollingUnitIncrement);
506: jtp.addTab(NbBundle.getBundle(TransactionView.class).getString(
507: "MON_Header_19"), p);
508:
509: jtp.addChangeListener(this );
510:
511: dataPanel = new JPanel();
512: dataPanel.setLayout(new BorderLayout());
513: dataPanel.add(BorderLayout.CENTER, jtp);
514: dataPanel.setPreferredSize(dataD);
515: }
516:
517: /**
518: * Invoked by DisplayAction. Displays monitor data for the selected
519: * node.
520: * PENDING - register this as a listener for the display action
521: */
522: void displayTransaction(Node node) {
523: if (node == null)
524: return;
525:
526: if (node instanceof TransactionNode
527: || node instanceof NestedNode) {
528: try {
529: selected = (AbstractNode) node;
530: } catch (ClassCastException ex) {
531: selected = null;
532: selectNode(null);
533: }
534: } else {
535: selected = null;
536: selectNode(null);
537: }
538:
539: showData();
540: }
541:
542: void saveTransaction(Node[] nodes) {
543: if ((nodes == null) || (nodes.length == 0))
544: return;
545: controller.saveTransaction(nodes);
546: selected = null;
547: selectNode(null);
548: showData();
549: }
550:
551: /**
552: * Listens to events from the tab pane, displays different
553: * categories of data accordingly.
554: */
555: public void stateChanged(ChangeEvent e) {
556:
557: setName(NbBundle.getBundle(TransactionView.class).getString(
558: "MON_Title"));
559:
560: JTabbedPane p = (JTabbedPane) e.getSource();
561: displayType = p.getSelectedIndex();
562: showData();
563: }
564:
565: void showData() {
566:
567: DataRecord dr = null;
568: try {
569: if (selected != null) {
570: dr = controller.getDataRecord(selected);
571: }
572: } catch (Exception ex) {
573: ex.printStackTrace();
574: }
575:
576: if (displayType == 0)
577: requestDisplay.setData(dr);
578: else if (displayType == 1)
579: cookieDisplay.setData(dr);
580: else if (displayType == 2)
581: sessionDisplay.setData(dr);
582: else if (displayType == 3)
583: contextDisplay.setData(dr);
584: else if (displayType == 4)
585: clientDisplay.setData(dr);
586: else if (displayType == 5)
587: headerDisplay.setData(dr);
588:
589: this .repaint();
590:
591: }
592:
593: /**
594: * Display the data for a node if it's selected. This should
595: * probably be done by checking if you can get the DisplayAction
596: * from the Node, and then calling it if it's enabled.
597: */
598: public void propertyChange(PropertyChangeEvent evt) {
599:
600: setName(NbBundle.getBundle(TransactionView.class).getString(
601: "MON_Title"));
602: //updateTitle();
603:
604: if (evt.getPropertyName().equals(
605: ExplorerManager.PROP_SELECTED_NODES)) {
606:
607: if (evt.getNewValue() instanceof Node[]) {
608: try {
609: Node[] ns = (Node[]) evt.getNewValue();
610: if (ns.length == 1) {
611: displayTransaction(ns[0]);
612: }
613: }
614: // Do nothing, this was not a proper node
615: catch (Exception e) {
616: Logger.getLogger(TransactionView.class.getName())
617: .log(Level.INFO, "", e);
618: selected = null;
619: showData();
620: return;
621: }
622: }
623: }
624: }
625:
626: /**
627: * Blanks out the displays - this is used by the delete actions
628: */
629: void blank() {
630: selected = null;
631: selectNode(null);
632: showData();
633: }
634:
635: /**
636: * When paint is first invoked, we set the rowheight based on the
637: * size of the font. */
638: public void paint(Graphics g) {
639: if (fontChanged) {
640: super .paint(g);
641: return;
642: }
643:
644: FontMetrics fm = g.getFontMetrics(getFont());
645: fontChanged = false;
646:
647: double logWidth = fm
648: .stringWidth(NbBundle.getBundle(TransactionView.class)
649: .getString("MON_Transactions_27")) * 1.1;
650:
651: if (logWidth > logD.getWidth()) {
652: double factor = logWidth / logD.getWidth();
653: logD.setSize(logWidth, factor * logD.getHeight());
654:
655: dataD.setSize(factor * dataD.getWidth(), factor
656: * dataD.getHeight());
657: }
658:
659: logPanel.setPreferredSize(logD);
660: dataPanel.setPreferredSize(dataD);
661: splitPanel.resetToPreferredSizes();
662: splitPanel.setDividerLocation((int) (logD.getWidth()));
663:
664: try {
665: Container o = (Container) this .getParent();
666: while (true) {
667: if (o instanceof JFrame) {
668: JFrame parent = (JFrame) o;
669: parent.pack();
670: break;
671: }
672: o = o.getParent();
673: }
674: } catch (Throwable t) {
675: // Do nothing, we can't resize the component
676: // invalidate on this component does not work.
677: }
678: //super.paint(g);
679: return;
680: }
681:
682: public static final class ResolvableHelper implements Serializable {
683: static final long serialVersionUID = 1234546018839457544L;
684:
685: Object readResolve() {
686: Controller.getInstance().getTransactions();
687: return TransactionView.getInstance();
688: }
689: }
690:
691: protected String preferredID() {
692: return "TransactionView"; //NOI18N
693: }
694:
695: // methods needed for binding with context menu ------
696: void setTimestampButtonSelected(boolean state) {
697: timestampButton.setSelected(state);
698: }
699:
700: boolean isTimestampButtonSelected() {
701: return timestampButton.isSelected();
702: }
703:
704: void addTimestampButtonActionListener(ActionListener l) {
705: timestampButton.addActionListener(l);
706: }
707:
708: boolean isAscButtonSelected() {
709: return timeAButton.isSelected();
710: }
711:
712: boolean isDescButtonSelected() {
713: return timeDButton.isSelected();
714: }
715:
716: boolean isAlphButtonSelected() {
717: return alphaButton.isSelected();
718: }
719:
720: void toggleTaskbarButtons(boolean asc, boolean desc, boolean alph) {
721: timeAButton.setSelected(asc);
722: timeDButton.setSelected(desc);
723: alphaButton.setSelected(alph);
724: }
725:
726: // EOF: methods needed for binding with context menu ------
727:
728: public ExplorerManager getExplorerManager() {
729: return mgr;
730: }
731:
732: protected void componentActivated() {
733: ExplorerUtils.activateActions(mgr, true);
734: }
735:
736: protected void componentDeactivated() {
737: ExplorerUtils.activateActions(mgr, false);
738: }
739: }
|