...
The goal of this quickstart is to introduce you to the the context menu api, so you will be able to add context menu extensions in your IGB Apps.
- Clone the quickstart project
Info |
---|
|
"A context menu (also called contextual, shortcut, and popup or pop-up menu) is a menu in a graphical user interface (GUI) that appears upon user interaction, such as a right-click mouse operation. A context menu offers a limited set of choices that are available in the current state, or context, of the operating system or application. Usually the available choices are actions related to the selected object." |
Image Modified
IGB Context Menu
...
Image Added
Image Removed
Code Block |
---|
|
package org.lorainelab.igb.context.menu.menu.api;
import java.util.List;
import java.util.Optional;
import org.lorainelab.igb.contextmenu.menuapi.model.AnnotationContextEvent;
import org.lorainelab.igb.contextmenu.menuapi.model.ContextMenuItem;
/**
*
* @author dcnorris
*/
public interface AnnotationContextMenuProvider {public interface AnnotationContextMenuProvider {
public Optional<ContextMenuItem>Optional<List<ContextMenuItem>> buildMenuItem(AnnotationContextEvent event);
public MenuSection getMenuSection();
}}
|
Code Block |
---|
|
package org.lorainelab.igb.contextmenu.menuapi.model;
import com.affymetrix.genometry.symmetry.impl.SeqSymmetry;
import java.util.List;
/**
*
* @author dcnorris
*/
public class AnnotationContextEvent {
private final List<SeqSymmetry> selectedItems;
public AnnotationContextEvent(List<SeqSymmetry> selectedItems) {
this.selectedItems = selectedItems;
}
public List<SeqSymmetry> getSelectedItems() {
return selectedItems;
}
}
|
Code Block |
---|
|
package org.lorainelab.igb.context.menu.api.quickstartmodel;
import aQutejava.bnd.annotation.component.Componentutil.Set;
import java.util.Optionalfunction.Function;
import org.lorainelab.igb.context.menu.AnnotationContextMenuProvider;
import org.lorainelab.igb.context.menu.MenuSection;
import org.lorainelab.igb.context.menu.model.AnnotationContextEvent;
import org.lorainelab.igb.context.menu.model.ContextMenuItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author dcnorris
*/
@Component(immediate = true)
public class ContextMenuExtension implements AnnotationContextMenuProvider {
private static final Logger logger = LoggerFactory.getLogger(ContextMenuExtension.class
public class ContextMenuItem extends MenuItem {
private ContextMenuSection menuSection = ContextMenuSection.APP;
public ContextMenuItem(String menuLabel, Set<MenuItem> subMenuItems) {
super(menuLabel, subMenuItems);
}
public ContextMenuItem(String menuLabel, Function<Void, Void> action) {
super(menuLabel, action);
@Override}
public Optional<ContextMenuItem>void buildMenuItemsetMenuSection(AnnotationContextEventContextMenuSection eventmenuSection) {
ContextMenuItemthis.menuSection contextMenuItem = new ContextMenuItem("Log Selection ids", (Void t) -> {menuSection;
}
public event.getSelectedItems().stream().map(selectedSym -> selectedSym.getID()).forEach(logger::info);
ContextMenuSection getMenuSection() {
return tmenuSection;
});
return Optional.ofNullable(contextMenuItem);
}
@Override
public MenuSection getMenuSection()}
}
|
Code Block |
---|
|
package org.lorainelab.igb.menu.api.model;
import com.google.common.io.BaseEncoding;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MenuIcon {
private String encodedImage;
return MenuSection.INFORMATION;
private static }
}
|
Code Block |
---|
|
package org.lorainelab.igb.context.menu.model;
import com.google.common.io.BaseEncoding;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author dcnorris
*/
public class MenuIconfinal Logger logger = LoggerFactory.getLogger(MenuIcon.class);
public MenuIcon(InputStream resourceAsStream) {
try {
private String encodedImage;
private static final Logger logger = LoggerFactory.getLogger(MenuIcon.class);
public MenuIcon(InputStream resourceAsStream) {
try {
encodedImage encodedImage = BaseEncoding.base64().encode(IOUtils.toByteArray(resourceAsStream));
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
}
public byte[] getEncodedImage() {
return BaseEncoding.base64().decode(encodedImage);
}
}
|
...
ContextMenuSection
Code Block |
---|
|
package org.lorainelab.igb.menu.contextapi.menumodel;
/**
*
* @author dcnorris
*/
public enum MenuSectionContextMenuSection {
INFORMATION,
SEQUENCE,
APP,
UI_ACTION;
}
|
...
Code Block |
---|
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.affymetrix</groupId>
<artifactId>igb-project</artifactId>
<version>9.0.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<groupId>org.lorainelab.igb</groupId>
<artifactId>context-menu-api</artifactId>
<packaging>bundle</packaging>
<name>Context Menu API</name>
<dependencies>package org.lorainelab.igb.context.menu.api.quickstart;
import aQute.bnd.annotation.component.Component;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import org.lorainelab.igb.menu.api.AnnotationContextMenuProvider;
import org.lorainelab.igb.menu.api.model.AnnotationContextEvent;
import org.lorainelab.igb.menu.api.model.ContextMenuItem;
import org.lorainelab.igb.menu.api.model.ContextMenuSection;
import org.lorainelab.igb.menu.api.model.MenuIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(immediate = true)
public class ContextMenuExtension implements AnnotationContextMenuProvider {
private static final Logger LOG = LoggerFactory.getLogger(ContextMenuExtension.class);
private static final String ICONPATH = "terminal.png";
@Override
public Optional<List<ContextMenuItem>> buildMenuItem(AnnotationContextEvent event) {
ContextMenuItem contextMenuItem = new ContextMenuItem("Log Selection ids", (Void t) -> {
event.getSelectedItems().stream().map(selectedSym -> selectedSym.getID()).forEach(LOG::info);
<dependency>
return t;
<groupId>biz.aQute.bnd</groupId> });
try (InputStream resourceAsStream <artifactId>bndlib</artifactId>= ContextMenuExtension.class.getClassLoader().getResourceAsStream(ICONPATH)) {
<scope>provided</scope> contextMenuItem.setMenuIcon(new MenuIcon(resourceAsStream));
</dependency>
} catch (Exception <dependency>ex) {
<groupId>com.affymetrix</groupId>LOG.error(ex.getMessage(), ex);
<artifactId>genometry</artifactId>}
<scope>provided</scope>contextMenuItem.setMenuSection(ContextMenuSection.INFORMATION);
</dependency> return Optional.ofNullable(Arrays.asList(contextMenuItem));
<dependency>
}
}
|
Code Block |
---|
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<groupId>com.affymetrix</groupId>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>igb-services</artifactId> <groupId>org.lorainelab.igb</groupId>
<scope>provided</scope><artifactId>igb-project</artifactId>
</dependency> <version>9.0.0</version>
<dependency></parent>
<groupId>com.google.guava<<groupId>org.lorainelab.igb</groupId>
<artifactId>org.lorainelab.igb.menu.api.quickstart</artifactId>
<version>1.0.0</version>
<artifactId>guava<<packaging>bundle</artifactId>packaging>
<name>Context Menu <scope>provided</scope>Extension Quickstart</name>
</dependency><dependencies>
<!--Start of logging dependencies-->
<dependency>
<dependency>
<groupId>org.slf4j< <groupId>biz.aQute.bnd</groupId>
<artifactId>slf4j-api<<artifactId>bndlib</artifactId>
<scope>provided</scope>
</dependency>
<!--End of logging dependencies-->
<dependency>
<groupId>com<groupId>org.lorainelab.affymetrix<igb</groupId>
<artifactId>affymetrix-common<<artifactId>genometry</artifactId>
<scope>provided</scope>
</dependency>
</dependency>!--Start of logging dependencies-->
<dependency>
<groupId>commons-io<<groupId>org.slf4j</groupId>
<artifactId>commons<artifactId>slf4j-io<api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<!--End of logging dependencies-->
<plugins>
<dependency>
<plugin>
<groupId>org.lorainelab.igb</groupId>
<artifactId>maven-clean-plugin< <artifactId>org.lorainelab.igb.menu.api</artifactId>
<<scope>provided</plugin>scope>
</dependency>
<plugin></dependencies>
<build>
<plugins>
<groupId>org.apache.maven.plugins</groupId>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration><executions>
<instructions><execution>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName><id>build plugin repository</id>
<Import-Package>*</Import-Package><goals>
<Export-Package>
<goal>
${project.groupId}.context.menu,
index
${project.groupId}.context.menu.model
</goal> </Export-Package>
<Service-Component>*</Service-Component>
goals>
<<phase>package</instructions>
phase>
</configuration><configuration>
</plugin>
</plugins>
<obrRepository>${project.build.directory}</build>
</project>
obrRepository>
<mavenRepository>${project.build.directory}</mavenRepository>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Import-Package>*</Import-Package>
<Export-Package/>
<Service-Component>*</Service-Component>
<Bundle-Description>${bundleDescription}</Bundle-Description>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.lorainelab</groupId>
<artifactId>bundle-markdown-encoder</artifactId>
<executions>
<execution>
<goals>
<goal>encodeMarkdown</goal>
</goals>
</execution>
</executions>
<configuration>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</configuration>
</plugin>
</plugins>
</build>
</project>
|
Add a README.md markdown file to the root of the project for a customized APP manager display of your new app.
Example
Code Block |
---|
|
# Context Menu API Quickstart
A small example context menu extension that logs the ids of all selected SeqSymmetry objects
```java
package org.lorainelab.igb.context.menu.api.quickstart;
import aQute.bnd.annotation.component.Component;
import java.io.InputStream;
import java.util.Optional;
import org.lorainelab.igb.context.menu.AnnotationContextMenuProvider;
import org.lorainelab.igb.context.menu.MenuSection;
import org.lorainelab.igb.context.menu.model.AnnotationContextEvent;
import org.lorainelab.igb.context.menu.model.ContextMenuItem;
import org.lorainelab.igb.context.menu.model.MenuIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author dcnorris
*/
@Component(immediate = true)
public class ContextMenuExtension implements AnnotationContextMenuProvider {
private static final Logger logger = LoggerFactory.getLogger(ContextMenuExtension.class);
private static final String ICONPATH = "terminal.png";
@Override
public Optional<ContextMenuItem> buildMenuItem(AnnotationContextEvent event) {
ContextMenuItem contextMenuItem = new ContextMenuItem("Log Selection ids", (Void t) -> {
event.getSelectedItems().stream().map(selectedSym -> selectedSym.getID()).forEach(logger::info);
return t;
});
try (InputStream resourceAsStream = ContextMenuExtension.class.getClassLoader().getResourceAsStream(ICONPATH)) {
contextMenuItem.setMenuIcon(new MenuIcon(resourceAsStream));
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
return Optional.ofNullable(contextMenuItem);
}
@Override
public MenuSection getMenuSection() {
return MenuSection.INFORMATION;
}
}
```
|
- Navigate to the root of the project (e.g. the cloned repository https://bitbucket.org/lorainelab/context-menu-api-quickstart.git)
- use maven to build the project
Code Block |
---|
mvn clean install |
- The build process will result in a new folder being added into your project directory (i.e. the target folder)
- Add the target directory as a new IGB App repository
- IGB App Manger Tab -> Launch App Manager -> Manage Repositories -> Add...
- Image Added
- Image Added
- Select and add the target directory
- Use the IGB App Manager to Install the new plugin
- Image Added
Image Added