VersioningSystemIntegration

NetBeans Version Control System Integration Guide

This document describes how to implement and register version control system provider that can be used by other IDE components (projects, nodes, editors and filesystems).

There is sibling Project Versioning that describes how to code version control aware IDE components.

Document Status

The document describes basic integration. More detailed tricks are TODO.

Goal

This document describes version control integration on a virtual NoVersion version control system that keeps local history.

Integration Points Summary

Version control system should integrate with IDE filesystems, IDE project system, IDE diff, IDE editor, IDE window system. More advanced integrations are possible, but not described here. Check particular module APIs.

Your project should declare dependencies on:

  org.netbeans.api.progress: Progress UI and cancel
  org.netbeans.modules.diff: Differences engine and UI, patch algorithm and conflict resolver UI
  org.netbeans.modules.editor,
org.netbeans.modules.editor.errorstripe,
org.netbeans.modules.editor.fold,
org.netbeans.modules.editor.lib,
org.netbeans.modules.editor.mimelookup,
org.netbeans.modules.editor.settings: Editor sidebars org.netbeans.modules.masterfs,
org.openide.filesystems: Project nodes annotations, context actions, FS operations intercaption org.netbeans.modules.projectapi,
org.netbeans.modules.projectuiapi: Project level integration org.netbeans.modules.queries: ignore list default (SharabilityQuery) org.netbeans.modules.versioning: SOCKS proxy, Turbo cache org.openide.io: Output window org.openide.windows: Main menu definition, windows (TopComponent) OpenIDE APIs: Nodes, DataObjects, Lookup, ModuleInstall
  • org.openide.awt
  • org.openide.dialogs
  • org.openide.explorer
  • org.openide.loaders
  • org.openide.modules
  • org.openide.nodes
  • org.openide.options
  • org.openide.text
  • org.openide.util

Create NetBeans Plug-in Project

From File menu select New Project... and choose NetBeans Plug-in Module, Module Project. It creates blank project with (under Important files) XML Layer and Module Manifest. From project contextual menu select Properties and in Libraries section declare all above dependencies.

Main Menu Actions

Open module XML Layer and define user actions. A user reachable action is a SystemAction subclass that is registered in Actions repository and potentially in Main menu and have assigned a shortcut.

Example action:

package org.noversion;

import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.nodes.Node;
import org.openide.util.HelpCtx;
import org.openide.util.RequestProcessor;
import org.openide.util.actions.NodeAction;

/**
 * Sample action
 */
public class NoVersionAction extends NodeAction {

    public NoVersionAction() {
        setIcon(null);
        putValue("noIconInMenu", Boolean.TRUE); // NOI18N
    }

    protected void performAction(final Node[] node) {

        // do all necessary node queries getting files it represents
        // you can inspire in org.netbeans.subversion.util.SvnUtils.getCurrentContext()
        // @see VersionActionContext link bellow

        RequestProcessor.getDefault().post(new Runnable() {
            public void run() {
                ProgressHandle progress =
                        ProgressHandleFactory.createHandle("No-versioning...");

                progress.start();
                try {
                    // NoVersion.perform();
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException ex) {
                    }
                } finally {
                    progress.finish();
                }
            }
        });
    }

    protected boolean enable(Node[] node) {
        return true;
    }

    public String getName() {
        return "No Version";
    }

    protected boolean asynchronous() {
        return false;  // => performAction comes from AWT
    }

    public HelpCtx getHelpCtx() {
        return new HelpCtx(getClass());
    }

}

Note: See typical VersionActionContext implementation (Node[[ | ]] => File[[ | ]] transformation).

Sample XML Layer registration snippet:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
<filesystem>

    <!-- Actions Registry -->
    <folder name="Actions">
        <folder name="Noversion">
            <file name="org-noversion-NoVersionAction.instance">
                <attr name="instanceClass" stringvalue="org.noversion.NoVersionAction"/>
            </file>
        </folder>
    </folder>

    <!-- Main Menu Reference -->

    <folder name="Menu">
        <!-- Menu Location after Run, CVS, Subversion, Refactoring but before Tools -->
        <attr name="RunProject/NoVersion" boolvalue="true"/>
        <attr name="Refactoring/NoVersion" boolvalue="true"/>
        <attr name="CVS/NoVersion" boolvalue="true"/>
        <attr name="SVN/NoVersion" boolvalue="true"/>
        <attr name="NoVersion/Tools" boolvalue="true"/>

        <folder name="NoVersion">
            <attr name="SystemFileSystem.localizingBundle" stringvalue="org.noversion.Bundle"/>

            <file name="org-noversion-NoVersionAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Noversion/org-noversion-NoVersionAction.instance"/>
            </file>
        </folder>
    </folder>

    <!-- Keyboard Shortcut Reference -->
    <folder name="Shortcuts">
        <file name="C-Q.shadow">
            <attr name="originalFile" stringvalue="Actions/Noversion/org-noversion-NoVersionAction.instance"/>
        </file>
    </folder>
</filesystem>

Relevant Bundle.properties:

OpenIDE-Module-Name=NoVersion
Menu/Noversion=N&o.Version

Check your results, from project context menu choose Install/Reload in Target Platform, there should be new menu item. Actual NoVersionAction action business logic is upon you.

Project Explorer Contextual Actions and Node Badging

Node contextual actions and their badging are delivered using MasterFileSystem's AnnotationProvider. Subclass AnnottaionProvider and register it as a service in your META-INF/services.

Note: MasterFileSystem is non-API module you need establish implementation dependency or become it's friend,

Create META-INF/services/org.netbeans.modules.masterfs.providers.AnnotationProvider file that reads:

org.noversion.FileStatusProvider

and its example implementation:

package org.noversion;

import java.awt.Image;
import java.io.*;
import java.util.*;
import java.util.Set;
import javax.swing.Action;
import org.netbeans.modules.masterfs.providers.AnnotationProvider;
import org.netbeans.modules.masterfs.providers.InterceptionListener;
import org.openide.filesystems.*;

/**
 * Recognizes noversioned work dirs, adds context action
 * and annotates node name.
 */
public class FileStatusProvider extends AnnotationProvider {

    /** Creates a new instance of FileStatusProvider */
    public FileStatusProvider() {
    }

    public String annotateName(String name, Set files) {
        if (isManaged(files)) {
            // XXX too simplified
            Iterator it = files.iterator();
            if (it.hasNext()) {
                FileObject first = (FileObject) it.next();
                String version = getNoVersion(FileUtil.toFile(first));
                if (version != null) {
                    return name + " ["+Version+"]";
                }
            }
        }
        return null;
    }

    public Image annotateIcon(Image image, int i, Set set) {
        return null;
    }

    public String annotateNameHtml(String name, Set files) {
        if (isManaged(files)) {
            // XXX too simplified. add HTML escaping, etc
            Iterator it = files.iterator();
            if (it.hasNext()) {
                FileObject first = (FileObject) it.next();
                String version = getNoVersion(FileUtil.toFile(first));
                if (version != null) {
                    return "<html><font color=\"#0000FF\">" + name + "</font>&nbsp;<i>" + version + "</i>";
                }
            }
        }
        return null;
    }

    public Action[] actions(Set files) {
        if (isManaged(files)) {
            // FIXME add submenu example
        }
        return null;
    }

    public InterceptionListener getInterceptionListener() {
        return null;
    }

    /**
     * @return true if at least one file is managed (any parent
     * has <tt>noversion.properties</tt> and it is not explicitly marked
     * as unmanaged (future user action feature))
     */
    private static boolean isManaged(Set fileObjects) {
        boolean managed  = false;
        Iterator it = fileObjects.iterator();
        while (it.hasNext()) {
            FileObject fo = (FileObject) it.next();
            File file = FileUtil.toFile(fo);
            if (file == null) {
                continue;
            }
            return getMarker(file) != null;
        }
        return false;
    }

    private static File getMarker(File file) {
        File parent = file.getParentFile();
        if (parent != null) {
            File marker = new File(parent, "noversion.properties");
            if (marker.isFile()) {
                return marker;
            }
        }
        return null;
    }

    private static String getNoVersion(File file) {
        if (file == null) {
            return null;
        }

        File props = getMarker(file);
        if (props != null) {
            Properties map = new Properties();
            try {
                map.load(new FileInputStream(props));
                return map.getProperty(file.getName());
            } catch (IOException ex) {
                // FIXME ignore
            }
        }
        return null;
    }
}

Project Contextual Menu

Project node uses TODO registration mechanism.

Diff

TODO call Diff APIs.

Editor

TODO Editor sidebar resgistration.

Downloads

TODO How to attach <nop>NoVersion module zip archive?

Other Documentation

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo