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-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.core.compiler;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.ResourceBundle;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;

import org.openide.loaders.DataObject;
import org.openide.text.Line;
import org.openide.text.Annotation;
import org.openide.text.Annotatable;
import org.openide.ErrorManager;
import org.openide.compiler.*;
import org.openide.cookies.LineCookie;
import org.openide.filesystems.FileObject;
import org.openide.windows.InputOutput;
import org.openide.windows.OutputEvent;
import org.openide.windows.OutputListener;
import org.openide.windows.OutputWriter;
import org.openide.util.NbBundle;

import org.netbeans.core.output.OutputTabInner;
import org.netbeans.core.output.OutputSettings;
import org.openide.awt.StatusDisplayer;
import org.openide.util.Mutex;
import org.openide.windows.IOProvider;

/** This class is responsible for displaying the messages
* as a reactions to the state changes and errors produced by
* the compiler.
*
* @author Ales Novak, Ian Formanek, Petr Hamernik, Jaroslav Tulach
*/
final class CompilerDisplayer extends Object implements CompilerListener, ActionListener {
    /** output tab */
    private InputOutput compilerIO;
    /** writer to that tab */
    private OutputWriter ow = null;
    /** format for errors */
    private MessageFormat errorMsg;
    /** format for error description */
    private MessageFormat errorDescr;
    /** message for compiling */
    private MessageFormat compilingMsg;
    /** compilaton successful */
    private MessageFormat compSuccess;
    /** compilaton unsuccessful */
    private MessageFormat compUnsuccess;
    /** compilation started */
    private MessageFormat compStarted;
    /** compiling progress status messages */
    private static String parsing;
    private static String generating;
    private static String writing;
    private static String cleaning;
    
    /** Swing Timer which posts setStatusText only every 100 ms */
    private Timer statusTextTimer;
    /** Text to set */
    private String statusText;
    /** List of ErrorEvents */
    private ErrorCtl lastError;

    /** flag to test whether the tab has been selected or not */
    private boolean notSelected = true;
    
    public CompilerDisplayer () {
        // bundle
        final ResourceBundle bundle = NbBundle.getBundle (CompilerDisplayer.class);
        if (parsing == null) {
            parsing = bundle.getString ("MSG_StatusParsing");
            writing = bundle.getString ("MSG_StatusWriting");
            generating = bundle.getString ("MSG_StatusGenerating");
            cleaning = bundle.getString ("MSG_StatusCleaning");
        }
        errorMsg = new MessageFormat (bundle.getString ("MSG_CompileError"));
        errorDescr = new MessageFormat (bundle.getString ("MSG_CompileErrorDescr"));
        compilingMsg = new MessageFormat (bundle.getString ("MSG_Compiling"));
        compSuccess = new MessageFormat (bundle.getString ("MSG_CompilationSuccessful"));
        compUnsuccess = new MessageFormat (bundle.getString ("MSG_CompilationUnsuccessful"));
        compStarted = new MessageFormat (bundle.getString ("MSG_CompilationStarted"));
    }

    /****** Implementation of the CompilerListener interface *******/

    /** Displayes status text as a reaction to the
    * notification of compilation progress.
    *
    * @param ev event that holds information about currently compiled object
    */
    public void compilerProgress (ProgressEvent ev) {
        // choose right message
        String status = null;
        switch (ev.getTask()) {
        case ProgressEvent.TASK_PARSING: status = parsing; break;
        case ProgressEvent.TASK_WRITING: status = writing; break;
        case ProgressEvent.TASK_GENERATING: status = generating; break;
        case ProgressEvent.TASK_CLEANING: status = cleaning; break;
        default: status = parsing; break;
        }
        if (status == null) return;
        Object[] args = new Object[] {
                            status,
                            ev.getFile().getPath()
                        };
        String msg = compilingMsg.format (args);
        setStatusText (msg);
    }

    /** Displayes error line in output window as a reaction to the
    * notification that an error occured in the compiler.
    * @param ev event describing that error
    */
    public void compilerError(ErrorEvent ev) {
        javax.swing.SwingUtilities.invokeLater(new AWTDispatcher(ev));
    }

    int dispatcherCounts = 0;
    final synchronized void newDispatcher() {
        dispatcherCounts++;
    }
    final synchronized void dispatcherEnd() {
        dispatcherCounts--;
        notify();
    }
    final synchronized void dispatcherWait() throws InterruptedException {
        while (dispatcherCounts > 0) {
            wait();
        }
    }
    
    final class AWTDispatcher implements Runnable {
        private ErrorEvent ev;
        
        AWTDispatcher(ErrorEvent ev) {
            this.ev = ev;
            newDispatcher();
        }
        
        public void run () {
            initialize ();

            ensureSelect();

            if (ev.getFile() == null) {
                String msg = ev.getMessage();
                if (!msg.equals("")) { // NOI18N
                    if (msg.startsWith("\n")) // NOI18N
                        msg = msg.substring(1);
                    println(msg);
                    ow.flush();
                }
                dispatcherEnd();
                return;
            }

            Object[] args = new Object[] {
                                ev.getFile ().getPath(),
                                new Integer (ev.getLine ()),
                                new Integer (ev.getColumn ()),
                                ev.getMessage ()
                            };
            String text = errorMsg.format (args);
            try {
                int line = Math.max(ev.getLine() - 1, 0);
                Integer lineCov = new Integer(line);
                ErrorCtl ec = new ErrorCtl (
                                  ev.getFile(),
                                  line,
                                  Math.max(ev.getColumn() - 1, 0),
                                  text,
                                  ev.getMessage()
                              );
                println(text, ec);
            } catch (IOException ex) {
                println (text);
            }
            
            String refText = ev.getReferenceText();
            if (refText != null && ! refText.equals("")) { // NOI18N
                if (refText.startsWith("\n")) // NOI18N
                    refText = refText.substring(1);
                println (errorDescr.format (new Object[] { refText }));
            }
            // ow.println (""); // NOI18N
            dispatcherEnd();
        }
    }
    
    private static Object[] taskToArgs (CompilerTaskImpl task) {
        return new Object[] {
            task.getDisplayName (),
            "".equals (task.getDisplayName ()) ? new Integer (0) : new Integer (1) // NOI18N
        };
    }

    /** Displayes information that compilation has just started. */
    void compilationStarted (final CompilerTaskImpl task) {
        initialize ();
        setStatusText(compStarted.format (taskToArgs (task)));
        try {
            ow.reset ();
            notSelected = true;
        } catch (java.io.IOException ex) {
            ErrorManager.getDefault().notify (ex);
        }
        lastError = null;
    }
    
    private void ensureSelect() {
        if (notSelected) {
            notSelected = false;
            compilerIO.select ();
        }
    }

    /** Displayes information that compilation has finished,
    * and whether succesfully or not. */
    public void compilationFinished (final CompilerTaskImpl task, boolean uptodate) {
        boolean always_print = true;
        if ( !alwaysOpenAfterCompile() && task.isSuccessful() && compilerIO.isClosed() )
            always_print = false;
        try {
            initialize ();
            MessageFormat msg = task.isSuccessful() ? compSuccess : compUnsuccess;
            dispatcherWait();
            String fimsg = msg.format (taskToArgs (task));
            setStatusText(fimsg);
            if (always_print) {
                ensureSelect();
                if (uptodate) {
                    println(NbBundle.getBundle(CompilerDisplayer.class).getString("MSG_UpToDate"));
                }
                println(fimsg);
            }
        } catch (InterruptedException e) {
            org.openide.ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, e);
        } finally {
            Mutex.EVENT.writeAccess(new Runnable() {
                public void run() {
            AnnotationImpl impl = AnnotationImpl.getAnnotation();
            impl.detach(null);
            // akemr - OW needs to know, when compilation finished
            if ( compilerIO instanceof OutputTabInner ) {
                ((OutputTabInner)compilerIO).setCompilationFinished();
            }
                }
            });
        }
    }
    /*
    private static final void log(String msg) {
        org.openide.ErrorManager.getDefault().log(5, msg);
    }
    
    private static final void logStack() {
        java.io.StringWriter sw = new java.io.StringWriter();
        java.io.PrintWriter pw = new java.io.PrintWriter(sw, true);
        new Exception().printStackTrace(pw);
        log(sw.toString());
    }*/

    private void initialize () {
        if (ow == null) {
            synchronized (this) {
                // prepare output tab
                setOw (NbBundle.getBundle (CompilerDisplayer.class).getString ("CTL_CompileTab"));
            }
        }
    }

    private void setOw (String name) {
        if (ow != null) return;
        compilerIO = IOProvider.getDefault().getIO(name, true);
        compilerIO.setFocusTaken (false);
        ow = compilerIO.getOut();
    }
    
    private long lastTime = 0;

    /** Sets text to status line
    */
    public void setStatusText (String text) {
        boolean notifyNow;
        synchronized (this) {
            statusText = text;
            long currentTime = System.currentTimeMillis();
            notifyNow = (currentTime - lastTime) > 250;
        }
        if (notifyNow) {
            actionPerformed(null);
        } else {
            getStatusTextTimer().restart();
        }
    }

    private Timer getStatusTextTimer() {
        if (statusTextTimer == null) {
            statusTextTimer = new Timer(250, this);
            statusTextTimer.setRepeats(false);
        }
        return statusTextTimer;
    }
    
    public void actionPerformed(java.awt.event.ActionEvent p1) {
        String print;
        synchronized (this) {
            if (statusText == null) {
                return;
            }
            print = statusText;
            statusText = null;
            lastTime = System.currentTimeMillis();
        }
        
        StatusDisplayer.getDefault().setStatusText(oneLine(print));
    }
    
    /** Removes newlines from the string */
    private static String oneLine(final String txt) {
        StringBuffer sb = new StringBuffer(txt.length());
        boolean lastIsNewline = false;
        for (int i = 0; i < txt.length(); i++) {
            char ch = txt.charAt(i);
            if (ch == '\n' || ch == '\r') {
                if (! lastIsNewline) {
                    lastIsNewline = true;
                    sb.append(' ');
                }
            } else {
                sb.append(ch);
                lastIsNewline = false;
            }
        }
        return sb.toString();
    }
    
    private static boolean alwaysOpenAfterCompile () {
        OutputSettings settings = (OutputSettings)OutputSettings.findObject (OutputSettings.class, true);
        if ( settings != null )
            return settings.isAlwaysOpenAfterCompile();
        return true;
    }

    /** Prints the text */
    final void println(String msg) {
        if (lastError != null) {
            OutputController ctl = new OutputController(lastError);
            lastError = null;
            try {
                println(msg, ctl);
            } catch (IOException e) {
                println(msg);
            }
        } else {
            ow.println(msg);
        }
    }

    /** Prints the text */
    final void println(final String msg, OutputListener err) throws IOException {
        if (err instanceof ErrorCtl) {
            lastError = (ErrorCtl) err;
        }
        ow.println(msg, err);
    }
        
    final class OutputController implements OutputListener {
        private ErrorCtl ctl;
        
        OutputController(ErrorCtl ctl) {
            this.ctl = ctl;
        }
        
        public void outputLineSelected(OutputEvent ev) {
            ctl.outputLineSelected(ev);
        }

        public void outputLineAction(OutputEvent ev) {
            ctl.outputLineAction(ev);
        }

        public void outputLineCleared(OutputEvent ev) {
        }
    }

    final class ErrorCtl implements OutputListener {
        /** file we check */
        FileObject file;

        /** line we check */
        Line xline;

        /** column with the err */
        int column;

        /** text to display */
        private String text;
        
        /** text to display */
        private String shortMsg;
        
        /**
        * @param fo is a FileObject with an error
        * @param line is a line with the error
        * @param column is a column with the error
        * @param text text to display to status line
        * @exception FileNotFoundException
        */
        public ErrorCtl (FileObject fo, int line, int column, String text, String shortMsg)
        throws java.io.IOException {
            file = fo;
            this.column = column;
            DataObject data = DataObject.find (file);
            LineCookie cookie = (LineCookie)data.getCookie(LineCookie.class);
            if (cookie == null) {
                throw new java.io.FileNotFoundException ();
            }
            xline = cookie.getLineSet ().getOriginal (line);
            this.text = text;
            this.shortMsg = shortMsg;
        }

        public void outputLineSelected (OutputEvent ev) {
            AnnotationImpl impl = AnnotationImpl.getAnnotation();
            impl.setShortDescription(shortMsg);
            setStatusText(shortMsg);
            impl.attach(this, xline);
            xline.show(Line.SHOW_TRY_SHOW, column);
        }

        public void outputLineAction (OutputEvent ev) {
            AnnotationImpl impl = AnnotationImpl.getAnnotation();
            impl.setShortDescription(shortMsg);
            setStatusText(shortMsg);
            impl.attach(this, xline);
            xline.show(Line.SHOW_GOTO, column);
        }

        public void outputLineCleared (OutputEvent ev) {
            AnnotationImpl impl = AnnotationImpl.getAnnotation();
            impl.detach(this);
        }
        
    } // end of ErrorCtl inner class
    
    /** Implements Annotation */
    static final class AnnotationImpl extends Annotation implements PropertyChangeListener {
        private static AnnotationImpl INSTANCE;
        
        private String text;
        private ErrorCtl currentCtl;
        
        public static AnnotationImpl getAnnotation() {
            if (INSTANCE == null) {
                INSTANCE = new AnnotationImpl();
            }
            
            return INSTANCE;
        }
        
        /** Returns name of the file which describes the annotation type.
         * The file must be defined in module installation layer in the
         * directory "Editors/AnnotationTypes"
         * @return  name of the anotation type */
        public String getAnnotationType() {
            return "org-netbeans-core-compiler-error"; // NOI18N
        }
        
        /** Returns the tooltip text for this annotation.
         * @return  tooltip for this annotation */
        public String getShortDescription() {
            return text;
        }
        
        /** Sets the tooltip text */
        public void setShortDescription(String text) {
            this.text = text;
        }
        
        public void attach(ErrorCtl ctl, Line line) {
            if (currentCtl != null) {
                detach(currentCtl);
            }
            currentCtl = ctl;
            attach(line);
            line.addPropertyChangeListener(this);
        }
        
        public void detach(ErrorCtl ectl) {
            if (ectl == currentCtl || ectl == null) {
                currentCtl = null;
                Annotatable at = getAttachedAnnotatable();
                if (at != null) {
                    at.removePropertyChangeListener(this);
                }
                detach();
            }
        }
        
        public void propertyChange(PropertyChangeEvent ev) {
            if (Annotatable.PROP_TEXT.equals(ev.getPropertyName())) {
                detach(null);
            }
        }
    }
}
... 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.