DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Coding
  3. Tools
  4. How to use Guarded Sections in Editors on the NetBeans Platform

How to use Guarded Sections in Editors on the NetBeans Platform

Enrico Scantamburlo user avatar by
Enrico Scantamburlo
·
Feb. 28, 11 · Interview
Like (0)
Save
Tweet
Share
4.78K Views

Join the DZone community and get the full member experience.

Join For Free
I was asked to implement a non-editable section, like the ones that in Java files do not allow to edit the code by Matisse. I had not to let the user edit some variables whose syntax was like ${ABC}.

I copied the code that is used for the BeanInfo, especially "BIEditorSupport.java". Following are the steps to create a new file type and to add Guarded Sections to it. Of course, it can be customized at your own will.

I was also asked to add popup actions to the code to edit the content of the Guarded Sections, probably I will write about it in another tutorial.

Thanks to Matteo Di Giovinazzo and Paolo Repele for their code review.

Note: The complete code sample can be downloaded here.

  1. Create a new "NetBeans Platform Application". Call it "GuardedSectionSuite", any other name is fine. In order to do this, in the File menu select "New Project..." / "NetBeans Modules" / "NetBeans Platform Application". Finish the wizard and then right-click on the suite node, select "Properties", then select "Libraries". Within the "ide" cluster, check the "Editor Guarded Sections " node.

  2. Add a new module. Expand the suite node. Right-click on the "Modules" node. Select "Add New...". Call the module "GuardedSectionModule", for example. Add the new module to the suite. Click "Next". Be sure that the "Generate XML Layer" checkbox is selected. Click "Finish". Right-click on the new module node and select "Properties" and then "Libraries". Click on "Add Dependency" and then add dependencies on "General Queries API", "Editor Guarded Sections", "UI Utilities API", if you do not add this you get problem when launching the suite.

  3. Recognize a new file type. Right-click on the new module node and select "New"/"Other". Select "Module Development" and "File Type". Fill the textfield, the extension is the extension used to recognize the file and the MIME type will be the identifier for that file. Click "Next". Again, fill the fields, the icon is unimportant. Click "Finish".

  4. Write the code. Edit "ScantiDataObject.java" Replace this line:
    cookies.add((Node.Cookie)DataEditorSupport.create(this, getPrimaryEntry(), cookies));

    with this one

    cookies.add(new ScantiDesignEditorSupport(this, getCookieSet()));
    Create a new java class and call it "ScantiDesignEditorSupport". This class will take care of saving and loading the file and it will indirectly call the "GuardedSectionProvider" in these cases. Remember to change it if you have a MIME type different from "text/x-scanti". Copy this code inside "ScantiDesignEditorSupport":
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.Reader;
    import java.io.Writer;
    import java.nio.charset.Charset;
    import javax.swing.text.BadLocationException;
    import javax.swing.text.EditorKit;
    import javax.swing.text.StyledDocument;
    import org.netbeans.api.editor.guards.GuardedSectionManager;
    import org.netbeans.api.queries.FileEncodingQuery;
    import org.netbeans.spi.editor.guards.GuardedEditorSupport;
    import org.netbeans.spi.editor.guards.GuardedSectionsFactory;
    import org.netbeans.spi.editor.guards.GuardedSectionsProvider;
    import org.openide.cookies.EditCookie;
    import org.openide.cookies.EditorCookie;
    import org.openide.cookies.OpenCookie;
    import org.openide.cookies.PrintCookie;
    import org.openide.cookies.SaveCookie;
    import org.openide.filesystems.FileLock;
    import org.openide.filesystems.FileObject;
    import org.openide.loaders.DataObject;
    import org.openide.loaders.MultiDataObject;
    import org.openide.nodes.CookieSet;
    import org.openide.text.DataEditorSupport;
    import org.openide.windows.CloneableOpenSupport;

    public class ScantiDesignEditorSupport extends DataEditorSupport
    implements OpenCookie, EditCookie, EditorCookie, PrintCookie, EditorCookie.Observable {

    private MyGuardedEditor guardedEditor;

    public ScantiDesignEditorSupport(DataObject obj, CookieSet cookieSet) {
    super(obj, new Environment(obj, cookieSet));
    setMIMEType("text/x-scanti");
    }

    /**
    * gets the GuardedSectionManager from a given document
    * Useful to get a list of Guarded Sections inside a document
    * @param doc the document
    * @return a GuardedSectionManager
    */
    public GuardedSectionManager getGuardedSectionManager(StyledDocument doc) {
    return GuardedSectionManager.getInstance(doc);
    }

    public GuardedSectionManager getGuardedSectionManager() {
    try {
    StyledDocument doc = openDocument();
    return GuardedSectionManager.getInstance(doc);
    } catch (IOException ex) {
    throw new IllegalStateException("cannot open document", ex); // NOI18N
    }
    }

    @Override
    protected void loadFromStreamToKit(StyledDocument doc, InputStream stream, EditorKit kit)
    throws IOException, BadLocationException {
    guardedEditor = null;

    GuardedSectionsProvider guardedProvider = getGuardedProvider(doc);

    if (guardedProvider != null) {
    guardedEditor.document = doc;
    Charset c = FileEncodingQuery.getEncoding(this.getDataObject().getPrimaryFile());
    Reader reader = guardedProvider.createGuardedReader(stream, c);
    try {
    kit.read(reader, doc, 0);
    } finally {
    reader.close();
    }
    } else {
    super.loadFromStreamToKit(doc, stream, kit);
    }
    }

    private GuardedSectionsProvider getGuardedProvider(StyledDocument doc) {
    GuardedSectionsProvider guardedProvider = null;
    if (guardedEditor == null) {
    guardedEditor = new MyGuardedEditor(doc);
    String mimeType = ((DataEditorSupport.Env) env).getMimeType();
    GuardedSectionsFactory gFactory = GuardedSectionsFactory.find(mimeType);
    if (gFactory != null) {
    guardedProvider = gFactory.create(guardedEditor);
    }
    }
    return guardedProvider;
    }

    @Override
    protected void saveFromKitToStream(StyledDocument doc, EditorKit kit, OutputStream stream)
    throws IOException, BadLocationException {
    GuardedSectionsProvider guardedProvider = getGuardedProvider(doc);
    if (guardedProvider != null) {
    Charset c = FileEncodingQuery.getEncoding(this.getDataObject().getPrimaryFile());
    Writer writer = guardedProvider.createGuardedWriter(stream, c);
    try {
    kit.write(writer, doc, 0, doc.getLength());
    } finally {
    writer.close();
    }
    } else {
    super.saveFromKitToStream(doc, kit, stream);
    }
    }

    @Override
    public void saveDocument() throws IOException {
    super.saveDocument();
    }

    @Override
    protected boolean notifyModified() {
    if (!super.notifyModified()) {
    return false;
    }
    ((Environment) this.env).addSaveCookie();
    return true;
    }

    @Override
    protected void notifyUnmodified() {
    super.notifyUnmodified();
    ((Environment) this.env).removeSaveCookie();
    }

    @Override
    protected void notifyClosed() {
    super.notifyClosed();
    }

    static class MyGuardedEditor implements GuardedEditorSupport {

    protected StyledDocument document;

    public MyGuardedEditor(StyledDocument document) {
    this.document = document;
    }

    @Override
    public StyledDocument getDocument() {
    return document;
    }
    }

    static ScantiDesignEditorSupport findEditor(DataObject dobj) {
    return dobj.getLookup().lookup(ScantiDesignEditorSupport.class);
    }

    private static final class Environment extends DataEditorSupport.Env {

    private static final long serialVersionUID = -1;
    private final transient CookieSet cookieSet;
    private transient SaveSupport saveCookie = null;

    private final class SaveSupport implements SaveCookie {

    @Override
    public void save() throws java.io.IOException {
    DataObject dobj = getDataObject();
    ((DataEditorSupport) findCloneableOpenSupport()).saveDocument();
    dobj.setModified(false);
    }
    }

    public Environment(DataObject obj, CookieSet cookieSet) {
    super(obj);
    this.cookieSet = cookieSet;
    }

    @Override
    protected FileObject getFile() {
    return this.getDataObject().getPrimaryFile();
    }

    @Override
    protected FileLock takeLock() throws java.io.IOException {
    return ((MultiDataObject) this.getDataObject()).getPrimaryEntry().takeLock();
    }

    public
    @Override
    CloneableOpenSupport findCloneableOpenSupport() {
    return findEditor(this.getDataObject());
    }

    public void addSaveCookie() {
    DataObject javaData = this.getDataObject();
    if (javaData.getCookie(SaveCookie.class) == null) {
    if (this.saveCookie == null) {
    this.saveCookie = new SaveSupport();
    }
    this.cookieSet.add(this.saveCookie);
    javaData.setModified(true);
    }
    }

    public void removeSaveCookie() {
    DataObject javaData = this.getDataObject();
    if (javaData.getCookie(SaveCookie.class) != null) {
    this.cookieSet.remove(this.saveCookie);
    javaData.setModified(false);
    }
    }
    }
    }
  5. Create a new Java class. Call it "ScantiGuardedSectionsFactory". Paste this code inside:
    import org.netbeans.spi.editor.guards.GuardedEditorSupport;
    import org.netbeans.spi.editor.guards.GuardedSectionsFactory;
    import org.netbeans.spi.editor.guards.GuardedSectionsProvider;

    public class ScantiGuardedSectionsFactory extends GuardedSectionsFactory{

    @Override
    public GuardedSectionsProvider create(GuardedEditorSupport ges) {
    return new ScantiGuardedSectionsProvider(ges);
    }

    }
  6. Finally, create the Java class that does the job. Call it "ScantiGuardedSectionsProvider". The "readSection" method reads the content of the file and extracts the sections from it. The "Result" object that is returned contains an array of chars and a list of sections. I think that the displayed text could be changed by returning a different array. The same thing can be said for the "writeSections" method. This is useful if you want to mark your section with some text that you do not want to be displayed to the user.
    import java.util.ArrayList;
    import java.util.List;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.swing.text.BadLocationException;
    import org.netbeans.api.editor.guards.GuardedSection;
    import org.netbeans.api.editor.guards.SimpleSection;
    import org.netbeans.spi.editor.guards.GuardedEditorSupport;
    import org.netbeans.spi.editor.guards.support.AbstractGuardedSectionsProvider;
    import org.openide.util.Exceptions;


    public class ScantiGuardedSectionsProvider extends AbstractGuardedSectionsProvider {

    public ScantiGuardedSectionsProvider(GuardedEditorSupport editor) {
    super(editor);
    }

    @Override
    public char[] writeSections(List list, char[] chars) {
    return chars;
    }

    @Override
    public Result readSections(char[] chars) {
    List sections = new ArrayList();

    StringBuilder sb = new StringBuilder();

    int start = 0;
    int len = 0;
    for (int i = 0; i < chars.length; i++) {
    char c = chars[i];

    switch (c) {
    case '}': // I have found the closing brace
    if (len == 2) {
    try {
    Logger.getLogger(ScantiGuardedSectionsProvider.class.getName()).log(Level.INFO, "Appending Section {0}", sb.toString());
    SimpleSection section = createSimpleSection(sb.toString(), start, i);
    sections.add(section);
    } catch (BadLocationException ex) {
    Exceptions.printStackTrace(ex);
    }
    sb = new StringBuilder();

    len = 0;
    }
    break;
    case '$': // I have found the first character
    if (len == 0) {
    len++;
    }
    start = i;
    break;

    case '{': // secondcharacter
    if (len == 1) {
    len++;
    }
    break;

    default: // I create the variable name
    if (len == 2) {
    sb.append(c);
    }
    break;


    } // end of switch
    }

    Result res = new Result(chars, sections);

    return res;
    }

    }
  7. Edit the "layer.xml" to register the factory. Add these tags:
    <folder name="Editors">
        <folder name="text">
            <folder name="x-scanti">
                <file name="org-mycompany-guardedsection-ScantiGuardedSections.instance">
                    <attr name="instanceCreate" newvalue="org.mycompany.guardedsection.ScantiGuardedSectionsFactory"/>
                    <attr name="instanceOf" stringvalue="org.netbeans.spi.editor.guards.GuardedSectionsFactory"/>
                </file>
            </folder>
        </folder>
    </folder>
  8. Run the module. Create a new file and write some text in it, making sure that there is something like ${ABC} in it. Save the file with the ".scanti" extension, close it and re-open it, and the guarded sections will be applied.

 

NetBeans

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • GitLab vs Jenkins: Which Is the Best CI/CD Tool?
  • How To Build an Effective CI/CD Pipeline
  • 3 Main Pillars in ReactJS
  • Understanding and Solving the AWS Lambda Cold Start Problem

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: