created a simple plugin interface
This commit is contained in:
103
plugins/BasicListStatisticsPlugin.groovy
Normal file
103
plugins/BasicListStatisticsPlugin.groovy
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import de.frosch95.geofrogger.plugins.Plugin
|
||||||
|
import javafx.collections.FXCollections
|
||||||
|
import javafx.scene.chart.PieChart
|
||||||
|
import javafx.scene.control.Label
|
||||||
|
import javafx.scene.control.ScrollPane
|
||||||
|
import javafx.scene.layout.Pane
|
||||||
|
import javafx.scene.layout.VBox
|
||||||
|
import org.controlsfx.dialog.Dialog
|
||||||
|
|
||||||
|
import static javafx.scene.chart.PieChart.Data
|
||||||
|
|
||||||
|
class BasicListStatisticsPlugin implements Plugin {
|
||||||
|
|
||||||
|
private difficultyTerrainValues = ['1', '1.5', '2', '2.5', '3', '3.5', '4', '4.5', '5']
|
||||||
|
|
||||||
|
final String name = "Basic List Statistic"
|
||||||
|
final String version = "0.0.1"
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void run(final Map context) {
|
||||||
|
showDialog(createHeader(context.sessionContext), createContent(context.sessionContext))
|
||||||
|
}
|
||||||
|
|
||||||
|
private javafx.scene.Node createHeader(sessionContext) {
|
||||||
|
def pane = new Pane()
|
||||||
|
def Label label = new Label()
|
||||||
|
label.text = "This example plugin shows some stats based on the current list.\nThese statistics are global statistics over all caches in list\nand not personalized statistics over own founds."
|
||||||
|
pane.children.add(label)
|
||||||
|
pane
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates the statistic charts to show
|
||||||
|
* @param sessionContext context with the cache list in it
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private javafx.scene.Node createContent(sessionContext) {
|
||||||
|
|
||||||
|
// get the cache list out of the context
|
||||||
|
def cacheList = sessionContext.getData("cache-list")
|
||||||
|
|
||||||
|
// create a vbox as layout container
|
||||||
|
VBox contenPane = new VBox()
|
||||||
|
|
||||||
|
// groovy maps for selecting the statistic numbers
|
||||||
|
def typeStats = [:]
|
||||||
|
def difficultyStats = [:]
|
||||||
|
def terrainStats = [:]
|
||||||
|
|
||||||
|
// iterate over all the caches and count the data
|
||||||
|
for (def cache in cacheList) {
|
||||||
|
incrementStats(typeStats, cache.type)
|
||||||
|
incrementStats(difficultyStats, cache.difficulty)
|
||||||
|
incrementStats(terrainStats, cache.terrain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create javafx chart
|
||||||
|
def typeData = FXCollections.observableArrayList()
|
||||||
|
typeStats.each() { key, value -> typeData.add(new Data(key as String, value as double)) }
|
||||||
|
def typeChart = new PieChart(typeData);
|
||||||
|
typeChart.setTitle("Number of cache types in list.");
|
||||||
|
|
||||||
|
// create javafx chart
|
||||||
|
def difficultyData = FXCollections.observableArrayList()
|
||||||
|
difficultyTerrainValues.each {
|
||||||
|
def value = difficultyStats[it]
|
||||||
|
if (value) difficultyData.add(new Data(it, value))
|
||||||
|
}
|
||||||
|
def difficultyChart = new PieChart(difficultyData);
|
||||||
|
difficultyChart.setTitle("Number of difficulties in list.");
|
||||||
|
|
||||||
|
// create javafx chart
|
||||||
|
def terrainData = FXCollections.observableArrayList()
|
||||||
|
difficultyTerrainValues.each {
|
||||||
|
def value = terrainStats[it]
|
||||||
|
if (value) terrainData.add(new Data(it, value))
|
||||||
|
}
|
||||||
|
def terrainChart = new PieChart(terrainData);
|
||||||
|
terrainChart.setTitle("Number of terrain in list.");
|
||||||
|
|
||||||
|
// add charts to layout container
|
||||||
|
contenPane.children.addAll(typeChart, difficultyChart, terrainChart)
|
||||||
|
|
||||||
|
// return the layout container
|
||||||
|
def scrollPane = new ScrollPane(contenPane)
|
||||||
|
scrollPane.minWidth = 600
|
||||||
|
scrollPane.prefWidth = 600
|
||||||
|
scrollPane.maxWidth = 600
|
||||||
|
scrollPane.minHeight = 450
|
||||||
|
scrollPane
|
||||||
|
}
|
||||||
|
|
||||||
|
private void incrementStats(map, key) {
|
||||||
|
map[key] = map[key] ? map[key] + 1 : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showDialog(header, content) {
|
||||||
|
Dialog dialog = new Dialog(null, name+" ("+version+")")
|
||||||
|
dialog.setMasthead(header)
|
||||||
|
dialog.setContent(content)
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,8 @@ package de.frosch95.geofrogger.application;
|
|||||||
|
|
||||||
import de.frosch95.geofrogger.gpx.GPXReader;
|
import de.frosch95.geofrogger.gpx.GPXReader;
|
||||||
import de.frosch95.geofrogger.gpx.GroundspeakGPXReader;
|
import de.frosch95.geofrogger.gpx.GroundspeakGPXReader;
|
||||||
|
import de.frosch95.geofrogger.plugins.PluginService;
|
||||||
|
import de.frosch95.geofrogger.plugins.PluginServiceImpl;
|
||||||
import de.frosch95.geofrogger.service.CacheService;
|
import de.frosch95.geofrogger.service.CacheService;
|
||||||
import de.frosch95.geofrogger.service.CacheServiceImpl;
|
import de.frosch95.geofrogger.service.CacheServiceImpl;
|
||||||
import de.frosch95.geofrogger.sql.DatabaseService;
|
import de.frosch95.geofrogger.sql.DatabaseService;
|
||||||
@@ -42,6 +44,7 @@ public class ServiceManager {
|
|||||||
private GPXReader gpxReader;
|
private GPXReader gpxReader;
|
||||||
private DatabaseService databaseService;
|
private DatabaseService databaseService;
|
||||||
private CacheService cacheService;
|
private CacheService cacheService;
|
||||||
|
private PluginService pluginService;
|
||||||
|
|
||||||
private ServiceManager() {
|
private ServiceManager() {
|
||||||
// private for singleton pattern
|
// private for singleton pattern
|
||||||
@@ -72,4 +75,11 @@ public class ServiceManager {
|
|||||||
return cacheService;
|
return cacheService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized PluginService getPluginService() {
|
||||||
|
if (pluginService == null) {
|
||||||
|
pluginService = new PluginServiceImpl();
|
||||||
|
}
|
||||||
|
return pluginService;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ import de.frosch95.geofrogger.application.ServiceManager;
|
|||||||
import de.frosch95.geofrogger.application.SessionContext;
|
import de.frosch95.geofrogger.application.SessionContext;
|
||||||
import de.frosch95.geofrogger.gpx.GPXReader;
|
import de.frosch95.geofrogger.gpx.GPXReader;
|
||||||
import de.frosch95.geofrogger.model.Cache;
|
import de.frosch95.geofrogger.model.Cache;
|
||||||
|
import de.frosch95.geofrogger.plugins.Plugin;
|
||||||
|
import de.frosch95.geofrogger.plugins.PluginService;
|
||||||
import de.frosch95.geofrogger.service.CacheService;
|
import de.frosch95.geofrogger.service.CacheService;
|
||||||
import de.frosch95.geofrogger.service.CacheSortField;
|
import de.frosch95.geofrogger.service.CacheSortField;
|
||||||
import de.frosch95.geofrogger.service.SortDirection;
|
import de.frosch95.geofrogger.service.SortDirection;
|
||||||
@@ -39,12 +41,10 @@ import javafx.beans.property.SimpleObjectProperty;
|
|||||||
import javafx.concurrent.Service;
|
import javafx.concurrent.Service;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
|
import javafx.event.EventHandler;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.control.ProgressBar;
|
|
||||||
import javafx.scene.control.ProgressIndicator;
|
|
||||||
import javafx.scene.control.TextArea;
|
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.controlsfx.dialog.Dialog;
|
import org.controlsfx.dialog.Dialog;
|
||||||
|
|
||||||
@@ -106,6 +106,7 @@ public class GeofroggerController implements Initializable {
|
|||||||
|
|
||||||
private final GPXReader gpxReader = ServiceManager.getInstance().getGPXReader();
|
private final GPXReader gpxReader = ServiceManager.getInstance().getGPXReader();
|
||||||
private final CacheService cacheService = ServiceManager.getInstance().getCacheService();
|
private final CacheService cacheService = ServiceManager.getInstance().getCacheService();
|
||||||
|
private final PluginService pluginService = ServiceManager.getInstance().getPluginService();
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label leftStatus;
|
private Label leftStatus;
|
||||||
@@ -113,6 +114,9 @@ public class GeofroggerController implements Initializable {
|
|||||||
@FXML
|
@FXML
|
||||||
private ProgressBar progress;
|
private ProgressBar progress;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Menu pluginsMenu;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the controller class.
|
* Initializes the controller class.
|
||||||
*
|
*
|
||||||
@@ -121,14 +125,16 @@ public class GeofroggerController implements Initializable {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL url, ResourceBundle rb) {
|
public void initialize(URL url, ResourceBundle rb) {
|
||||||
gpxReader.addListener((ProgressEvent event) -> {
|
|
||||||
updateStatus(event.getMessage(), event.getProgress());
|
|
||||||
});
|
|
||||||
|
|
||||||
cacheService.addListener((ProgressEvent event) -> {
|
List<Plugin> plugins = pluginService.getAllPlugins();
|
||||||
updateStatus(event.getMessage(), event.getProgress());
|
for (Plugin plugin: plugins) {
|
||||||
});
|
MenuItem menuItem = new MenuItem(plugin.getName()+" ("+plugin.getVersion()+")");
|
||||||
|
menuItem.setOnAction(actionEvent -> pluginService.executePlugin(plugin));
|
||||||
|
pluginsMenu.getItems().add(menuItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpxReader.addListener((ProgressEvent event) -> updateStatus(event.getMessage(), event.getProgress()));
|
||||||
|
cacheService.addListener((ProgressEvent event) -> updateStatus(event.getMessage(), event.getProgress()));
|
||||||
loadFromDBService.start();
|
loadFromDBService.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
<MenuItem mnemonicParsing="false" onAction="#exit" text="%menu.title.quit"/>
|
<MenuItem mnemonicParsing="false" onAction="#exit" text="%menu.title.quit"/>
|
||||||
</items>
|
</items>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
<Menu fx:id="pluginsMenu" mnemonicParsing="false" text="%menu.title.plugins"/>
|
||||||
<Menu mnemonicParsing="false" text="%menu.title.help">
|
<Menu mnemonicParsing="false" text="%menu.title.help">
|
||||||
<items>
|
<items>
|
||||||
<MenuItem mnemonicParsing="false" onAction="#showAboutDialog" text="%menu.title.about"/>
|
<MenuItem mnemonicParsing="false" onAction="#showAboutDialog" text="%menu.title.about"/>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ menu.title.file = Datei
|
|||||||
menu.title.quit = Beenden
|
menu.title.quit = Beenden
|
||||||
menu.title.help = Hilfe
|
menu.title.help = Hilfe
|
||||||
menu.title.about = \u00dcber GeoFroggerFX
|
menu.title.about = \u00dcber GeoFroggerFX
|
||||||
|
menu.title.plugins = Plugins
|
||||||
|
|
||||||
menu.title.sort = Sortieren
|
menu.title.sort = Sortieren
|
||||||
menu.title.filter = Filtern
|
menu.title.filter = Filtern
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ menu.title.file = File
|
|||||||
menu.title.quit = Quit
|
menu.title.quit = Quit
|
||||||
menu.title.help = Help
|
menu.title.help = Help
|
||||||
menu.title.about = About GeoFroggerFX
|
menu.title.about = About GeoFroggerFX
|
||||||
|
menu.title.plugins = Plugins
|
||||||
|
|
||||||
menu.title.sort = Sort
|
menu.title.sort = Sort
|
||||||
menu.title.filter = Filter
|
menu.title.filter = Filter
|
||||||
|
|||||||
30
src/de/frosch95/geofrogger/plugins/Plugin.java
Normal file
30
src/de/frosch95/geofrogger/plugins/Plugin.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package de.frosch95.geofrogger.plugins;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface defines the method a plugin has to provide to be called correctly
|
||||||
|
*
|
||||||
|
* @author abi
|
||||||
|
*/
|
||||||
|
public interface Plugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return name
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return version
|
||||||
|
*/
|
||||||
|
String getVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the main method of the plugin. All the logic is done in this method.
|
||||||
|
* Every run method will get a context map, with all the services inside,
|
||||||
|
* to use them.
|
||||||
|
* @param context services and data
|
||||||
|
*/
|
||||||
|
void run(Map context);
|
||||||
|
|
||||||
|
}
|
||||||
18
src/de/frosch95/geofrogger/plugins/PluginService.java
Normal file
18
src/de/frosch95/geofrogger/plugins/PluginService.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package de.frosch95.geofrogger.plugins;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: class description
|
||||||
|
*
|
||||||
|
* @author abi
|
||||||
|
*/
|
||||||
|
public interface PluginService {
|
||||||
|
|
||||||
|
List<Plugin> getAllPlugins();
|
||||||
|
|
||||||
|
void executePlugin(Plugin plugin);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
61
src/de/frosch95/geofrogger/plugins/PluginServiceImpl.java
Normal file
61
src/de/frosch95/geofrogger/plugins/PluginServiceImpl.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package de.frosch95.geofrogger.plugins;
|
||||||
|
|
||||||
|
import de.frosch95.geofrogger.application.ServiceManager;
|
||||||
|
import de.frosch95.geofrogger.application.SessionContext;
|
||||||
|
import groovy.lang.GroovyClassLoader;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: class description
|
||||||
|
*
|
||||||
|
* @author abi
|
||||||
|
*/
|
||||||
|
public class PluginServiceImpl implements PluginService {
|
||||||
|
|
||||||
|
private final GroovyClassLoader gcl = new GroovyClassLoader();
|
||||||
|
private final ServiceManager serviceManager = ServiceManager.getInstance();
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Plugin> getAllPlugins() {
|
||||||
|
|
||||||
|
List<Plugin> plugins = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
File file = new File("./plugins");
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new IllegalArgumentException("plugins folder does not exit");
|
||||||
|
}
|
||||||
|
|
||||||
|
File[] pluginFiles = file.listFiles((dir, name) -> name.endsWith("Plugin.groovy"));
|
||||||
|
for (File pluginFile: pluginFiles) {
|
||||||
|
Class clazz = gcl.parseClass(pluginFile);
|
||||||
|
for (Class interf: clazz.getInterfaces()) {
|
||||||
|
if (interf.equals(Plugin.class)) {
|
||||||
|
plugins.add((Plugin)clazz.newInstance());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException | InstantiationException | IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void executePlugin(final Plugin plugin) {
|
||||||
|
Map<String, Object> context = new HashMap<>();
|
||||||
|
context.put("sessionContext", SessionContext.getInstance());
|
||||||
|
context.put("cacheService", serviceManager.getCacheService());
|
||||||
|
plugin.run(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user