Hyperlink.java :  » IDE-Netbeans » collab » org » netbeans » modules » collab » channel » output » Java Open Source

Java Open Source » IDE Netbeans » collab 
collab » org » netbeans » modules » collab » channel » output » Hyperlink.java
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common
 * Development and Distribution License("CDDL") (collectively, the
 * "License"). You may not use this file except in compliance with the
 * License. You can obtain a copy of the License at
 * http://www.netbeans.org/cddl-gplv2.html
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 * specific language governing permissions and limitations under the
 * License.  When distributing the software, include this License Header
 * Notice in each file and include the License file at
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the
 * License Header, with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Contributor(s):
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 *
 * If you wish your version of this file to be governed by only the CDDL
 * or only the GPL Version 2, indicate your decision by adding
 * "[Contributor] elects to include this software in this distribution
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 * single choice of license, a recipient has the option to distribute
 * your version of this file under either the CDDL, the GPL Version 2 or
 * to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 * Version 2 license, then the option applies only if the new code is
 * made subject to such option by the copyright holder.
 */
package org.netbeans.modules.collab.channel.output;

import org.openide.ErrorManager;
import org.openide.awt.StatusDisplayer;
import org.openide.cookies.EditorCookie;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.URLMapper;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.text.Annotatable;
import org.openide.text.Annotation;
import org.openide.text.Line;
import org.openide.util.WeakSet;
import org.openide.windows.OutputEvent;
import org.openide.windows.OutputListener;

import java.awt.Toolkit;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import java.io.IOException;

import java.net.URL;

import java.util.Iterator;
import java.util.Set;


/**
 * Represents a linkable line (appears in red in Output Window).
 * Line and column numbers start at 1, and -1 means an unknown value.
 * Careful since org.openide.text seems to assume 0-based line and column numbers.
 * @author Jesse Glick
 */
public final class Hyperlink extends Annotation implements OutputListener, PropertyChangeListener {
    // #14804: detach everything before uninstalling module.
    private static final Set hyperlinks = new WeakSet(); // Set<Hyperlink>
    private final URL url;
    private final String message;
    private final int line1;
    private int col1;
    private final int line2;
    private final int col2;
    private boolean dead = false;

    private static final ErrorManager err = ErrorManager.getDefault().getInstance("org.apache.tools.ant.module"); // NOI18N

    public Hyperlink(URL url, String message, int line1, int col1, int line2, int col2) {
        this.url = url;
        this.message = message;
        this.line1 = line1;
        this.col1 = col1;
        this.line2 = line2;
        this.col2 = col2;

        synchronized (hyperlinks) {
            hyperlinks.add(this);
        }
    }

    public static void detachAllAnnotations() {
        synchronized (hyperlinks) {
            Iterator it = hyperlinks.iterator();

            while (it.hasNext()) {
                ((Hyperlink) it.next()).destroy();
            }
        }
    }

    /**
     * Enables the column number of the hyperlink to be changed after the fact.
     * If it is already set, this is ignored.
     */
    public void setColumn1(int col1) {
        if (this.col1 == -1) {
            this.col1 = col1;
        }
    }

    void destroy() {
        doDetach();
        dead = true;
    }

    public void outputLineAction(OutputEvent ev) {
        if (dead) {
            return;
        }

        FileObject file = URLMapper.findFileObject(url);

        if (file == null) { // #13115
            Toolkit.getDefaultToolkit().beep();

            return;
        }

        try {
            DataObject dob = DataObject.find(file);
            EditorCookie ed = (EditorCookie) dob.getCookie(EditorCookie.class);

            if ((ed != null) && /* not true e.g. for *_ja.properties */
                    (file == dob.getPrimaryFile())) {
                if (line1 == -1) {
                    // OK, just open it.
                    ed.open();
                } else {
                    ed.openDocument(); // XXX getLineSet does not do it for you!
                    err.log("opened document for " + file);

                    try {
                        Line l = ed.getLineSet().getOriginal(line1 - 1);

                        if (!l.isDeleted()) {
                            attachAsNeeded(l);

                            if (col1 == -1) {
                                l.show(Line.SHOW_GOTO);
                            } else {
                                l.show(Line.SHOW_GOTO, col1 - 1);
                            }
                        }
                    } catch (IndexOutOfBoundsException ioobe) {
                        // Probably harmless. Bogus line number.
                        ed.open();
                    }
                }
            } else {
                Toolkit.getDefaultToolkit().beep();
            }
        } catch (DataObjectNotFoundException donfe) {
            ErrorManager.getDefault().notify(ErrorManager.WARNING, donfe);
        } catch (IOException ioe) {
            // XXX see above, should not be necessary to call openDocument at all
            ErrorManager.getDefault().notify(ErrorManager.WARNING, ioe);
        }

        if (message != null) {
            // Try to do after opening the file, since opening a new file
            // clears the current status message.
            StatusDisplayer.getDefault().setStatusText(message);
        }
    }

    public void outputLineSelected(OutputEvent ev) {
        if (dead) {
            return;
        }

        FileObject file = URLMapper.findFileObject(url);

        if (file == null) {
            return;
        }

        try {
            DataObject dob = DataObject.find(file);
            EditorCookie ed = (EditorCookie) dob.getCookie(EditorCookie.class);

            if (ed != null) {
                if (ed.getDocument() == null) {
                    // The document is not opened, don't bother with it.
                    // The Line.Set will be corrupt anyway, currently.
                    err.log("no document for " + file);

                    return;
                }

                err.log("got document for " + file);

                if (line1 != -1) {
                    Line l = ed.getLineSet().getOriginal(line1 - 1);

                    if (!l.isDeleted()) {
                        attachAsNeeded(l);

                        if (col1 == -1) {
                            l.show(Line.SHOW_TRY_SHOW);
                        } else {
                            l.show(Line.SHOW_TRY_SHOW, col1 - 1);
                        }
                    }
                }
            }
        } catch (DataObjectNotFoundException donfe) {
            ErrorManager.getDefault().notify(ErrorManager.WARNING, donfe);
        } catch (IndexOutOfBoundsException iobe) {
            // Probably harmless. Bogus line number.
        }
    }

    private synchronized void attachAsNeeded(Line l) {
        if (getAttachedAnnotatable() == null) {
            boolean log = err.isLoggable(ErrorManager.INFORMATIONAL);
            Annotatable ann;

            // Text of the line, incl. trailing newline.
            String text = l.getText();

            if (log) {
                err.log(
                    "Attaching to line " + l.getDisplayName() + " text=`" + text + "' line1=" + line1 + " line2=" +
                    line2 + " col1=" + col1 + " col2=" + col2
                );
            }

            if ((text != null) && ((line2 == -1) || (line1 == line2)) && (col1 != -1)) {
                int new_col1 = convertTabColumnsToCharacterColumns(text, col1 - 1, 8);
                int new_col2 = convertTabColumnsToCharacterColumns(text, col2 - 1, 8);

                if (log) {
                    err.log("\tfits on one line");
                }

                if ((new_col2 != -1) && (new_col2 >= new_col1) && (new_col2 < text.length())) {
                    if (log) {
                        err.log("\tspecified section of the line");
                    }

                    ann = l.createPart(new_col1, new_col2 - new_col1 + 1);
                } else if (new_col1 < text.length()) {
                    if (log) {
                        err.log("\tspecified column to end of line");
                    }

                    ann = l.createPart(new_col1, text.length() - new_col1 - 1);
                } else {
                    if (log) {
                        err.log("\tcolumn numbers are bogus");
                    }

                    ann = l;
                }
            } else {
                if (log) {
                    err.log("\tmultiple lines, something wrong with line, or no column given");
                }

                ann = l;
            }

            attach(ann);

            // #17625: detach others however
            Iterator it = hyperlinks.iterator();

            while (it.hasNext()) {
                Hyperlink h = (Hyperlink) it.next();

                if (h != this) {
                    h.doDetach();
                }
            }

            ann.addPropertyChangeListener(this);
        }
    }

    // XXX should be handled in StandardLogger, perhaps?
    private int convertTabColumnsToCharacterColumns(String text, int column, int tabSize) {
        // #16867 - jikes is right now only compiler which reports column of the error.
        // If the text contains 'tab' character, the jikes expects
        // that tab character is defined as 8 spaces, and so it sets the column accordingly.
        // This method converts jikes columns back to character columns
        char[] textChars = text.toCharArray();
        int i;
        int jikes_column = 0;

        for (i = 0; (i < textChars.length) && (jikes_column < column); i++) {
            if (textChars[i] == 9) {
                jikes_column += (tabSize - (jikes_column % tabSize));
            } else {
                jikes_column++;
            }
        }

        return i;
    }

    private synchronized void doDetach() {
        Annotatable ann = getAttachedAnnotatable();

        if (ann != null) {
            if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
                err.log("Detaching from " + ann + " `" + ann.getText() + "'");
            }

            ann.removePropertyChangeListener(this);
            detach();
        }
    }

    public void outputLineCleared(OutputEvent ev) {
        doDetach();
    }

    public void propertyChange(PropertyChangeEvent ev) {
        if (dead) {
            return;
        }

        String prop = ev.getPropertyName();

        if ((prop == null) || prop.equals(Annotatable.PROP_TEXT) || prop.equals(Annotatable.PROP_DELETED)) {
            // Affected line has changed.
            // Assume user has edited & corrected the error.
            if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
                err.log("Received Annotatable property change: " + prop);
            }

            doDetach();
        }
    }

    public String getAnnotationType() {
        return "org-apache-tools-ant-module-error"; // NOI18N
    }

    public String getShortDescription() {
        if (message != null) {
            return message;
        } else {
            return null;
        }
    }

    public String toString() {
        return "Hyperlink[" + url + ":" + line1 + ":" + col1 + ":" + line2 + ":" + col2 + "]"; // NOI18N
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.