X

Geertjan's Blog

  • July 7, 2007

Simultaneous Multi File Link Check Feature

Geertjan Wielenga
Product Manager
My link checker has turned into a pretty useful feature already, despite some minor flaws. Either on an HTML document's node, or in the HTML editor, or on a folder containing at least one HTML document, I can now select the new 'Link Check' menu item. When chosen on document-level, the Output window then immediately contains a list of hyperlinks, one for each HREF attribute in the document, prefaced either by 'ok' or 'broken'. When an 'ok' hyperlink is clicked, the corrctly linked document opens in the editor. When a 'broken' hyperlink is clicked, the document in which the HREF attribute is defined opens and the cursor lands on the offending line.

But one doesn't want to do a document-by-document link check, does one? One would rather right-click a folder and choose 'Link Check'. In that case, all HTML documents within the folder are link checked and only the broken links are written to the Output window (otherwise the list of hyperlinks would be too long, i.e., if the 'ok' hyperlinks were also written there). The result can be seen in the screenshot below:

The folder-level "Link Check" menu item is only enabled if at least one HTML document is found within the folder. This is how to do that:

@Override
protected boolean enable(Node[] activatedNodes) {
if (super.enable(activatedNodes)) {//Look up the node's data folder:
DataFolder dFo = activatedNodes[0].getLookup().lookup(org.openide.loaders.DataFolder.class);
if (!(dFo == null)) {
DataObject[] objs;//Get the children of the data folder:
objs = dFo.getChildren();//If there is at least one HTML file, return true:
for (int i = 0; i < objs.length; i++) {
DataObject dataObject = objs[i];
if (dataObject.getPrimaryFile().getMIMEType().equals("text/html")) {
return true;
}
}
}
}
return false;
}

And that's it. Notice that here we are overriding the CookieAction.enable method. This is an extremely powerful method. Even before the user invokes the menu item, this method is called. As a result, you can use it to determine whether the menu item is enabled or disabled, depending on whatever conditions you set, such as, in the above case, the content of the folder. In fact, it is a filter that narrows the scope of the CookieAction. Here, although the menu item can be seen in the contextual menu item of all folders, it will only be enabled when at least one HTML file is found within the folder.

The handleStartTag method, in the HTMLEditorKit.ParserCallback class, which was mentioned yesterday, is filled out to handle various values that come from identified HREF attributes. A variety of different kinds of values could be returned, such as internal links (prefaced by #) and "nbdocs" links. These are excluded. Other values are relative links. For these, the data object's parent, or parent's parent, is needed to resolve the link. My solution here is incomplete, but gets the job done for my needs.

public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
if (t.toString().equals("a")) {
try {//Get the HREF attribute's value:
java.lang.String value = (java.lang.String) a.getAttribute(HTML.Attribute.HREF);//Exclude internal links and 'nbdocs' links:
if (value.startsWith("nbdocs") || value.startsWith("#")) {
return;
}//Create the full URL to the HREF value,
//solution here is imperfect and incomplete:

java.lang.String url;
if (value.startsWith("../..")) {
url = "/" + dataObject.getPrimaryFile().getParent().getParent().getParent().getPath() + value.substring(5);
} else if (value.startsWith("..")) {
url = "/" + dataObject.getPrimaryFile().getParent().getParent().getPath() + value.substring(2);
} else {
url = "/" + dataObject.getPrimaryFile().getParent().getPath() + "/" + value;
}//Get line number and subtract 1:
int lineNo = NbDocument.findLineNumber(ec, pos);
int realLineNo = lineNo - 1;//Create the file object from the string:
org.openide.filesystems.FileObject fo = null;
fo = org.openide.filesystems.FileUtil.toFileObject(new java.io.File(url));//If the file object is null, then the
//link is broken:

String found = null;
if (fo == null) {
found = "broken";//Write to the Output window,
//creating hyperlinks:

writer.println(found + ": " + dataObject.getNodeDelegate().getDisplayName() + ", line " + (realLineNo + 2) + ": " + value, new HTMLOutputListener(found, url, dataObject, fo, realLineNo, pos));
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
}

Then, in the HTMLOutputListener class, as shown yesterday, use the LineCookie to open the document and jump the cursor to the place where the HREF attribute is defined. Because that's where the problem is and the help author needs to fix that link.

Join the discussion

Comments ( 7 )
  • sahara Wednesday, September 26, 2007

    Hi,

    First,thanks for your useful documents,

    I want to manage menu and toolbar by activated editor topComponent,for example enable/disable or show/hide menu items and toolbar items.

    would you help me ?

    thanks.


  • Geertjan Wednesday, September 26, 2007

    CookieAction.enable() is what you need to use. Use the New Action wizard to create the action, make sure to select 'conditionally enabled' in the first panel, then your class will extend CookieAction and you will be able to specify in CookieAction.enabled() when the menu item or toolbar button should be enabled/disabled. Please join dev@openide.netbeans.org, which is a mailing list where questions such as these are answered.


  • Roger Thursday, September 27, 2007

    Some of the links I use contain fragment identifiers and those fail the link check because the fragment id is included when the filename is constructed. Perhaps the fragment and query components could be stripped from the HREF before checking for the file.

    It might also be nice if absolute url's (http://...) could be checked as well but that would cross a complexity threshold. Perhaps it is sufficient to flag any URL other than relative or file: urls as unchecked instead of broken.

    Just a thought...

    Roger


  • sahara Monday, October 1, 2007

    Thaks for your attention,

    I try to work with enable() method but i cant work with it.

    Can you give me an example to enable menu item whenever specified topComponent opened?

    sahara.


  • sahara Tuesday, October 2, 2007

    Is it possible to add or remove toolbar icon of related action by programming , for example when specified topcomponent open or not?


  • Geertjan Tuesday, October 2, 2007

    Hi Roger, good ideas, thanks.

    <p>Hi Sahara, please write to dev@openide.netbeans.org with these questions. For an example of setEnable(), see this tutorial:

    <p>

    http://platform.netbeans.org/tutorials/60/nbm-copyfqn.html


  • Geertjan Tuesday, October 2, 2007

    Sorry, not setEnable(), but CookieAction.enable(), I mean. It is used in the tutorial above.


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.