...
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.contextmenu.menuapi.model;
import static comjava.google.common.base.Preconditions.checkNotNullutil.Set;
import static comjava.googleutil.common.base.Preconditions.checkState;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
/**
*
* @author dcnorris
*/
public class ContextMenuItem {
private final String menuLabelfunction.Function;
public class ContextMenuItem extends MenuItem {
private ContextMenuSection menuSection = ContextMenuSection.APP;
public ContextMenuItem(String menuLabel, Set<MenuItem> subMenuItems) {
super(menuLabel, subMenuItems);
private}
MenuIcon menuIcon;
public ContextMenuItem(String privatemenuLabel, Function<Void, Void> action;) {
private Set<ContextMenuItem> subMenuItems;
super(menuLabel, action);
private int weight = 0;}
public void ContextMenuItemsetMenuSection(String menuLabel, Set<ContextMenuItem> subMenuItemsContextMenuSection menuSection) {
this.menuSection = checkNotNull(menuLabel)menuSection;
}
checkNotNullpublic ContextMenuSection getMenuSection(subMenuItems); {
checkState(!Strings.isNullOrEmpty(menuLabel))return menuSection;
checkState(!subMenuItems.isEmpty());
this.menuLabel = menuLabel;
this.subMenuItems = ImmutableSet.copyOf(subMenuItems);
}}
}
|
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;
private static final Logger logger = LoggerFactory.getLogger(MenuIcon.class);
public ContextMenuItemMenuIcon(String menuLabel, Function<Void, Void> actionInputStream resourceAsStream) {
try checkNotNull(menuLabel);
{
checkState(!Strings.isNullOrEmpty(menuLabel));
encodedImage checkNotNull(action= BaseEncoding.base64().encode(IOUtils.toByteArray(resourceAsStream));
} catch this.menuLabel = menuLabel;
(Exception ex) {
this.action = actionlogger.error(ex.getMessage(), ex);
subMenuItems = ImmutableSet.of();}
}
public Stringbyte[] getMenuLabelgetEncodedImage() {
return menuLabelBaseEncoding.base64().decode(encodedImage);
}
}
public Function<Void, Void> getAction() |
ContextMenuSection
Code Block |
---|
|
package org.lorainelab.igb.menu.api.model;
public enum ContextMenuSection {
INFORMATION,
return action;SEQUENCE,
}APP,
public Set<ContextMenuItem> getSubMenuItems() {
return subMenuItems;
}
public void setWeight(int weight) {
this.weight = weight;
}
public void setMenuIcon(MenuIcon menuIcon) {
this.menuIcon = menuIcon;
}
public Optional<MenuIcon> getMenuIcon() {
return Optional.ofNullable(menuIcon);
}
}
|
Code Block |
---|
|
packageUI_ACTION;
}
|
Image Added
Code Block |
---|
|
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.contextmenu.menuapi.model.ContextMenuSection;
import comorg.googlelorainelab.commonigb.io.BaseEncoding;
import java.io.InputStreammenu.api.model.MenuIcon;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
@Component(immediate *
* @author dcnorris
*/= true)
public class MenuIconContextMenuExtension {
implements private String encodedImage;AnnotationContextMenuProvider {
private static final Logger loggerLOG = LoggerFactory.getLogger(MenuIconContextMenuExtension.class);
publicprivate MenuIcon(InputStream resourceAsStream) {
static final String ICONPATH = "terminal.png";
try {@Override
public Optional<List<ContextMenuItem>> buildMenuItem(AnnotationContextEvent event) {
encodedImage = BaseEncoding.base64().encode(IOUtils.toByteArray(resourceAsStream));
ContextMenuItem contextMenuItem = new ContextMenuItem("Log Selection }ids", catch (ExceptionVoid ext) -> {
loggerevent.errorgetSelectedItems(ex).getMessagestream(), ex.map(selectedSym -> selectedSym.getID()).forEach(LOG::info);
}
return }t;
public byte[] getEncodedImage(}) {;
return BaseEncoding.base64try (InputStream resourceAsStream = ContextMenuExtension.class.getClassLoader().decodegetResourceAsStream(encodedImageICONPATH));
}
} |
Code Block |
---|
|
package org.lorainelab.igb.context.menu;
/**
*
* @author dcnorris
*/
public enum MenuSection {
INFORMATION, SEQUENCE, APP, UI_ACTION;
} |
Image Removed
Code Block |
---|
|
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) -> {
{
contextMenuItem.setMenuIcon(new MenuIcon(resourceAsStream));
} catch (Exception ex) {
LOG.error(ex.getMessage(), ex);
}
contextMenuItem.setMenuSection(ContextMenuSection.INFORMATION);
return Optional.ofNullable(Arrays.asList(contextMenuItem));
}
}
|
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>org.lorainelab.igb</groupId>
<artifactId>igb-project</artifactId>
<version>9.0.0</version>
</parent>
<groupId>org.lorainelab.igb</groupId>
<artifactId>org.lorainelab.igb.menu.api.quickstart</artifactId>
<version>1.0.0</version>
<packaging>bundle</packaging>
<name>Context Menu Extension Quickstart</name>
<dependencies>
<dependency>
<groupId>biz.aQute.bnd</groupId>
<artifactId>bndlib</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
event.getSelectedItems().stream().map(selectedSym -> selectedSym.getID()).forEach(logger::info);<groupId>org.lorainelab.igb</groupId>
return t;
<artifactId>genometry</artifactId>
});
<scope>provided</scope>
</dependency> try
(InputStream resourceAsStream = ContextMenuExtension.class.getClassLoader().getResourceAsStream(ICONPATH)) {
<!--Start of logging dependencies-->
contextMenuItem.setMenuIcon(new MenuIcon(resourceAsStream)); <dependency>
} catch (Exception ex) { <groupId>org.slf4j</groupId>
logger.error(ex.getMessage(), ex);
<artifactId>slf4j-api</artifactId>
}<scope>provided</scope>
return Optional.ofNullable(contextMenuItem);</dependency>
}
@Override
public MenuSection getMenuSection() {
<!--End of logging dependencies-->
<dependency>
return MenuSection.INFORMATION;
}
}
|
Code Block |
---|
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<groupId>org.lorainelab.igb</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>org.lorainelab.igb.menu.api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<groupId>com.affymetrix</groupId><plugin>
<artifactId>igb-project</artifactId>
<version>9<groupId>org.0apache.0<felix</version>groupId>
<relativePath>../../pom.xml</relativePath> <artifactId>maven-bundle-plugin</artifactId>
</parent>
<groupId>org.lorainelab.igb</groupId>
<artifactId>context-menu-api</artifactId>
<packaging>bundle<<extensions>true</packaging>extensions>
<name>Context Menu API</name>
<dependencies><executions>
<dependency>
<groupId>biz.aQute.bnd</groupId>
<execution>
<artifactId>bndlib</artifactId>
<id>build plugin <scope>provided<repository</scope>id>
</dependency>
<dependency>
<goals>
<groupId>com.affymetrix</groupId>
<artifactId>genometry</artifactId>
<scope>provided</scope>
<goal>
</dependency>
<dependency>
<groupId>com.affymetrix</groupId>
index
<artifactId>igb-services</artifactId>
<scope>provided</scope>
</dependency> </goal>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>provided<</scope>goals>
</dependency>
<!--Start of logging dependencies-->
<phase>package</phase>
<dependency>
<groupId>org.slf4j</groupId>
<configuration>
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
<obrRepository>${project.build.directory}</dependency>
obrRepository>
<!--End of logging dependencies-->
<dependency>
<groupId>com.affymetrix</groupId>
<mavenRepository>${project.build.directory}</mavenRepository> <artifactId>affymetrix-common</artifactId>
<scope>provided</scope>
</dependency>configuration>
<dependency>
<groupId>commons-io<</groupId>execution>
<artifactId>commons-io</artifactId>
</executions>
<scope>provided</scope> <configuration>
</dependency>
</dependencies>
<build>
<instructions>
<plugins>
<plugin>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<artifactId>maven-clean-plugin</artifactId>
<Import-Package>*</plugin>Import-Package>
<plugin>
<Export-Package/>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<Service-Component>*</Service-Component>
</plugin>
<Bundle-Description>${bundleDescription}</Bundle-Description>
<plugin>
<groupId>org.apache.felix</groupId></instructions>
<artifactId>maven-bundle-plugin</artifactId>
</configuration>
</plugin> <extensions>true</extensions>
<configuration><plugin>
<groupId>org.lorainelab</groupId>
<instructions>
<artifactId>bundle-markdown-encoder</artifactId>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<executions>
<Import-Package>*</Import-Package> <execution>
<Export-Package><goals>
${project.groupId}.context.menu,<goal>encodeMarkdown</goal>
</goals>
${project.groupId}.context.menu.model
</execution>
</Export-Package>
</executions>
<Service-Component>*</Service-Component><configuration>
</instructions><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.
...
...