alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.core.output;

import java.util.WeakHashMap;
import java.util.HashSet;
import java.io.PipedWriter;

import java.awt.*;
import java.awt.event.*;
import java.awt.datatransfer.*;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.util.Map;
import java.util.Set;
import javax.swing.AbstractAction;

import javax.swing.JPopupMenu;
import javax.swing.JMenuItem;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import org.openide.ErrorManager;
import org.openide.windows.*;
import org.openide.util.NbBundle;
import org.openide.util.Mutex;
import org.openide.util.Utilities;
import org.openide.util.WeakSet;
import org.openide.util.datatransfer.*;
import org.openide.nodes.Node;

import org.netbeans.lib.terminalemulator.*;

/**
 * TopComponent for output tabs. It handles output in new winsts implementation.
 *
 * @author  Marek Slama
 *
 */

public class OutputView extends TopComponent implements PropertyChangeListener, ActionListener {


    private static final boolean DEBUG = false;
    
    public static final String ICON_RESOURCE =
        "/org/netbeans/core/resources/frames/output.gif"; // NOI18N
    
    /** If true, the error output is separated from the normal output */

    /** Mapping of string:OutputTabInner */
    static final Map ioCache = new WeakHashMap(7);

    /** Singleton instances of the standard output tabs */
    private static OutputTabInner standard;
    
    private static final long serialVersionUID = 3276523892250080205L;
    
    private static Factory factory;
    
    /** Singleton instance */
    private static OutputView DEFAULT;
    
    private JTabbedPane tabbedPane;
    
    /** Set of opened components in OutputView */
    private Set openedComps = new HashSet(10);
    
    /** Set of closed components in OutputView */
    private Set closedComps = new WeakSet(10);
    
    private String baseName;
    
    /**
     * State machine (State _enum_ really) for recognizing java exception
     * patterns.
     * See comment above appendText() for general idea.
     */
    private static class State {
	private final String name;
	private State(String name) { 
	    this.name = name;
	}
	public String toString() { return name; }

	public static final State init = new State("init");
	public static final State collect = new State("collect");
	public static final State pass = new State("pass");
    };

    private static void debug(String s) {
        if (!DEBUG) return;
        s = "OutputView:"+s+"\r\n"; // NOI18N
        try {
            String dir = outputSettings().getDirectory().getAbsolutePath();
            java.io.FileOutputStream fos = new java.io.FileOutputStream (dir + "/debug.log", true); // NOI18N
            fos.write(s.getBytes());
            fos.close();
        } catch (java.io.IOException e) {
            ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
        }
    }
    
    private OutputView () {
        synchronized (OutputView.class) {
            setActivatedNodes (null);
            
            setIcon(Utilities.loadImage("org/netbeans/core/resources/outputSettings.gif")); // NOI18N
        
            TopComponent.getRegistry().addPropertyChangeListener(
                org.openide.util.WeakListener.propertyChange(this, TopComponent.getRegistry()));
            
            // set accessiblle description
            getAccessibleContext ().setAccessibleName (
                NbBundle.getBundle (OutputView.class).getString ("ACSN_OutputWindow"));
            getAccessibleContext ().setAccessibleDescription (
                NbBundle.getBundle (OutputView.class).getString ("ACSD_OutputWindow"));
            setBorder(null);
            setLayout(new BorderLayout());
        }        
    }
    
    private OutputView (String name) {
        this();
        setName(name);
        baseName = name;
    }
    
    public void addNotify() {
        super.addNotify();
        TabHandlePopupListener.install();
    }
    
    /** Return preferred ID */
    protected String preferredID () {
        return "output"; //NOI18N
    }
    
    public void removeNotify() {
        TabHandlePopupListener.uninstall();
        super.removeNotify();
    }
    
    public void requestActive () {
        requestActive(true);
    }
    
    public void requestActive(boolean focus) {
        //Intentionally does not change active component if there is no
        //inner term to focus - this will leave winsys in an inconsistent
        //state - the active tc will be the output window but keyboard focus
        //will be in the editor
        if (focus) {
            Component c = getSelectedComponent();
            if (c != null) {
                if (c instanceof OutputTabInner) {
                    boolean focused = c.requestFocusInWindow();
                    if (focused) {
                        super.requestActive();
                    }
                }
            }
        }
    }
    
    /* Singleton accessor. As OutputView is persistent singleton this
     * accessor makes sure that OutputView is deserialized by window system.
     * Uses known unique TopComponent ID "output" to get OutputView instance
     * from window system. "output" is name of settings file defined in module layer.
     */
    public static synchronized OutputView findDefault () {
        if (DEFAULT == null) {
            TopComponent tc = WindowManager.getDefault().findTopComponent("output"); // NOI18N
            if (tc != null) {
                if (tc instanceof OutputView) {
                    DEFAULT = (OutputView) tc;
                } else {
                    //Incorrect settings file?
                    IllegalStateException exc = new IllegalStateException
                    ("Incorrect settings file. Unexpected class returned." // NOI18N
                    + " Expected:" + OutputView.class.getName() // NOI18N
                    + " Returned:" + tc.getClass().getName()); // NOI18N
                    ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, exc);
                    //Fallback to accessor reserved for window system.
                    OutputView.getDefault();
                }
            } else {
                //OutputView cannot be deserialized
                //Fallback to accessor reserved for window system.
                OutputView.getDefault();
            }
        }
        return DEFAULT;
    }
    
    /* Singleton accessor reserved for window system ONLY. Used by window system to create
     * OutputView instance from settings file when method is given. Use findDefault
     * to get correctly deserialized instance of OutputView. */
    public static synchronized OutputView getDefault () {
        if (DEFAULT == null) {
            DEFAULT = new OutputView(NbBundle.getBundle(OutputView.class).getString("CTL_OutputWindow_OutputTab"));
        }
        return DEFAULT;
    }
    
    /* Accessor reserved for window system, to discard the default instance on project switch. */
    public static synchronized void discardDefault() {
        if (DEFAULT != null) {
            final OutputView last = DEFAULT;
            DEFAULT = null;
            Mutex.EVENT.writeAccess(new Runnable() {
                public void run() {
                    last.clear();
                }
            });
        }
    }
    
    
    void clear() {
        discardAllTabs();
        closedComps.clear();
        close();
    }
    
    /** Overriden to explicitely set persistence type of OutputView
     * to PERSISTENCE_ALWAYS */
    public int getPersistenceType() {
        return TopComponent.PERSISTENCE_ALWAYS;
    }
    
    public static InputOutput getIO(String name, boolean newIO) {
        //System.out.println("++ OutputView.getIO ENTER");
        //Thread.dumpStack();
        InputOutput inpo = getFactory().getIO(name, newIO);
        /*System.out.println("++ OutputView.getIO RETURN"
        + " c:" + ((TopComponent) inpo).getName()
        + " [" + inpo.getClass().getName() + "]");*/
        return inpo;
    }

    public static OutputWriter getStdOut() {
        //System.out.println("++ OutputView.getStdOut");
        return getFactory().getStdOut ();
    }
    
    /** Reads OutputView.
    */
//    public void readExternal (ObjectInput oi)
//    throws IOException, ClassNotFoundException {
//        super.readExternal (oi);
//    }
    
    /** Writes OutputView. */
//    public void writeExternal (ObjectOutput oo) throws IOException {
//        super.writeExternal(oo);
//    }
    
    /** Resolve to singleton instance */
    public Object readResolve() throws java.io.ObjectStreamException {
        return OutputView.getDefault();
    }
    
    
    private JTabbedPane getTabbedPane() {
        if(tabbedPane == null) {
            tabbedPane = new JTabbedPane(JTabbedPane.TOP);
            tabbedPane.getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
                KeyStroke.getKeyStroke(KeyEvent.VK_F4, KeyEvent.CTRL_DOWN_MASK), 
                "discard"); //NOI18N
            tabbedPane.getActionMap().put("discard", new DiscardAction());
        }
        return tabbedPane;
    }
    
    private class DiscardAction extends AbstractAction {
        public void actionPerformed (ActionEvent ae) {
            discardTab();
        }
    }    
    
    // Methods to manipulate with tabs inside OutputView.
    /* Select component inside tab. */
    void requestVisible (final Component c) {
        /*System.out.println("OutputView.requestVisible ENTER"
        + " c:" + c.getName()
        + " th:" + Thread.currentThread().getName());
        Thread.dumpStack();*/
        Mutex.EVENT.readAccess(new Runnable() {
            public void run() {
                // The output TopComponent has to be visible too.
                OutputView.this.requestVisible();
                
                /*System.out.println("OutputView.requestVisible ENTER DELAYED"
                + " c:" + c.getName()
                + " th:" + Thread.currentThread().getName()
                + " isOpenedInOV(c):" + isOpenedInOV(c)
                + " openedComps.size:" + openedComps.size()); */
                if (isOpenedInOV(c) && (openedComps.size() > 1)) {
                    /* System.out.println("OutputView.requestVisible CALL OF setSelectedComponent"
                    + " c:" + c.getName()); */
                    JTabbedPane tab = getTabbedPane();
                    if (!c.equals(tab.getSelectedComponent())) {
                        //System.out.println("OutputView.requestVisible CALL OF");
                        tab.setSelectedComponent(c);
                        setActivatedNodes(((TopComponent) c).getActivatedNodes());
                    }
                } /*else {
                    System.out.println("OutputView.requestVisible NOT OPENED"
                    + " c:" + c.getName());
                }*/
                /*System.out.println("OutputView.requestVisible LEAVE DELAYED"
                + " c:" + c.getName()
                + " th:" + Thread.currentThread().getName());*/
            }
        });
    }
    
    /* Request focus on component in tab. */
    void requestFocus (final Component c) {
        Mutex.EVENT.readAccess(new Runnable() {
            public void run() {
                // The output TopComponent has to be active when the inner tab gets focus.
                OutputView.this.requestActive(false);
                if (isOpenedInOV(c)) {
                    if (openedComps.size() > 1) {
                        JTabbedPane tab = getTabbedPane();
                        if (!c.equals(tab.getSelectedComponent())) {
                            tab.setSelectedComponent(c);
                            setActivatedNodes(((TopComponent) c).getActivatedNodes());
                        }
                    }
                    c.requestFocusInWindow();
                }
            }
        });
    }
    
    /* Returns component selected in OutputView. Returns null when OutputView is empty
     * or when 'there is no tab selected' in JTabbedPane 
     * ie. return value from JTabbedPane.getSelectedComponent */
    Component getSelectedComponent () {
        if (openedComps.size() > 1) {
            return getTabbedPane().getSelectedComponent();
        } else if (openedComps.size() == 1) {
            return ((Component []) openedComps.toArray(new Component[1]))[0];
        } else {
            return null;
        }
    }
    
    /** Returns standard output top component */
    /*public static TopComponent getStdOutputTab() {
        System.out.println("++ OutputView.getStdOutputTab");
        return getFactory().getStdOutputTab();
    }*/
    
    private static OutputSettings outputSettings () {
        return (OutputSettings)OutputSettings.findObject (OutputSettings.class, true);
    }
    
    /* Returns text content of output tab. This is
    * content of terminal buffer, which is limited by
    * history size.
    * 

* This function is no MT-safe call it from the AWT Event Dispatch thread. * * @return text content of output window buffer */ public String toString () { return ""; } static synchronized Factory getFactory () { if (factory == null) { factory = new Factory(); } return factory; } private static synchronized void initialize () { if (standard == null) { // create the tab for StdOut String name = NbBundle.getBundle(OutputView.class).getString("CTL_OutputWindow_OutputTab"); standard = new OutputTabInner(name); // delete default behaviour of output tabs - remember even closed standard tab standard.putClientProperty("PersistenceType", null); // NOI18N } } public static class Factory { //implements OutputTabProvider { Factory () { //debug("OutputTabInner.Factory()"); // NOI18N } /** Print output writer. * @return default system output printer */ public OutputWriter getStdOut() { //System.out.println("OutputView.Factory.getStdOut()"); //debug("OutputTabInner.Factory.getStdOut()"); // NOI18N initialize(); return standard.getOut(); } /** creates new OutputWriter * @param name is a name of the writer * @return new OutputWriter with given name */ public InputOutput getIO(String name, boolean newIO) { //System.out.println("OutputView.Factory.getIO("+ name + ", " + newIO + ")"); //debug("OutputTabInner.Factory.getIO("+name+", "+newIO+")"); // NOI18N initialize(); if (newIO) { //debug("..creating new"); // NOI18N /*System.out.println("OutputView.Factory.getIO" + " CREATE NEW 1");*/ return new OutputTabInner(name); } else { InputOutput ino; synchronized(ioCache) { ino = (InputOutput)ioCache.get(name); } if (ino == null) { //debug("..cannot find - creating new"); // NOI18N /*System.out.println("OutputView.Factory.getIO" + " CREATE NEW 2");*/ ino = new OutputTabInner(name); } else { //debug("using existing"); // NOI18N /*System.out.println("OutputView.Factory.getIO" + " USE EXISTING");*/ } return ino; } } /** Returns standard output top component */ public TopComponent getStdOutputTab() { //System.out.println("OutputView.Factory.getStdOutputTab"); //debug("OutputTabInner.Factory.getStdOutputTab()"); // NOI18N initialize(); return standard; } } // OutputTabs are not serialized // null is returned during deserialization // only standard output tab is dseserialized to // default instance /** This class is serializaed instead of OutputView */ static class Replace implements java.io.Serializable { private static final long serialVersionUID =-3237844916624172415L; public Replace () { } /** Resolve as default singleton or null */ public Object readResolve() throws java.io.ObjectStreamException { return OutputView.getDefault(); } } // public boolean isClosed() { // //debug("isClosed()"); // NOI18N // Workspace wrkSpace = WindowManager.getDefault().getCurrentWorkspace(); // return !isOpened(wrkSpace); // } // void ensureOpen() { // //debug("ensureOpen()"); // NOI18N // if (isClosed()) { // //debug("opening"); // NOI18N // open(); // } // } /** Returns true if given component is opened in OutputView */ public boolean isOpenedInOV (Component c) { return openedComps.contains(c); } /** Returns true if given component is closed and present in OutputView. * For example it could be opened and closed. */ public boolean isClosedInOV (Component c) { return closedComps.contains(c); } /* Opens component in OutputView */ public void openInOV (final Component c) { /* System.out.println("-- OutputView.openInOV ENTER" + " c:" + c.getName() + " [" + Integer.toHexString(System.identityHashCode(c)) + "]" + " th:" + Thread.currentThread().getName()); */ //Open OutputView Mutex.EVENT.readAccess(new Runnable() { public void run() { /*System.out.println("-- OutputView.openInOV ENTER DELAYED" + " c:" + c.getName() + " [" + Integer.toHexString(System.identityHashCode(c)) + "]" + " th:" + Thread.currentThread().getName()); */ //Open OutputView if (!isOpened()) { open(); } if (isOpenedInOV(c)) { //Already opened /*System.out.println("-- OutputView.openInOV LEAVE 1 DELAYED" + " c:" + c.getName()); */ return; } /* System.out.println("-- OutputView.openInOV DELAYED" + " c:" + c.getName() + " th:" + Thread.currentThread().getName() + " CALL OF addTab openedComps.size=" + openedComps.size()); */ if (openedComps.size() == 0) { //Add component directly to OutputView add(c); revalidate(); setActivatedNodes(((TopComponent) c).getActivatedNodes()); setName(baseName + " - " + c.getName()); getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put( KeyStroke.getKeyStroke(KeyEvent.VK_F4, KeyEvent.CTRL_DOWN_MASK), "discard"); //NOI18N getActionMap().put("discard", new DiscardAction()); } else if (openedComps.size() == 1) { Component old = getComponents()[0]; remove(old); JTabbedPane tab = getTabbedPane(); add(tab); tab.addTab(old.getName(),old); tab.addTab(c.getName(),c); setActivatedNodes(((TopComponent) c).getActivatedNodes()); setName(baseName); getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).remove( KeyStroke.getKeyStroke(KeyEvent.VK_F4, KeyEvent.CTRL_DOWN_MASK)); getTabbedPane().addTab(c.getName(),c); setActivatedNodes(((TopComponent) c).getActivatedNodes()); } if (closedComps.contains(c)) { closedComps.remove(c); } openedComps.add(c); if (openedComps.size() > 1) { JTabbedPane tab = getTabbedPane(); if (tab.getTabCount() != openedComps.size()) { tab.add (c.getName(), c); } } /*System.out.println("-- OutputView.openInOV LEAVE 2 DELAYED" + " c:" + c.getName());*/ } }); /*System.out.println("-- OutputView.openInOV LEAVE 2" + " c:" + c.getName() + " [" + Integer.toHexString(System.identityHashCode(c)) + "]");*/ } /** Creates and returns popup menu for given top component, * filled with standard action presenters for window actions */ protected JPopupMenu createPopupMenu () { JPopupMenu popup = new JPopupMenu(); JMenuItem menuItem = new JMenuItem (NbBundle.getBundle(OutputView.class).getString("LBL_Discard")); menuItem.setActionCommand("Discard"); menuItem.addActionListener(this); popup.add(menuItem); menuItem = new JMenuItem (NbBundle.getBundle(OutputView.class).getString("LBL_DiscardAll")); menuItem.setActionCommand("DiscardAll"); menuItem.addActionListener(this); popup.add(menuItem); return popup; } /** Shows given popup on given coordinations and takes care about the * situation when menu can exceed screen limits */ protected void showPopupMenu (JPopupMenu popup, Point p, Component comp) { SwingUtilities.convertPointToScreen (p, comp); Dimension popupSize = popup.getPreferredSize (); Rectangle screenBounds = Utilities.getUsableScreenBounds(getGraphicsConfiguration()); if (p.x + popupSize.width > screenBounds.x + screenBounds.width) { p.x = screenBounds.x + screenBounds.width - popupSize.width; } if (p.y + popupSize.height > screenBounds.y + screenBounds.height) { p.y = screenBounds.y + screenBounds.height - popupSize.height; } SwingUtilities.convertPointFromScreen (p, comp); popup.show(comp, p.x, p.y); } // // Static stuff // static String getOutDisplayName() { return NbBundle.getBundle(OutputView.class).getString("CTL_OutputWindow"); } // // TopComponent methods // /** always open this top component in output mode, if * no mode for this component is specified yet */ public void open (Workspace workspace) { //debug("OutputTabInner.open():"+getName()); // NOI18N if (!isShowing()) { Workspace realWorkspace = (workspace == null) ? WindowManager.getDefault().getCurrentWorkspace() : workspace; // dock into outwin mode if not docked yet Mode mode = realWorkspace.findMode("output"); // NOI18N if (mode == null) { mode = realWorkspace.createMode("output", getOutDisplayName(), // NOI18N OutputView.class.getResource(ICON_RESOURCE)); } Mode tcMode = realWorkspace.findMode(this); if (tcMode == null) { mode.dockInto(this); } // behave like superclass super.open(workspace); } else { requestActive(); } } // // inner classes // // Replacement for TopComponentListener. Listen on opened components. public void propertyChange(PropertyChangeEvent evt) { } public void actionPerformed(ActionEvent e) { if ("Discard".equals(e.getActionCommand())) { discardTab(); } else if ("DiscardAll".equals(e.getActionCommand())) { discardAllTabs(); } } /* Close selected inner tab */ void discardTab () { Mutex.EVENT.readAccess(new Runnable() { public void run() { Component c = getSelectedComponent(); if (c == null) { return; } discardTab(c); } }); } /** Called by OutputTabInner in doClose() to close the tab when the * output is closed. Must be called on the event thread */ void discardTab (Component c) { if (openedComps.size() > 2) { getTabbedPane().remove(c); setActivatedNodes(((TopComponent) getSelectedComponent()).getActivatedNodes()); } else if (openedComps.size() == 2) { JTabbedPane tab = getTabbedPane(); remove(tab); tab.remove(c); Component old = tab.getComponentAt(0); tab.remove(old); add(old); setActivatedNodes(((TopComponent) old).getActivatedNodes()); setName(baseName + " - " + old.getName()); getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put( KeyStroke.getKeyStroke(KeyEvent.VK_F4, KeyEvent.CTRL_DOWN_MASK), "discard"); //NOI18N getActionMap().put("discard", new DiscardAction()); } else if (openedComps.size() == 1) { getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).remove( KeyStroke.getKeyStroke(KeyEvent.VK_F4, KeyEvent.CTRL_DOWN_MASK)); remove(c); setActivatedNodes(new Node[0]); setName(baseName); } revalidate(); repaint(); openedComps.remove(c); closedComps.add(c); } /* Close all inner tabs */ void discardAllTabs () { Mutex.EVENT.readAccess(new Runnable() { public void run() { if (openedComps.size() > 1) { JTabbedPane tab = getTabbedPane(); tab.removeAll(); remove(tab); } else if (openedComps.size() == 1) { remove(((Component []) openedComps.toArray(new Component[1]))[0]); setName(baseName); } setActivatedNodes(new Node[0]); revalidate(); repaint(); closedComps.addAll(openedComps); openedComps.clear(); } }); } /*private static void invokeLater(Runnable runnable) { if (SwingUtilities.isEventDispatchThread()) { runnable.run(); } else { SwingUtilities.invokeLater(runnable); } }*/ /* DEBUG private static void ckEventDispatchThread() { if (!SwingUtilities.isEventDispatchThread()) { System.out.println("OW: NOT IN EventDispatchThread"); Thread.dumpStack(); } } */ }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.