Vercue Extensions with C# – Part 1

In this post, we’ll see how to implement a Vercue Extension using Visual Studio and C#.

Topics covered by this post:

  • What are Vercue Extensions

  • Implementing a button that runs an action on the selected Source

  • Implementing a button that runs an action on all available Sources

  • Run an async action

  • Run an action based on user-properties


Vercue Extensions

Vercue can be extended to add UI elements and/or automation actions and macros.

For example, new command menu items can be added to the Sources and Log-Entries panels. New custom Actions can be implemented and used in automated Rules, and more.

Implementing such extensions is easy and fast, using Visual Studio and a .NET programming language, such as C#.

In this post, we will implement some custom menu-commands for a Source.

Extending the Source Menu

Sample 1: Run a command based on the Source’s built-in properties

First, we’ll see how to implement a command that executes an action on the Source’s built-in properties, such as its path (in case it is a Working-Copy).

A useful action we can implement will be a button that commits changes of a selected source with a predefined message. A one-click commit button. For example, committing a conflict-less reintegration-merge.

Step 1: Create the extension class library in Visual Studio

Create a new Visual Studio C# class library project, give it a meaningful name (“VercueExtension”, for example) and make sure the target framework is 3.5, to match Vercue’s framework version:

image

Add a reference to the Vercue.Library.dll file, which should be located under Vercue’s installation folder (C:\Program Files (x86)\Vercue\Vercue.Library.dll)

Step 2: Create the extension class

Add a new class and implement the Vercue.Extensibility.IExtension interface:

public class MyExtension : IExtension
{
    public void Extend(IExtensible extensible)
    {

    }
}

 

Step 3: Create the One-Click Commit method:

private void Commit(object sender, ExtensionEventArgs<SvnSource> args)
{
    // Get the first selected Source
    //
    var selectedSource = args.SelectedItems.FirstOrDefault();

    // If there is no selected Source – do nothing
    //
    if (selectedSource == null)
    {
        return;
    }

    // Svn is declared in the Vercue.Extensibility.Utils namespace
    //
    Svn.Commit(selectedSource.Path, "The Log Message");

    // Check the Source for updates to hide the blue arrow
    //
    selectedSource.CheckUpdates();
}

Step 4: Introduce the command to the UI:

private void AddCommitCommand(IExtensible extensible)
{
    extensible.SourceCommands.AddCommand(
        new UICommandExtensionInfo<SvnSource>(
            "Commit", // The command text
            Commit)   // The click handler
        {
            // In-addition to the context menu,
            // the command will be available from the main toolbar and
            // the tray context menu
            //
            AddToMainToolbarAndMenu = true,
            AddToTrayContextMenu = true,

            // The command is initialy disabled, until the Enabler
            // predicate is called
            //
            InitialEnabled = false,

            // The Enabler predicate enables/disables the command based
            // on the selected items.
            // In this case, the command is enabled only for
            // Working-Copy Sources
            //
            Enabler = sources => sources.All(src => src.IsWorkingCopy),
        });
}

Step 5: Build and Install

Build the project. Locate the output dll file and copy it to %appdata%\Vercue\Extensions.

Restart the application. Your new extension should be loaded and available from the Source’s context menu.

image

Notice that the command is available from the context-menu, the main menu, the Sources pane’s toolbar, the main toolbar and the tray-menu.

Sample 2: Run a command on all the available items

How about a button that runs svn-cleanup on all the Working-Copies?

Easy:

private void Cleanup(object sender, ExtensionEventArgs<SvnSource> args)
{
    // Target all Working-Copies Sources
    //
    var sources = args.AllItems.Where(src => src.IsWorkingCopy);

    foreach (var source in sources)
    {
        Svn.CleanUp(source.Path);
    }
}

The command runs on all the available Working-Copy sources, so it has to be always enabled.

The Enabler property of the command has to be an always-true predicate:

private void AddCleanupCommand(IExtensible extensible)
{
    extensible.SourceCommands.AddCommand(
        new UICommandExtensionInfo<SvnSource>(
            "Cleanup",
            Cleanup)
        {
            AddToMainToolbarAndMenu = true,
            AddToTrayContextMenu = true,
            InitialEnabled = true,

            // This command is always enabled
            //
            Enabler = sources => true,
        });
}

Build, copy, restart the application and you can start using your new cleanup action!

Notice that the svn-cleanup command is time-consuming. If you have many Sources – it can take minutes to complete. Let’s change the command to run on a background-thread so it doesn’t block the user-interface. In-addition, while the application keeps executing svn commands on the Sources (checking for updates), the Cleanup command might fail. Let’s also add some error-handling to the command:

private void Cleanup(object sender, ExtensionEventArgs<SvnSource> args)
{
    // Take all the available Sources which are Working-Copies
    //
    var sources = args.AllItems.Where(src => src.IsWorkingCopy);

    // Run the cleanup in a background-thread
    //
    ThreadPool.QueueUserWorkItem(obj => Cleanup(sources));
}

private void Cleanup(IEnumerable<SvnSource> sources)
{
    foreach (var source in sources)
    {
        try
        {
            Svn.CleanUp(source.Path);
        }
        catch
        {
            // The Source might be currently in use by
            // the main application.
            // Lets just ignore it for now.
        }
    }
}

Notice that this is only a sample. Error handling, user-notifications and command-availability are up to you to implement. For example – disabled the command until the cleanup is complete to prevent multiple clicks.

User-Properties and Values

Vercue allows the end-users to add custom properties and values to Sources. These custom values can be used in Rules conditions and Actions (Next post will discuss this feature).

Another use for such values is in UI commands.

Sample 3: Run a command based on user-values

Let’s see an example of a command that uses Source’s user-specific values.

A useful example can be a button that opens a Source’s project file. Referring to a .NET project, the file will probably be a .sln file (A Visual Studio solution), but the command may suit any type of file, as long as Windows knows how to open it.

The only important difference between this implementation and the previous one is the fact that we now use a user-property instead of a built-in one.

public void OpenProject(
    object sender,
    ExtensionEventArgs<SvnSource> args)
{
    // Get the first selected Source
    //
    var selectedSource = args.SelectedItems.FirstOrDefault();

    // If there is no selected Source – do nothing
    //
    if (selectedSource == null)
    {
        return;
    }

    object project = null;

    // Try to get the "project" user-property
    //
    if (selectedSource.UserProperties.
        TryGetValue("project", out project))
    {
        // Combine it with the Source's path
        //
        var projectFullPath =
            Path.Combine(selectedSource.Path, (string)project);

        // Run it
        //
        Process.Start(projectFullPath);
    }
}

We want the command to be enabled only for Sources that have the “project” user-property.

Here’s the Enabler predicate for such condition:

Enabler = sources => sources.All(
    src => src.UserProperties.ContainsKey("project")),

Built and copy the dll to its destination folder.

Adding User-Properties to a Source

Double-click a Source, click the “User Properties” button.

image

In the Source User Properties dialog, add a key named “project” and set its value to the name of the project/solution file within the folder:

image

Click OK on all the dialogs and you can now test your command.

Debugging

In-order to debug the extension – all you need to do is attach to the Vercue.exe process and click the command you just added. Place a breakpoint in your action method and it will break there.

More things to explore

  • Log-Entries and Log-Entries Items: In addition to Source commands, an extension can add commands to the Log-Entries menu and to the Log-Entry Items menu using the UICommandExtensionInfo<SvnLogEntry> and UICommandExtensionInfo<SvnLogEntryItem> classes
  • SelectedItems vs. AllItems: The ExtensionEventArgs object contains also an AllItems property which contains a list of all the items in the relevant collection, and not only the selected ones. For example, a instance of ExtensionEventArgs<SvnSource> will contain all the available Sources.
  • Svn Commands: The Vercue.Extensibility.Utils.Svn class has various static methods that can be used to perform common svn actions, such as Update, Revert, Cleanup and Commit, which we used in this post. Explore the class and see what else is available.

In the next post, we will implement some automation extensions, such as custom Actions, Macros and Monitors.

Share, please:
  • Digg
  • del.icio.us
  • Google Bookmarks
  • DotNetKicks
  • DZone
  • StumbleUpon
  • Facebook
  • Tumblr
  • Twitter
This entry was posted in .NET, Extensions, Vercue and tagged , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Spam protection by WP Captcha-Free