Personal tools
You are here: Home gvSIG Projects gvSIG Desktop Documentation Developers documentation Developers Quick Start Guide gvSIG 2.0.0. Developers Quick Start Guide
gvSIG Desktop
gvSIG Desktop
 
Document Actions

gvSIG 2.0.0. Developers Quick Start Guide

by Joaquin Jose del Cerro Murciano last modified 2012-03-12 15:33


Introduction

Attention!

This document is designed to work with version 2.0.0 of gvsIG. If you're developing on another version of gvSIG please check if there is documentation specific to that version.

data/developers_quick_start.png

This document is intended as an introduction to developing with gvSIG 2.0. It does not delve into the intricacies of gvSIG but rather provides an overview of the major components and how they can be used to build your first gvSIG development.

Java is used as the development language for gvSIG and it is recommended that you familiarise yourself with Java if not already so. Eclipse is used as the project's integrated development environment, so you should be familiar with it too. Tools like Maven or Ant are also used, and familiarity with them is recommended, although not essential, for a first attempt at development with gvSIG.

In addition to these skills, it is highly recommended that the developer be familiar with the application from the user's point of view. You can find user documentation on the gvsig.org web site, which, while not corresponding exactly with the version of gvSIG you will be working with, will nevertheless provide a better understanding of the different pieces of code.

In short, before continuing you should know:

Java:necessary
Eclipse:necessary
Ant:recommended
Maven:recommended
gvSIG application:
 recommended

In addition to this, you should have:

  • Ubuntu (or derived) 10.04
  • Eclipse (Helios or newer recommended).
  • Maven (recommended).
  • Internet connection for accessing Maven's public repositories
  • A JDK 1.5/1.6 installed and correctly configured (compilation with Maven requires a JDK separate from Eclipse).
  • A gvSIG 2.0 installed, preferably one of the last builds of the 2.0 series.

Tip

You can find information on the development list and an overview of all the project lists in the Project Mailing Lists document.

If you have trouble following this document please feel free to ask questions on the project development list. They will help answer any questions that may arise.

Changes to using gvSIG

Prior to gvSIG version 2, the main way of developing with gvSIG was to create a workspace with the official distribution's source, so that making a plugin required all the information necessary to compile the full gvSIG distribution. Although some efforts were made to build plugins without the need for a full gvSIG workspace, it was not up until version 2 that this mechanism functioned properly. The recommendation now is not to insert plugins into a workspace with gvSIG sources.

In version 2, the correct way of developing a new plugin is with a binary installation of gvSIG by creating a workspace containing only our projects, and then deploying our binaries with that installation.

In addition to this, considerable effort has been made in version 2 to make the libraries that use the gvSIG plugin mechanism independent. This allows us to perform much of the development without having to bind to gvSIG, or to compile to test it. We can create small applications that use the libraries of gvSIG and can be run independently.

Complementing this, ​​the necessary changes have been made so you do not have modify the code for common operations you might need during development.

If you have already developed for gvSIG 1 you should bear in mind this change in the way of working. Do not create a workspace with the gvSIG sources and compile them if it is not necessary. This only needs to be done if you need to make changes to the sources.

Usually the gvSIG source code does not need to be modified as you can develop your own plugin functionality rather than modifying the gvSIG code. If you need to do this, and these modifications might be useful for other users, then you can submit them as patches for inclusion in future versions of gvSIG.


Basic architecture of gvSIG

org.gvsig.tools

The Tools library is an important part of gvSIG. It provides a number of utilities and services which support the other modules in gvSIG. The main functionality provided by this library relates to:

  • Registration of extension points
  • Initialisation of libraries
  • Utilities for the separation of the API and implementation (Registration of APIs, registration of implementations for the APIs, registration of SPI service providers or localisation of an API implementation)
  • Monitoring of Tasks

Although these are the most important services the library provides, it also provides other tools that can be considered structural to the application. These include:

  • Disposables
  • Interfaces for managing Observers-observables
  • Interfaces for managing visitors
  • Definition of data types
  • Base interfaces for evaluators
  • Object Persistence

Tip

You can find more detailed information on how the library mechanism works in gvSIG at org.gvsig.tools.library, on the use of locators you can consult org.gvsig.tools.locator, and for managers you can find documentation at org.gvsig.tools.service.

We will focus now on three basic concepts that are repeated throughout the code that we see, and that are linked to utilities that enable a strict separation of the API from the implementation:

  • Libraries. These are pieces of code normally associated with a jar that provides a functionality. Each of these libraries must be a class that implements the Library interface, usually extending the AbstractLibrary class. They have methods for initialising the library that are invoked when it is loaded.
  • Managers. These components provide functionality to the application, acting as an agent for the various services offered by the library and for their configuration. Acts as a singleton, since in the application there is usually only one instance of each of these components. Libraries will have one or more of these according to their logic.
  • Locators. This is a utility that allows you to register implementations of managers for a given library, and to retrieve the manager implementation of a specific API.

These three components play a major role whenever we want to use or create new components, as they are the devices that allow us to access different parts of gvSIG

Andami Plugins Framework

The Andami framework is used to compose the gvSIG application. It provides mainly two types of services, the management and loading of plugins, and the management of windows that make up the user interface.

At this point we will focus briefly on the management of plugins. Andami provides a launcher for the application that initializes the plugins system, and is responsible for loading the plugins that are installed in the application. A plugin is a functional unit that can provide:

  • Menu options to install the application
  • New buttons and toolbars
  • New data providers
  • New document types

Normally in a gvSIG installation you will find a folder gvSIG/extensions. This folder contains the different plugins installed in the application. Each plugin is contained in a folder, which always contains the files:

  • Config.xml, which describes:

    • Where to find this plugin's classes

      Tip

      More information on the structure and different labels that are allowed in this file can be found at config.xml file

    • Whether this plugin depends on some other plugin

    • What menu options the plugin added to the application

    • What toolbars and buttons the plugin added.

  • Package.info, which reports on the version, name, ID or description of the plugin. It is like a container for the plugin's metadata, and allows us to identify the plugin when updating or reinstalling it.

There is also a theme folder, which contains the configuration of the application's splash, window icons and background colors.

Although the mechanism for adding new functionality to gvSIG is also adding new plugins, these in turn contain one or more extensions that provide the functionality being added. So we will have a plugin containing extensions.

With respect to the management of plugins, the main components are:

  • PluginsLocator, which provides access to the plugins manager through a static getManager method.
  • PluginsManager, which provides methods to interrogate which plugins are loaded and what extension each of them has.
  • The PluginsServices class that represents an instance of a given plugin.
  • The IExtension interface that represents an action or block of actions to incorporate into gvSIG.
  • The ExclusiveUIExtension interface that allows us to control the visibility of all the extensions loaded into the application.

We will examine the IExtension interface in more detail. This is the interface that we implement in order to add a new button or menu option. In this interface we find the methods:

  • Initialize. Executed when loading the extension and initialising the plugin. Keep in mind that when you invoke this method it is possible that not all the gvSIG extensions will have been loaded and initialized. Normally here we will initialise the components of our extension that are used by other extensions.
  • postInitilize. Invoked in the indexing of the extension. Just after having invoked the initialize method of all the gvSIG extensions. Normally, here we will perform the initialisation of our extension's components that require other extensions.
  • terminate. Invoked when gvSIG needs to release the extension. Normally this will occur when the application is closed. Here we ensure that the system resources reserved for our extension are released.
  • execute. This method is executed every time the user interacts with the menu or toolbar button associated with the extension. Normally this will implement the execution of our functionality.
  • isEnable. Invoked when you need to know if the user interface associated with the extension (buttons or menu items) is enabled.
  • isVisible. Is invoked when you need to know if the user interface associated with the extension (buttons or menu options) is visible.

Windows

Tip

Although there is currently no documentation related to this for version 2 of gvSIG, in general, existing documentation for gvSIG 1 should be valid. It can be found at Andami windows

Andami, in addition to providing a mechanism for loading and managing plugins, also provides an API for the management of the application's windows. Currently the MDI paradigm is used to manage windows. However, gvSIG's window manager itself can be replaced to provide other forms of display (SDI, tabs,...).

The main entities found in Andami related to windows management are:

  • MDIManagerFactory is the factory where it is recorded and from which we obtain the instance of MDIManager (made from Locator).
  • MDIManager represents the window manager registered in gvSIG. It has methods to make or close a window.
  • IWindow is the interface that must implement a JPanel to be present as a window in gvSIG.
  • WindowInfo, provides our panel through the IWindow interface and defines the characteristics of our window (title, size, type,...).

In general if we do not need fine control over our windows we can use the ShowWindow method from MDIManager to display a window from a standard JPanel swing.

Some gvSIG plugins

In gvSIG there are a number of plugins that provide the application's base functionality that have some relevance to the other plugins. These are:

  • org.gvsig.app. This plugin provides gvSIG with the bulk of the generic functionality of the application, as well as basic access to vector data. It provides:

    • The concept of project and its documents.
    • The View document.
    • The Table document.
    • The Map document.
    • The basic tools for accessing the view's vector data.

    This plugin, in addition to implementing these features, provides a manager and an important locator in order to develop other plugins:

    • ApplicationManager. This is a manager that provides access to the application's other managers, as well as basic functionality for accessing the global resources of the application. This becomes the object representing the gvSIG application.
    • ApplicationLocator, which is the locator that gives us access to the manager of the application (ApplicationManager).
  • org.gvsig.editing provides the functionality for editing tabular and vector data.

  • org.gvsig.geodb adds support for accessing databases such as PostgreSQL.

  • org.gvsig.i18n.extension adds support for internationalization of the application.

  • org.gvsig.crs.extension adds support for management of CRSs.

  • org.gvsig.rastertools adds raster support to gvSIG.

  • org.gvsig.app.extension adds support for managing add-ons.

  • org.gvsig.app.daltransform adds support for registration and implementation of transformations on data.

These are some of the most important plugins in gvSIG in the sense that they provide important basic functionality necessary for other plugins to function.

Besides these plugins there are many more plugins in the gvSIG distribution that may or may not be necessary depending on what we're going to do with gvSIG.

Some relevant Libraries

When developing with gvSIG it is useful to know the existing plugins, especially the functionality provided by the ApplicationManager. But the important thing is to control which of the libraries we will require in order to implement the functionality we need.

In version 2.0.0 of gvSIG major changes have been introduced, both in how to build gvSIG as well as in the nomenclature used to identify the projects and libraries that are generated. However, this is not a process that has taken place suddenly, it has been happening over a number of years. This has now resulted in a lack of uniformity in the nomenclature of existing components. When it comes to referring to a library we can use the Eclipse project name, the name of the generated jar, or the Maven artifact name. In projects generated recently the chosen rule is that these three names must match, with the name of the Maven artifact being used for all three. Prior to this decision projects had different names for each of these components. For a developer who intends using gvSIG, the important thing is to know the names of the Maven artifact, since they usually need to know for which artifacts dependencies should be set, with the eclipse project name associated with that artifact being less relevant.

The libraries that most meet our needs in gvSIG are:

  • org.gvsig.tools.lib contains structural utilities. Already mentioned at the beginning of the document so we won't elaborate on it at this point.
  • org.gvsig.fmap.geometry (libFMap_geometries). The library for managing gvSIG's geometries. Presents a geometry model with an API independent of its implementation.
  • org.gvsig.projection (libProjection). The library for managing gvSIG's coordinate reference systems.
  • org.gvsig.fmap.dal (libFMap_DAL). The data access library of gvSIG (Data Access Library). It is used by all projects in one form or another to access to a shape, dxf, a PostgreSQL table, a GML, a WFS layer or a DGN file. It presents a common API for accessing vector and tabular data or for accessing coverages.
  • org.gvsig.fmap.mapcontext (libFMap_mapcontext). Contains the API and implementation of layers and map at the logical level.
  • org.gvsig.fmap.control (libFMap_controls). Contains swing components that are linked to the logical components that are presented in the DAL library and mapcontext. It could be a visual component for displaying a map or presenting a table obtained from the DAL.
  • org.gvsig.crs (libJCRS). Is an API implementation of the projections from org.gvsig.projection.
  • org.gvsig.symbology.lib.api. Contains the API of gvSIG's symbology library.
  • org.gvsig.ui (libUIComponent). This is a library that houses a series of general utility graphical components.

Construction tools

All construction of gvSIG build in version 2.0 has been performed with Maven. This tool has been adopted as a tool for building the project.

Tip

It would be advisable to read the documentation on Maven that exists in the gvSIG 2.0 development guide, in the "Maven" section where you will find a brief description as well as links to useful resources related to Maven.

This tool was adopted largely because of the management of dependencies that it is capable of performing, one benefit from a number of good practices that Maven gives us.

You can compile and deploy developments from the command line without being tied to a particular integrated development environment (IDE).

It is therefore important, at the very least, that you know the functioning of Maven if you intend carrying out developments on gvSIG.

In addition to Maven, ant scripts are still used for various maintenance or construction tasks as these are two complementary tools.

The project still uses and recommends Eclipse as an IDE. Several specific configuration files have been prepared to facilitate development on it, and its integration with the compilation system of gvSIG using Maven.


Building our first plugin

Approach

At this point we will generate a project that will allow us to see a number of gvSIG's basic features. To do this we will create a small map viewer. The requirements might be:

  • It must allow us to view a map of city blocks.
  • There must be a query tool that allows us to click on a block to show information on the parcels associated with it.
  • To customize the gvSIG splash and the background of the main window with the corporate image.
  • When starting gvSIG display the map window and enable the cadastral information tool without the user having to interact with the application.
  • Customise the "about" gvSIG to show corporate information.
  • Disabled the editing tools on the map of city blocks.
  • To prepare a plugin installation package so that users can install it using the Add-ons Manager.

To start making our project we will use the wizard to generate projects that are included in the gvSIG distribution.

The project creation wizard

The gvSIG distribution includes a plugin that displays an assistant for creating development projects on gvSIG. The extension providing this wizard is disabled by default so the first thing we must do is to activate it.

Tip

To assist you in the creation of development projects you can find documentation in the Creating our project section of gvSIG's Guide for developers.

To do this, go to the gvSIG preferences panel, and in General, Extensions look for "org.gvsig.mkmvnproject.MakeMavenProjectExtension", and activate the extension. You will need to restart gvSIG to effect the change.

After restarting gvSIG you will notice that the "Tools" menu now has a "Development" sub-menu, which contains a Create new plugin option.

It is important that we supply the following information properly:

  • Project name. The name you're going to give the project, following the normal rules for a Java identifier, trying not to use underscores, and capitalising when consisting of more than one word. We will use Viewer for this example.

  • GroupId. We normally use the java package name that is used as the base in our organization. In gvSIG we use org.gvsig so that is what we will use in this example.

    Note

    The wizard produces an error when a GroupId other than org.gvsig is used. We will try to fix this soon.

  • Path where the workspace is created. Use /home/gvSIG/workspace/viewer.

Having entered this data, select the Basic plugin with spatial support option.

Click Next to run the script and wait for it to finish generating the project. This can take several minutes depending on your Internet connection and your computer.

During the process of building the project you will be asked:

  • For the path to the Eclipse workspace you want to configure. The one offered to us is usually ok.
  • If we want to specify the path to gvSIG on which to deploy the plugin. Normally the path offered to us will be valid.

The script for creating our project, in addition to generating the source code and configuring Maven for use, compiles and displays the first version of the project in the Maven local repository, and also generates the corresponding Eclipse projects so that they can be imported into our workspace.

Project structure

Direct translation from Google translator

Once the wizard has generated our project we can get started by opening Eclipse and selecting as our workspace the folder that was indicated in the wizard. This opens an instance of Eclipse with an empty workspace. The first thing to do is to import the two projects that have been created. For this we will not use the import option.

From the File menu select New->Project... (not java project) and in the dialogue that appears select the General->Project option and click Next. Use "org.gvsig.viewer" as the project name to complete the process. Do the same for the "org.gvsig.viewer.app" project.

Tip

You may find it useful to consult information relating to this in the Developer Guide in the gvSIG project structure section and also in Things to consider before developing a plugin.

Let's take a look at the generated code. The projects that have been created are:

  • org.gvsig.viewer. This is a Maven project with multiple subprojects. In these we find the logic part, with its API and implementation, the user interface (and associated API and implementation) associated with the logical components, and a project that allows us to test the logic and interfaces without having to start gvSIG. In general the various components that we find here will be independent of the Andami framework as well as the gvSIG plugins, being dependent only on other libraries. The projects that we will find are:
    • org.gvsig.viewer.lib with the logic of our project
      • org.gvsig.viewer.lib.api
      • org.gvsig.viewer.lib.impl
    • org.gvsig.viewer.swing with the user interface of our logical components.
      • org.gvsig.viewer.swing.api
      • org.gvsig.viewer.swing.impl
    • org.gvsig.viewer.main our main testing.
  • org.gvsig.viewer.app This Maven project is also a multimodule project, that is it has sub-projects. These will contain the implementation of the various plugins that will be added to gvSIG. Normally you will use the components of the org.gvsig.viewer project and be responsible for the integration of these in gvSIG. In the template used for the generated sample project there is only one subproject, org.gvsig.viewer.app.mainplugin, since we will be providing a single plugin. If we had needed to contribute more than one plugin we would have a subproject for each plugin.

We could work with this but since Eclipse is not able to recognise the structure of Maven subprojects it will be much easier to import the child projects as Eclipse projects.

Select the File->import menu option and in the import dialog and select General->Existing Projects Into Workspace and click next. Click "Select root directory" and select the folder "/home/gvsig/workspce/viewer/org.gvsig.viewer/org.gvsig.viewer.lib". In doing this we suggest adding these projects:

  • org.gvsig.viewer.lib.api
  • org.gvsig.viewer.lib.impl

These will be selected so just press the button end.

Now repeat the process indicating as "root directory" the following folders:

  • /home/gvsig/workspce/viewer/org.gvsig.viewer/org.gvsig.viewer.swing
  • /home/gvsig/workspce/viewer/org.gvsig.viewer/org.gvsig.viewer.main
  • /home/gvsig/workspce/viewer/org.gvsig.viewer.app/org.gvsig.viewer.app.mainplugin

We have now imported all the projects related to our development into our workspace.

Dependencies between projects

First, let's see what dependencies the assistant has left us with in the org.gvsig.viewer project. Notice the following entry in the dependencyManagement section in the project's pom.xml file:

<dependencies>
  <dependency>
    <groupId>org.gvsig</groupId>
    <artifactId>org.gvsig.core.maven.dependencies</artifactId>
    <version>2.0.1-SNAPSHOT</version>
    <type>pom</type>
    <scope>import</scope>
  </dependency>
</dependencies>

This imports the dependencies of the various gvSIG libraries so that we don't have to worry about the versions of any of the gvSIG base libraries. As this importing is done in the dependencyManagement section, it is for information purposes only, ie a dependency on these libraries is not set.

If we now look at the dependencies section, we find the entry:

<dependency>
  <groupId>org.gvsig</groupId>
  <artifactId>org.gvsig.core.maven.dependencies</artifactId>
  <version>2.0.1-SNAPSHOT</version>
  <type>pom</type>
  <scope>test</scope>
</dependency>

This sets the implementation and test dependencies for all the core libraries of gvSIG so that we won't have to worry about whether all the implementations of the gvSIG APIs are loaded when testing our projects.

In addition we see:

<dependency>
  <groupId>org.gvsig</groupId>
  <artifactId>org.gvsig.tools.lib</artifactId>
  <type>jar</type>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.gvsig</groupId>
  <artifactId>org.gvsig.tools.lib</artifactId>
  <type>test-jar</type>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.gvsig</groupId>
  <artifactId>org.gvsig.fmap.geometry</artifactId>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.gvsig</groupId>
  <artifactId>org.gvsig.fmap.dal</artifactId>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.gvsig</groupId>
  <artifactId>org.gvsig.metadata.lib.basic.api</artifactId>
  <scope>compile</scope>
</dependency>

These are fixed build dependencies with the main gvSIG libraries, and are usually required in almost any project that we make with gvSIG.

This configuration of dependencies is found in the main project. Let's now see what dependencies are required for the subprojects.

  • org.gvsig.viewer.lib/pom.xml. This does not provide any declarations of dependencies additional to those defining the parent project already discussed.

  • org.gvsig.viewer.lib.api/pom.xml. Neither of these provide new dependencies.

  • org.gvsig.viewer.lib.impl/pom.xml. Does not provide new dependencies, but in this project we should add dependencies to the API project, both for compilation and for execution of tests.

  • org.gvsig.viewer.swing/pom.xml. Although not providing new dependencies, defined as dependencies of the lib.api. projects.

  • org.gvsig.viewer.swing.api/pom.xml. Does not add new dependencies.

  • org.gvsig.viewer.swing.imple/pom.xml. Although not providing dependencies you must declare dependencies with the swing API for testing and building.

    Warning

    There is also has a dependency on the implementation for compilation and even if you don't think you need it, you should review it.

  • And finally org.gvsig.viewer.main/pom.xml. This will declare the dependencies with our libraries' API for compilation and implementation for execution. Also adds build dependencies to the gvSIG libraries it uses, these being:

    <dependency>
       <groupId>org.gvsig</groupId>
       <artifactId>org.gvsig.fmap.control</artifactId>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>org.gvsig</groupId>
       <artifactId>org.gvsig.fmap.dal</artifactId>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>org.gvsig</groupId>
       <artifactId>org.gvsig.fmap.geometry</artifactId>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>org.gvsig</groupId>
       <artifactId>org.gvsig.fmap.mapcontext</artifactId>
       <scope>compile</scope>
     </dependency>
    

The Logic Library

The logic part of our development is divided into two projects:

  • org.gvsig.viewer.lib.api
  • org.gvsig.viewer.lib.impl

In the API project we find mostly interfaces. These interfaces make up the API of the logic components to be developed. The class model of the example is shown in the following diagram:

../data/org.gvsig.visor.api.png

Model if the API classes

We have the following entities:

  • VisorLibrary, which represents the object Library. In this note class methods:

    • doRegistration, which runs to load the library and tells what kind of library is, in our case the definition of an API as well as what other libraries are required initialized before this, the library of data access, and geometry. The code doing this is:

      public void doRegistration() {
        this.registerAs(VisorLibrary.class, Library.TYPE.API);
        this.require(DALLibrary.class);
        this.require(GeometryLibrary.class);
      }
      
    • doPostInitialize, which is executed when all bookstores have been initialized. In our case checks to verify that at least one implementation API has been registered. The code that does this is:

      protected void doPostInitialize() throws LibraryException {
        // Validate if there are any implementation registered.
        VisorManager manager = VisorLocator.getManager();
        if (manager == null) {
            throw new ReferenceNotRegisteredException(
                VisorLocator.MANAGER_NAME, VisorLocator.getInstance()
              );
        }
      }
      
  • VisorLocator, is the locator of our library, responsible for give us the instance of our manager. This is a class with methods static to register implementations of this API and an implementation him.

  • VisorManager. A interface. The manager of the bookstore. Defines methods to obtain the blocks and plots as well as locating an apple given a point. It is the entrance to the various entities in our model.

  • VisorBlock An interface that represents a block, and provides methods for geometry that defines the block or for the parcels are.

  • VisorProperty. An interface that represents a cadastral parcel. It has methods for geometry that defines it, your code or municipality.

Let's see what we are in the implementation part. Observe that while in the normal API interfaces has been found in the implementation we find classes. Classes that implement the various interfaces that defined in the API. By convention, the implementation of the various interfaces that appear in the API will call the API like prepending the prefix Default.

The class model of implementation for our example is:

../data/org.gvsig.visor.impl.png

Model implementation classes

Let us see the most relevant parts of the implementation.

  • VisorDefaultImplLibrary. As in the API, this class is responsible for initialize the library implementation. In this note class methods:

    • doRegistration, which is responsible for registering the library as an implementation API. VisorLibrary Should you have other dependencies other than those marked on the API, would be added here to make sure these libraries are initialized before this, but it is the case of our example. When you register this library as an implementation of VisorLibrary, cover two functions. On one side the library API will always initialized before this implementation, and secondly when some other library dependencies with the API set, the initialization mechanism library is responsible for initializing the implementation along with the API ensure you have an implementation of the API that we required. The code you need to put in our example is:

      public void doRegistration() {
        this.registerAsImplementationOf(VisorLibrary.class);
      }
      
    • doInitialize, que se encarga de registrar en el locator del API la implementación del manager que tenemos en esta librería. El código que hace esto es:

      protected void doInitialize() throws LibraryException {
          VisorLocator.registerManager(DefaultVisorManager.class);
      }
      
  • DefaultVisorManager. De esta clase conviene resaltar principalmente:

    • El método getBlock. Podemos ver cómo realizar una busqueda de un registro filtrando por una condición espacial:

      try {
        String attrGeomName = blocks.getDefaultFeatureType().getDefaultGeometryAttributeName();
        FeatureQuery query = blocks.createFeatureQuery();
        query.setFilter( new IntersectsEvaluator(attrGeomName,point) );
        set = blocks.getFeatureSet(query);
        if( set.isEmpty() ) {
          return null;
        }
        it = set.fastiterator();
        Feature f = (Feature) it.next();
        VisorBlock block = new DefaultVisorBlock(this,f.getGeometry(attrGeomName));
        return block; 
      } catch (DataException e) {
        ...
      } finally {
        if( it != null ) {
          it.dispose();
        }
        if( set != null ) {
          set.dispose();
        }
      }
      

      Tip

      You can find information on the mechanisms available for querying the data access Guide to the developer of the Data Access Library (DAL)

      From this point out:

      • We can find out which attribute of the features is the one that contains the geometry through the getDefaultGeometryAttributeName from feature type of our store.
      • To perform a search for features in a store we will invoke the method Passed as parameter getFeatureSet an instance of FeatureQuery in which specify the filter conditions. It can also be specified order or attributes that we want to recover in our query.
      • The filter condition is specified by providing a method setFilter Evaluator of our query.
      • We take care of releasing objects that we, like iterators o feature sets. Keep in mind that depending on the type of * store * with which we are working they may have reserved resources and connections to databases, recordsets or connections remote servers.
    • The openShape method. Here's how to open a store based on existing shapes:

      parameters = manager.createStoreParameters("Shape");
      parameters.setDynValue("shpfile", shape);
      parameters.setDynValue("crs", "EPSG:23030");
      return (FeatureStore) manager.openStore("Shape", parameters);
      

      Note that, to open a store we will do this in two phases. On the one hand create a structure to house the parameters needed to open our store the initialized with the appropriate values ​​and invoke the openStore method from the data access manager within those parameters.

      Each type of store will have a set of parameters specific to it. To open a shape, we indicate at least the name of the file and the reference system in which is located.

  • IntersectsEvaluator. This is the class that evaluates the condition used in the filter. This field class checks if the specified geometry intersects a given feature specific geometry. In its construction will provide the field containing the feature geometry and geometry to check whether there are intersecting. In this class should be emphasized:

    • The evaluate method, responsible for conducting the test:

      Geometry op1geom = (Geometry) data.getDataValue(this.op2attrname);
      return new Boolean(this.op1geom.intersects(op1geom));
      

      Knowing how to call the attribute that contains the geometry we can get this through the getDataValue method. Once we have the two geometries intersecs invoke * method * of the geometry to see if intersect.

    • The getCQL method. getCQL This method returns a string in the format of a where of sql to use as a filter in stores that attack to the database sql. The filter can be returned not be exactly the same as that implemented by the method code Evaluate, acting as a filter prior to this if the store supports it.

  • DefaultVisorBlock. Represents a block from our domain. Stores geometry that gives shape to the block. The most important of this class is the getProperties method that returns all parcels that are on the block:

    List<VisorProperty> properties = new ArrayList<VisorProperty>();            
    
    FeatureStore store = this.manager.getProperties();
    String attrGeomName = store.getDefaultFeatureType().getDefaultGeometryAttributeName();
    FeatureQuery query = store.createFeatureQuery();
    query.setFilter( new IntersectsEvaluator(attrGeomName, this.shape) );
    set = this.manager.getProperties().getFeatureSet(query);
    if( set.isEmpty() ) {
      return null;
    }
    it = set.fastiterator();
    while( it.hasNext() ) {
      Feature f = (Feature) it.next();
      VisorProperty property = new DefaultVisorProperty(
        this.manager,
        f.getString(PROPERTIES_CODE),
        f.getGeometry(attrGeomName),
        f.getInt(PROPERTIES_CREATIONDATE),
        f.getInt(PROPERTIES_MUNICODE)
      );
      properties.add(property);
    }
    return properties;
    

    We can see that the same mechanism used to filter the plots use the manager to retrieve an apple. In this case once you get the set the plots, runs, retrieving data from these and creating plot objects.

  • DefaultVisorProperty. This is the class that represents a plot. In our example is not only logical, merely exposing the data store by geters.

Presentation libray

Direct translation with Google Translator

As happened with the logic, the presentation also will be divided into two projects, on the one hand and on the other API implementation.

  • org.gvsig.visor.swing.api
  • org.gvsig.visor.swing.impl

Similar to as with the logic in the presentation, in the draft We only have the API interfaces and abstract classes that define our API. the API of the presenting part is formed by the interface along with manager a set of abstract classes that define the public API of our components, components usually extend to swing JPanel component. These classes are interfaces and abstract because no swing model interfaces for its components. In our example, the only component that is we visual component associated with an apple, the JVisorBlockPanel, which extends from JPanel API level by adding a single method that allows us to obtain the VisorBlock logical component that is associated at any given time.

In the implementation we will find the class DefaultJVisorBlockPanel it receives in its constructor the instance of the VisorBlock to be submitted their data. In general the presentation is not a complication beyond of persons as may be handling swing. The only thing to note is that the presentation should not use anything that is not exposed in the API from our library of logic.

A test application

Direct translation fron google translator

So far we've seen pieces that made up the various loose components that we needed to do our small viewfinder. We will see Now how can we join all those pieces and some more to create a simple viewer let us try everything without having to boot all gvSIG.

To do this, we focus on the org.gvsig.visor.main project. It can find a main class with everything you need to present our map and test our components.

Our program presents a window with a map and a few buttons to zoom or pan tools enable or our information tool on parcels of an apple.

Tip

It may be useful to consult the existing literature on the component MapControl This documentation is not has been updated with the changes that have made in that component in version 2 of gvSIG broad lines but continues to provide the same functionality and help better understand the tool.

To do this we will:

  • Create our swing component to display a map:

    mapControlManager = MapControlLocator.getMapControlManager();

    mapControl = mapControlManager.createJMapControlPanel();

  • We add the standard tools of zoom and pan, and we will set pan tool as the active tool:

    mapControl.addBehavior(
      "zoom", 
      new Behavior[] {  
        new RectangleBehavior(new ZoomInListenerImpl(mapControl)),
        new PointBehavior(new ZoomOutRightButtonListener(mapControl))
      }
    );
    mapControl.addBehavior(
      "pan", 
      new MoveBehavior(
        new PanListenerImpl(mapControl)
      )
    );
    mapControl.setTool("pan");
    
  • Add the buttons and links to tools that just register on our map:

    toolBar.add(
      new JButton(
        new AbstractAction("Zoom") {
          public void actionPerformed(ActionEvent e) {
            mapControl.setTool("zoom");
          }
        }
      )
    );
    
  • We will create our layer of apples and add to the map:

    FLyrVect layer = (FLyrVect) MapContextLocator.getMapContextManager().createLayer(
      "Blocks", 
      manager.getBlocks()
    );
    mapControl.getMapContext().getLayers().addLayer(layer);
    
  • And finally we will create our own tools and will record information on the map:

    PropertiesOfBlockListener listener = new PropertiesOfBlockListener();
    mapControl.addBehavior(SHOWINFO_TOOL_NAME, new PointBehavior(listener));
    

    This will register a point-like behavior, which associates a listener to perform particular actions that do not interest you. The listener code would be:

    public class PropertiesOfBlockListener extends AbstractPointListener {
    
      public void point(PointEvent event) throws BehaviorException {
        VisorSwingManager swingManager = VisorSwingLocator.getSwingManager();
    
        VisorBlock block;
        try {
          block = swingManager.getManager().getBlock(event.getMapPoint());
          if( block == null ) {
            return;
          }
          JPanel panel = swingManager.createJVisorBlockPanel(block);
          ToolsLocator.getWindowManager().showWindow(panel, "Block information", WindowManager.MODE.TOOL);
        } catch (VisorException e) {
          // FIXME: Process exception
          throw new RuntimeException("Can't show properties of selected block.",e);
        }
      }
    
    }
    

    Primarily derived from AbstractPointListener overwriting the point method that is called to perform the action associated with this tool. This method is limited to call our getBlocks method from the position on the map that was clicked, and if get some apple at that point our panel will be created to report this information in a window.

    What might be more remarkable when viewed in the parameter event for the coordinates of the point that was clicked is done through the getMapPoint method to ensure that returns us to map coordinates and not screen.

Integrating with gvSIG

Direct translation from google Translator

So far we have seen how to create our components, logic and user interface, using gvSIG libraries to access the geographic data or to present as well as a simple way to create a small application that uses them. Let's see now as integrate implementing these features in gvSIG.

If we look at the projects we have in your workspace you will see that there is still one on which we have not worked, org.gvsig.visor.app.mainplugin . That is where we implemented plugin. Before the plugin code to see a detailed comment. When we described what had to do our extension, we said we had to present a splash customized. Let us first how we can do this.

In the folder "src/main/resources" folder find a theme, and within this one andami-theme.xml file. This file is responsible for specifying the andami framework which splash must dislay as well as must be used a background image in the application MDI or the gvSIG windows icons. Andami, when starts, searchs into the extensions folder anyone wich contains a theme folder and within this file and when it finds it, it uses it. Xml file in our example contains:

<AndamiProperties>
  <ApplicationImages>
    <SplashImages>
      <Splash
      path="splash.png"
      timer="10000"
      x="270" y="240"
      fontsize="18" 
      color="80,170,240"
      version="2.0"/>
    </SplashImages>
    <!--BackgroundImage path="theme/logo_es.png"/-->
    <!--WallpaperType value="CENTERED"/-->
    <Icon path="$GVSIG_INSTALL/theme/icon.png"/>
  </ApplicationImages>
  <ApplicationName value="gvSIG 2.0.0"/>
</AndamiProperties>

By default routes appear in the file will be interpreted on the location of this file, having a variable GVSIG_INSTALL point to the folder where gvSIG is installed. In the example we see how the tag Splash not indicated path to the file "splash.png" Authors used the files in the folder while the plugin tag Icon variable GVSIG_INSTALL is used to refer the file is in the default theme of Andami.

GvSIG can start and check out the splash indicated in our andami-theme.xml.

Having seen how we can change the splash, we take a look at the extension of our plugin.

Now let's see the code for our plugin. We will see that there are only two classes, VisorExtension and PropertiesOfBlockListener VisorExtension. The class that integrates our functionality in gvSIG is VisorExtension. This class extends the Andami class Extension to integrate with the menus and toolbars, and implements the ExclusiveUIExtension interface to control the visibility of other gvSIG extensions.

To control the visibility of the other areas of gvSIG, the interface ExclusiveUIExtension provides methods:

  • isEnabled receiving as parameter the extension on which want to know whether to be enabled or not:

    public boolean isEnabled(IExtension extension)
    

    In our case, as we want to disable all extensions editing, check if the extension that comes in the java package "org.gvsig.editing" and for all who are in that package return false, while for the rest, delegating them to determine whether or not to be enabled.

  • isVisible receiving as parameter the extension on which want to find out whether it should be visible or not:

    public boolean isVisible(IExtension extension)
    

    In our case, we will use to determine which areas should be visible the same we use to determine whether they should be disabled.

It is very important delegate isEnabled or isVisible methods of each extension and not return true as you may specify the extent of certain specified conditions; to be visible and active checks herself.

The methods that we find in our class VisorExtension that needs to extend to Extension are:

  • initialize. Is invoked when loading a. Here we will simply record services provided by our extension. In our case we will simply inform the plugins Manager that our viewer class wants our to act as controller of the visibility of all extensions. This is done through the method SetExclusiveUIExtension:

    PluginsManager manager = PluginsLocator.getManager();
    manager.setExclusiveUIExtension(this);
    
  • PostInitialize. Invoked during the initialization of the plugin, once invoked initialize method of all extensions. This guarantees that when you run will become available virtually all parts of gvSIG. Take advantage of this method for:

    • Add our information about gvSIG, this is done through our addToAbout function. The code that does is:

      AboutManager about = AboutLocator.getManager();
      
      URL description = getResourceURL("about/description.html");
      URL icon = getResourceURL("about/icon.png");
      AboutParticipant dev = about.addDeveloper("Mi empresa", description, 1, icon);
      dev.addContribution("Mi visor", "Visor para consulta de parcelas catastrales", 2011, 5, 1, 2011, 7, 1);
      

      When we add our information to "about", we have to do two things:

      • Add an entry and developers with our information. We provide the name of our company and a description of this by the URL to an HTML document. Normally this document is resources of our project.

        If two extensions try to add more than once as a business developer with the same name will be added only the first.

      • Added information about our company development we have done, a name and a brief description.

      Normally we make each plugin register the company, such information concrete development of the plugin.

    • Create the manager of the logic part of our library.

    • Initialize stores through our function initializeStores. As the manager of our logical library has methods available to initialize the stores, we will be limited to invoke them:

      manager.initialize(
        getResource("data/properties.shp"), 
        getResource("data/blocks.shp")
      );
      
    • And finally create and display for sale with our eyes, through the method createViewWindow. let's see a little more detail how this is done. Before you start first thing to do is to obtain an object reference application and projects Manager:

      ApplicationManager application = ApplicationLocator.getManager();
      ProjectManager projectManager = application.getProjectManager();
      

      Once we have these references, we can create our view:

      // 1. Create a new view and set the name.
      ViewManager viewManager = (ViewManager) projectManager.getDocumentManagers(ViewManager.TYPENAME);
      ViewDocument view = (ViewDocument) viewManager.createDocument();
      view.setName(MY_VIEW_NAME);
      

      To create the view, ask to ProjectManager to return the manager views as This will ask a new instance of the document view. We recall here one of the main features of the manager is to act as a factory for instances of the managed objects that manager. Once we have the document view, assign the name that we deem appropriate.

      With the view already created, we will see what we do to add to this the layers need it. This will create a layer with the Manzamo this end we use createLayer method, indicating the name of the layer and the store on that we want to be based:

      // 2. Create a new layer with the blocks
      FLyrVect layer = (FLyrVect) application.getMapContextManager().createLayer("Blocks", this.manager.getBlocks());
      

      With the layer already created, add the * map * of the view the new layer:

      // 3. Add this layer to the mapcontext of the new view.
      view.getMapContext().getLayers().addLayer(layer);
      

      We will add th view to the current project:

      // 4. Add the view to the current project.
      projectManager.getCurrentProject().add(view);
      

      And finally we will present the window Join the view that just created:

      // 5. Force to show the view's window.
      IView viewWindow = (IView) viewManager.getMainWindow(view);
      
      application.getUIManager().addWindow(viewWindow, GridBagConstraints.CENTER);
      try {
        application.getUIManager().setMaximum((IWindow) viewWindow, true);
      } catch (PropertyVetoException e) {
        logger.info("Can't maximize view.",e);
      }
      

      Once we have shown our view window, be recorded in the map graphic component we bring the new tool, similar to as we did to add it to our map in the test project:

      // 6. Register my tool in the mapcontrol of the view.
      PropertiesOfBlockListener listener = new PropertiesOfBlockListener();
      viewWindow.getMapControl().addBehavior(TOOL_NAME, new PointBehavior(listener));
      

    With all this we initialize our plugin.

  • execute. This method will be invoked whenever the user interacts with the options menu or buttons that are configured in the config.xml file of our plugin. In our case, was set to trigger this event when the user wanted to activate the tool of information on cadastral parcels an apple. So the code would have to have there must correspond with this:

    if( ACTION_SETINFOTOOL.equalsIgnoreCase(actionCommand) ) {
      // Set the tool in the mapcontrol of the active view.
      ApplicationManager application = ApplicationLocator.getManager();
      if( application.getActiveWindow() != viewWindow ) {
        return;
      }
      viewWindow.getMapControl().setTool(TOOL_NAME);
      }
    }
    

    Observe that the first thing we do is check if the command received is that corresponding to the activation of our tool, and we set in config.xml. This is because in the same extension can group several tools, indicating different command names in the config.xml for each.

    Once we know that you are trying to activate our reporting tool, check if the window is active in our view, since on other views or other document types, we should not do anything. And finally, we will work to activate our tool in the map view. Toolmakers we recorded postInitialize * in * our extension.

  • isVisible. In this method we report if the menus and buttons associated with our tool should be visible. In our case, our tool will leave visible where is the active window from view:

    ApplicationManager application = ApplicationLocator.getManager();
    return application.getActiveWindow() == viewWindow;
    
  • isEnabled, which always return 'true', since our tool is active whenever it is visible, and there he put the necessary checks. If the logic allows our tool is not active in some cases which itself is allowed to be visible, will be here where we make these checks.

Basically, we have reviewed as is the integration of our functionality in gvSIG. It remains to be seen PropertiesOfBlockListener class we use to create our tool. The code of the listener is basically similar to that used by our test application.

Distributing our project.

direct translation from google translator*

Once we have our development can be deployed on a run that gvSIG gvSIG and see if it works. Now, normally our work not end there. Typically, we have to do to get these plugins to our users, or even before testers to verify that everything works properly.

With version 2.0 of gvSIG we developed a packaging system that allow us to distribute plugins so that users can install easily from the Add-ons Manager gvSIG (this functionality was ported a gvSIG version 1.11.0).

Tip

You can consult the documentation on how to build packages plugin for gvSIG in the section of the development guide, Generate an installation package in paragraph Generation from installation plugin .

The point is how to generate these packages with our plugins. Like with the standard installation of gvSIG had a utility to assist in the creation of our development projects, there is also a utility to generate a plugin packages already installed on gvSIG.

As we had to activate the project creation wizard from the preferences window, activate the same way this utility. We'll go gvSIG preferences panel, and in general, extensions look "org.gvsig.installer.app.extension.creation.MakePluginPackageExtension", and activate the extension. Once activated we gvSIG restart to take effect changes.

When you reboot gvSIG have the option "Create plugin installation package" in the menu Tools->Development. We will use this tool to build the package Installation of our plugin.

The installation package can be generated directly distribute to our users or to have them reach gvSIG to be exposed in the repository gvSIG supplements and available to users directly from the Add-ons Manager through of the URL displayed by default.

Likewise, for when it is ready the final version of gvSIG 2.0 is expected to have a mechanism that allows to easily include these binary packages in the official distribution gvSIG so that we can have a custom installer for our plugins deliver to our customers.

Conclusions

direct translation from google translator

We saw very quickly how to create our project to develop a functionality to gvSIG 2.0. It is not just a gvSIG development in We can actually see that this is an orderly way to develop, separating the different layers of abstraction that can be found in development:

  • Business logic
  • User Interface
  • Integration with gvSIG

And each clearly marked as part of our API and what is implementation.

Not only provide functionality to gvSIG, if not we offer the functionality so it can be reused by other developments through a well defined API, pudiéndonos benefit other projects that have packaged functionality as a library.

In addition we will benefit from Maven mechanisms that allow us to deploy these libraries to be easily accessible to other developers.

Finally note that this way of working also allows us to deploy our plugins easily as they reduce the dependencies between plugins directly attack the libraries you need.

Related documents


Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: