/*
* This file is part of JGrasstools (http://www.jgrasstools.org)
* (C) HydroloGIS - www.hydrologis.com
*
* JGrasstools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jgrasstools.geopaparazzi.simpleserver;
import static org.jgrasstools.gears.io.geopaparazzi.geopap4.TableDescriptions.TABLE_GPSLOGS;
import static org.jgrasstools.gears.io.geopaparazzi.geopap4.TableDescriptions.TABLE_GPSLOG_DATA;
import static org.jgrasstools.gears.io.geopaparazzi.geopap4.TableDescriptions.TABLE_GPSLOG_PROPERTIES;
import static org.jgrasstools.gears.io.geopaparazzi.geopap4.TableDescriptions.TABLE_METADATA;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.EventListener;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.JTextPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.event.EventListenerList;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jgrasstools.dbs.compat.ASpatialDb;
import org.jgrasstools.dbs.compat.IJGTConnection;
import org.jgrasstools.dbs.compat.IJGTResultSet;
import org.jgrasstools.dbs.compat.IJGTStatement;
import org.jgrasstools.dbs.spatialite.jgt.SqliteDb;
import org.jgrasstools.gears.io.geopaparazzi.GeopaparazziUtilities;
import org.jgrasstools.gears.io.geopaparazzi.geopap4.DaoGpsLog;
import org.jgrasstools.gears.io.geopaparazzi.geopap4.DaoGpsLog.GpsLog;
import org.jgrasstools.gears.io.geopaparazzi.geopap4.DaoGpsLog.GpsPoint;
import org.jgrasstools.gears.io.geopaparazzi.geopap4.DaoImages;
import org.jgrasstools.gears.io.geopaparazzi.geopap4.DaoNotes;
import org.jgrasstools.gears.io.geopaparazzi.geopap4.Image;
import org.jgrasstools.gears.io.geopaparazzi.geopap4.Note;
import org.jgrasstools.gears.io.geopaparazzi.geopap4.TableDescriptions.GpsLogsDataTableFields;
import org.jgrasstools.gears.io.geopaparazzi.geopap4.TableDescriptions.GpsLogsPropertiesTableFields;
import org.jgrasstools.gears.io.geopaparazzi.geopap4.TableDescriptions.GpsLogsTableFields;
import org.jgrasstools.gears.io.geopaparazzi.geopap4.TableDescriptions.MetadataTableFields;
import org.jgrasstools.gears.io.geopaparazzi.geopap4.ETimeUtilities;
import org.jgrasstools.gears.libs.logging.JGTLogger;
import org.jgrasstools.gears.libs.monitor.IJGTProgressMonitor;
import org.jgrasstools.gears.libs.monitor.LogProgressMonitor;
import org.jgrasstools.gears.modules.v.smoothing.FeatureSlidingAverage;
import org.jgrasstools.gears.utils.chart.Scatter;
import org.jgrasstools.gears.utils.geometry.GeometryUtilities;
import org.jgrasstools.geopaparazzi.GeopaparazziServer;
import org.jgrasstools.gui.utils.GuiBridgeHandler;
import org.jgrasstools.gui.utils.GuiUtilities;
import org.jgrasstools.gui.utils.GuiUtilities.IOnCloseListener;
import org.jgrasstools.gui.utils.ImageCache;
import org.jgrasstools.nww.gui.NwwPanel;
import org.jgrasstools.nww.utils.NwwUtilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.LineString;
import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.geom.Sector;
import gov.nasa.worldwind.layers.RenderableLayer;
import gov.nasa.worldwind.render.BasicShapeAttributes;
import gov.nasa.worldwind.render.Material;
import gov.nasa.worldwind.render.Path;
import gov.nasa.worldwind.render.PointPlacemark;
import gov.nasa.worldwind.render.PointPlacemarkAttributes;
/**
* The spatialtoolbox view controller.
*
* @author Andrea Antonello (www.hydrologis.com)
*
*/
public abstract class GeopaparazziController extends GeopaparazziView implements IOnCloseListener {
private static final String RED_HEXA = "#FF0000";
private static final Logger logger = LoggerFactory.getLogger(GeopaparazziController.class);
private static final long serialVersionUID = 1L;
protected HashMap<String, String> prefsMap = new HashMap<>();
protected GuiBridgeHandler guiBridge;
protected IJGTProgressMonitor pm = new LogProgressMonitor();
private List<ProjectInfo> projectInfos = new ArrayList<>();
protected ProjectInfo currentSelectedProject = null;
protected Image currentSelectedImage = null;
protected GpsLog currentSelectedGpsLog = null;
protected Note currentSelectedNote = null;
private Dimension preferredButtonSize = new Dimension(30, 30);
private JTextPane _infoArea;
private RenderableLayer geopapDataLayer;
private NwwPanel wwjPanel;
private ProjectInfo currentLoadedProject;
private GeopaparazziServer geopaparazziServer;
@SuppressWarnings({"unchecked", "rawtypes"})
public GeopaparazziController( GuiBridgeHandler guiBridge ) {
this.guiBridge = guiBridge;
setPreferredSize(new Dimension(900, 600));
HashMap<String, String> prefsMapTmp = guiBridge.getGeopaparazziProjectViewerPreferencesMap();
if (prefsMapTmp != null) {
prefsMap = (HashMap) prefsMapTmp;
}
init();
}
@SuppressWarnings({"serial"})
private void init() {
_infoArea = new JTextPane();
// _infoArea.setDocument(new SqlDocument());
_infoArea.setContentType("text/html");
_infoArea.setEditable(false);
_infoScroll.setViewportView(_infoArea);
// _infoScroll.setMinimumSize(new Dimension(10, 200));
_chartHolder.setLayout(new BorderLayout());
_loadFolderButton.setIcon(ImageCache.getInstance().getImage(ImageCache.REFRESH));
_loadFolderButton.setText("");
_loadFolderButton.setPreferredSize(preferredButtonSize);
_loadFolderButton.addActionListener(e -> {
final File geopaparazziFolder = new File(_projectsFolderTextfield.getText());
if (!geopaparazziFolder.exists()) {
GuiUtilities.showWarningMessage(this, null, "The projects folder doesn't exist.");
return;
}
File[] projectFiles = GeopaparazziUtilities.getGeopaparazziFiles(geopaparazziFolder);
try {
projectInfos = readProjectInfos(projectFiles);
layoutTree(projectInfos, false);
_filterTextfield.setText("");
} catch (Exception e1) {
logger.error("error", e1);
}
});
_projectsFolderBrowseButton.setPreferredSize(preferredButtonSize);
_projectsFolderBrowseButton.addActionListener(e -> {
File[] openFiles = guiBridge.showOpenDirectoryDialog("Open projects folder", GuiUtilities.getLastFile());
if (openFiles != null && openFiles.length > 0) {
try {
GuiUtilities.setLastPath(openFiles[0].getAbsolutePath());
} catch (Exception e1) {
logger.error("ERROR", e1);
}
} else {
return;
}
_projectsFolderTextfield.setText(openFiles[0].getAbsolutePath());
});
String lastSavedPath = prefsMap.get(GuiBridgeHandler.LAST_GP_PROJECTS_PATH);
_projectsFolderTextfield.setText(lastSavedPath);
_filterTextfield.addKeyListener(new KeyAdapter(){
@Override
public void keyReleased( KeyEvent e ) {
String filterText = _filterTextfield.getText().toLowerCase();
final List<ProjectInfo> filtered = new ArrayList<ProjectInfo>();
if (filterText == null) {
filtered.addAll(projectInfos);
} else {
for( ProjectInfo projectInfo : projectInfos ) {
if (projectInfo.fileName.toLowerCase().contains(filterText)
|| projectInfo.metadata.toLowerCase().contains(filterText)) {
filtered.add(projectInfo);
}
}
}
layoutTree(filtered, false);
}
});
_httpServerButton.setIcon(ImageCache.getInstance().getImage(ImageCache.BROWSER));
_httpServerButton.setText("");
_httpServerButton.setPreferredSize(preferredButtonSize);
_httpServerButton.setToolTipText("Start/stop a simple http server to connect Geopaparazzi to.");
_httpServerButton.addActionListener(e -> {
if (_httpServerButton.isSelected()) {
String folderPath = _projectsFolderTextfield.getText();
File folderFile = new File(folderPath);
if (folderFile.exists() && folderFile.isDirectory()) {
int port = 8080;
try {
String portChosen = JOptionPane.showInputDialog("Server port to use", "8080");
if (portChosen == null) {
_httpServerButton.setSelected(false);
return;
}
port = Integer.parseInt(portChosen);
} catch (NumberFormatException e1) {
_httpServerButton.setSelected(false);
GuiUtilities.showWarningMessage(this, null, "The port has to be a valid integer.");
return;
}
final int fPort = port;
new Thread(new Runnable(){
public void run() {
// TODO enable layers download
try {
geopaparazziServer = new GeopaparazziServer(fPort, folderFile);
geopaparazziServer.start();
} catch (Exception e) {
JGTLogger.logError(GeopaparazziController.this, e);
}
}
}).start();
} else {
_httpServerButton.setSelected(false);
GuiUtilities.showWarningMessage(this, null, "The supplied projects folder doesn't exist.");
}
} else {
// stop server
if (geopaparazziServer != null) {
geopaparazziServer.stop();
geopaparazziServer = null;
}
}
});
addComponentListener(new ComponentListener(){
public void componentShown( ComponentEvent e ) {
}
public void componentResized( ComponentEvent e ) {
}
public void componentMoved( ComponentEvent e ) {
}
public void componentHidden( ComponentEvent e ) {
onClose();
}
});
try {
_databaseTreeView.setMinimumSize(new Dimension(300, 200));
addJtreeDragNDrop();
addJtreeContextMenu();
_databaseTree.setRootVisible(false);
_databaseTree.setCellRenderer(new DefaultTreeCellRenderer(){
@Override
public java.awt.Component getTreeCellRendererComponent( JTree tree, Object value, boolean selected,
boolean expanded, boolean leaf, int row, boolean hasFocus ) {
super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
if (value instanceof ProjectInfo) {
setIcon(ImageCache.getInstance().getImage(ImageCache.DATABASE));
} else if (value instanceof Image) {
setIcon(ImageCache.getInstance().getImage(ImageCache.DBIMAGE));
} else if (value instanceof GpsLog) {
setIcon(ImageCache.getInstance().getImage(ImageCache.GEOM_LINE));
} else if (value instanceof Note) {
setIcon(ImageCache.getInstance().getImage(ImageCache.NOTE));
}
return this;
}
});
_databaseTree.addTreeSelectionListener(new TreeSelectionListener(){
public void valueChanged( TreeSelectionEvent evt ) {
TreePath[] paths = evt.getPaths();
currentSelectedProject = null;
currentSelectedImage = null;
currentSelectedNote = null;
currentSelectedGpsLog = null;
_chartHolder.removeAll();
if (paths.length > 0) {
Object selectedItem = paths[0].getLastPathComponent();
if (selectedItem instanceof ProjectInfo) {
currentSelectedProject = (ProjectInfo) selectedItem;
selectProjectInfo(currentSelectedProject);
logger.debug("Selected project: " + currentSelectedProject.fileName);
}
if (selectedItem instanceof Image) {
currentSelectedImage = (Image) selectedItem;
currentSelectedProject = getProjectForImage(currentSelectedImage);
selectImage(currentSelectedImage);
logger.debug("Selected image: " + currentSelectedImage.getName() + " of project "
+ currentSelectedProject.fileName);
}
if (selectedItem instanceof GpsLog) {
currentSelectedGpsLog = (GpsLog) selectedItem;
currentSelectedProject = getProjectForGpsLog(currentSelectedGpsLog);
selectGpsLog(currentSelectedGpsLog);
logger.debug("Selected gpslog: " + currentSelectedGpsLog.text + " of project "
+ currentSelectedProject.fileName);
}
if (selectedItem instanceof Note) {
currentSelectedNote = (Note) selectedItem;
currentSelectedProject = getProjectForNote(currentSelectedNote);
selectNote(currentSelectedNote);
logger.debug("Selected note: " + currentSelectedNote.simpleText + " of project "
+ currentSelectedProject.fileName);
}
}
}
});
_databaseTree.setVisible(false);
} catch (Exception e1) {
JGTLogger.logError(this, "Error", e1);
}
layoutTree(null, false);
Component wwjPanelComponent = null;
try {
wwjPanelComponent = NwwPanel.createNwwPanel(true);
} catch (UnsatisfiedLinkError e1) {
// ignore
}
if (wwjPanelComponent instanceof NwwPanel) {
_nwwHolder.setLayout(new BorderLayout());
_nwwHolder.add(wwjPanelComponent, BorderLayout.CENTER);
wwjPanel = (NwwPanel) wwjPanelComponent;
wwjPanel.addOsmLayer();
geopapDataLayer = new RenderableLayer();
wwjPanel.addLayer(geopapDataLayer);
} else {
_nwwHolderFrame.setVisible(false);
_chartHolderFrame.setVisible(false);
setPreferredSize(new Dimension(400, 600));
}
}
private List<ProjectInfo> readProjectInfos( File[] projectFiles ) throws Exception {
List<ProjectInfo> infoList = new ArrayList<ProjectInfo>();
for( File geopapDatabaseFile : projectFiles ) {
try (SqliteDb db = new SqliteDb()) {
db.open(geopapDatabaseFile.getAbsolutePath());
IJGTConnection connection = db.getConnection();
String projectInfo = GeopaparazziUtilities.getProjectInfo(connection, true);
ProjectInfo info = new ProjectInfo();
info.databaseFile = geopapDatabaseFile;
info.fileName = geopapDatabaseFile.getName();
info.metadata = projectInfo;
List<org.jgrasstools.gears.io.geopaparazzi.geopap4.Image> imagesList = DaoImages.getImagesList(connection);
info.images = imagesList.toArray(new org.jgrasstools.gears.io.geopaparazzi.geopap4.Image[0]);
List<Note> notesList = DaoNotes.getNotesList(connection, null);
info.notes = notesList;
List<GpsLog> logsList = DaoGpsLog.getLogsList(connection);
info.logs = logsList;
infoList.add(info);
}
}
return infoList;
}
private ProjectInfo getProjectForImage( Image currentSelectedImage ) {
boolean doBreak = false;
ProjectInfo selectedProject = null;
for( ProjectInfo projectInfo : projectInfos ) {
for( org.jgrasstools.gears.io.geopaparazzi.geopap4.Image tmpImage : projectInfo.images ) {
if (tmpImage.equals(currentSelectedImage)) {
selectedProject = projectInfo;
doBreak = true;
break;
}
}
if (doBreak) {
break;
}
}
return selectedProject;
}
private ProjectInfo getProjectForGpsLog( GpsLog currentSelectedGpsLog ) {
ProjectInfo selectedProject = null;
for( ProjectInfo projectInfo : projectInfos ) {
if (projectInfo.logs.contains(currentSelectedGpsLog)) {
selectedProject = projectInfo;
break;
}
}
return selectedProject;
}
private ProjectInfo getProjectForNote( Note currentSelectedNote ) {
ProjectInfo selectedProject = null;
for( ProjectInfo projectInfo : projectInfos ) {
if (projectInfo.notes.contains(currentSelectedNote)) {
selectedProject = projectInfo;
break;
}
}
return selectedProject;
}
private void addJtreeDragNDrop() {
_databaseTree.setDragEnabled(true);
_databaseTree.setTransferHandler(new TransferHandler(null){
public int getSourceActions( JComponent c ) {
return COPY;
}
protected Transferable createTransferable( JComponent c ) {
if (c instanceof JTree) {
if (currentSelectedImage != null) {
return new StringSelection(currentSelectedImage.getName());
} else if (currentSelectedGpsLog != null) {
return new StringSelection(currentSelectedGpsLog.text);
}
}
return new StringSelection("");
}
});
}
private void addJtreeContextMenu() {
JPopupMenu popupMenu = new JPopupMenu();
popupMenu.setBorder(new BevelBorder(BevelBorder.RAISED));
popupMenu.addPopupMenuListener(new PopupMenuListener(){
@Override
public void popupMenuWillBecomeVisible( PopupMenuEvent e ) {
if (currentSelectedImage != null) {
logger.debug("PopupMenuEvent on image: " + currentSelectedImage.getName());
List<Action> tableActions = makeImageAction(currentSelectedImage);
if (tableActions != null)
for( Action action : tableActions ) {
if (action != null) {
JMenuItem item = new JMenuItem(action);
popupMenu.add(item);
item.setHorizontalTextPosition(JMenuItem.RIGHT);
} else {
popupMenu.add(new JSeparator());
}
}
} else if (currentSelectedGpsLog != null) {
logger.debug("PopupMenuEvent on log: " + currentSelectedGpsLog.text);
List<Action> logActions = makeGpsLogActions(currentSelectedGpsLog);
if (logActions != null)
for( Action action : logActions ) {
if (action != null) {
JMenuItem item = new JMenuItem(action);
popupMenu.add(item);
item.setHorizontalTextPosition(JMenuItem.RIGHT);
} else {
popupMenu.add(new JSeparator());
}
}
} else if (currentSelectedNote != null) {
logger.debug("PopupMenuEvent on note: " + currentSelectedNote.simpleText);
List<Action> notesActions = makeNotesActions(currentSelectedNote);
if (notesActions != null)
for( Action action : notesActions ) {
if (action != null) {
JMenuItem item = new JMenuItem(action);
popupMenu.add(item);
item.setHorizontalTextPosition(JMenuItem.RIGHT);
} else {
popupMenu.add(new JSeparator());
}
}
} else if (currentSelectedProject != null) {
logger.debug("PopupMenuEvent on project: " + currentSelectedProject.fileName);
List<Action> dbActions = makeProjectAction(currentSelectedProject);
if (dbActions != null)
for( Action action : dbActions ) {
if (action != null) {
JMenuItem item = new JMenuItem(action);
popupMenu.add(item);
item.setHorizontalTextPosition(JMenuItem.RIGHT);
} else {
popupMenu.add(new JSeparator());
}
}
}
logger.debug("PopupMenuEvent with no available object to load menu from");
}
@Override
public void popupMenuWillBecomeInvisible( PopupMenuEvent e ) {
popupMenu.removeAll();
}
@Override
public void popupMenuCanceled( PopupMenuEvent e ) {
popupMenu.removeAll();
}
});
_databaseTree.addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked( MouseEvent e ) {
if (SwingUtilities.isRightMouseButton(e)) {
int row = _databaseTree.getClosestRowForLocation(e.getX(), e.getY());
_databaseTree.setSelectionRow(row);
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
});
}
private void layoutTree( List<ProjectInfo> projectInfos, boolean expandNodes ) {
if (projectInfos != null) {
_databaseTree.setVisible(true);
} else {
projectInfos = new ArrayList<>();
_databaseTree.setVisible(false);
}
ObjectTreeModel model = new ObjectTreeModel();
model.setRoot(projectInfos);
_databaseTree.setModel(model);
if (expandNodes) {
_databaseTree.expandRow(0);
// _databaseTree.expandRow(1);
}
// expandAllNodes(_databaseTree, 0, 2);
}
private void expandAllNodes( JTree tree, int startingIndex, int rowCount ) {
for( int i = startingIndex; i < rowCount; ++i ) {
tree.expandRow(i);
}
if (tree.getRowCount() != rowCount) {
expandAllNodes(tree, rowCount, tree.getRowCount());
}
}
class ObjectTreeModel implements TreeModel {
private List<ProjectInfo> root;
private EventListenerList listenerList = new EventListenerList();
/**
* Constructs an empty tree.
*/
public ObjectTreeModel() {
root = null;
}
/**
* Sets the root to a given variable.
* @param v the variable that is being described by this tree
*/
public void setRoot( List<ProjectInfo> v ) {
List<ProjectInfo> oldRoot = v;
root = v;
fireTreeStructureChanged(oldRoot);
}
public Object getRoot() {
return root;
}
@SuppressWarnings("rawtypes")
public int getChildCount( Object parent ) {
if (parent instanceof ProjectInfo) {
ProjectInfo projectInfo = (ProjectInfo) parent;
int childCount = projectInfo.images.length + projectInfo.logs.size() + projectInfo.notes.size();
return childCount;
} else if (parent instanceof Image) {
return 0;
} else if (parent instanceof GpsLog) {
return 0;
} else if (parent instanceof Note) {
return 0;
} else if (parent instanceof List) {
List list = (List) parent;
return list.size();
}
return 0;
}
@SuppressWarnings("rawtypes")
public Object getChild( Object parent, int index ) {
if (parent instanceof ProjectInfo) {
ProjectInfo projectInfo = (ProjectInfo) parent;
int imagesCount = projectInfo.images.length;
int logsCount = projectInfo.logs.size();
if (index > imagesCount + logsCount - 1) {
return projectInfo.notes.get(index - imagesCount - logsCount);
} else if (index > imagesCount - 1) {
return projectInfo.logs.get(index - imagesCount);
} else {
return projectInfo.images[index];
}
} else if (parent instanceof List) {
List list = (List) parent;
Object item = list.get(index);
return item;
}
return null;
}
public int getIndexOfChild( Object parent, Object child ) {
int n = getChildCount(parent);
for( int i = 0; i < n; i++ )
if (getChild(parent, i).equals(child))
return i;
return -1;
}
public boolean isLeaf( Object node ) {
return getChildCount(node) == 0;
}
public void valueForPathChanged( TreePath path, Object newValue ) {
}
public void addTreeModelListener( TreeModelListener l ) {
listenerList.add(TreeModelListener.class, l);
}
public void removeTreeModelListener( TreeModelListener l ) {
listenerList.remove(TreeModelListener.class, l);
}
protected void fireTreeStructureChanged( Object oldRoot ) {
TreeModelEvent event = new TreeModelEvent(this, new Object[]{oldRoot});
EventListener[] listeners = listenerList.getListeners(TreeModelListener.class);
for( int i = 0; i < listeners.length; i++ )
((TreeModelListener) listeners[i]).treeStructureChanged(event);
}
}
public JComponent asJComponent() {
return this;
}
public void onClose() {
try {
String lastPath = _projectsFolderTextfield.getText();
File file = new File(lastPath);
if (file.exists() && file.isDirectory()) {
prefsMap.put(GuiBridgeHandler.LAST_GP_PROJECTS_PATH, lastPath);
guiBridge.setGeopaparazziProjectViewerPreferencesMap(prefsMap);
}
// stop server
if (geopaparazziServer != null) {
geopaparazziServer.stop();
}
} catch (Exception e) {
logger.error("Error", e);
}
}
protected void setDbTreeTitle( String title ) {
Border databaseTreeViewBorder = _databaseTreeView.getBorder();
if (databaseTreeViewBorder instanceof TitledBorder) {
TitledBorder tBorder = (TitledBorder) databaseTreeViewBorder;
tBorder.setTitle(title);
}
}
private void selectProjectInfo( ProjectInfo selectedProject ) {
try {
String titleName = selectedProject.fileName;
titleName = titleName.replace('_', ' ').replaceFirst("\\.gpap", "");
String text = titleName + "<br/><br/>" + selectedProject.metadata;
_infoArea.setText(text);
} catch (Exception e) {
logger.error("error", e);
}
}
private void selectImage( org.jgrasstools.gears.io.geopaparazzi.geopap4.Image selectedImage ) {
try {
checkLoadedProject();
String dateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(selectedImage.getTs()));
String picInfo = "<b>Image:</b> " + GeopaparazziUtilities.escapeHTML(selectedImage.getName()) + "<br/>" //
+ "<b>Timestamp:</b> " + dateTimeString + "<br/>" //
+ "<b>Azimuth:</b> " + (int) selectedImage.getAzim() + " deg<br/>" //
+ "<b>Altim:</b> " + (int) selectedImage.getAltim() + " m<br/>";
_infoArea.setText(picInfo);
if (wwjPanel != null)
wwjPanel.goTo(selectedImage.getLon(), selectedImage.getLat(), 1000.0, null, false);
} catch (Exception e) {
logger.error("error", e);
setNoProjectLabel();
}
}
private void checkLoadedProject() throws Exception {
if (currentLoadedProject == null || currentLoadedProject != currentSelectedProject) {
loadProjectData(currentSelectedProject, false);
}
}
private void selectNote( Note selectedNote ) {
try {
checkLoadedProject();
String dateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(selectedNote.timeStamp));
String picInfo = "<b>Text:</b> " + GeopaparazziUtilities.escapeHTML(selectedNote.simpleText) + "<br/>" //
+ "<b>Description:</b> " + GeopaparazziUtilities.escapeHTML(selectedNote.description) + "<br/>" //
+ "<b>Timestamp:</b> " + dateTimeString + "<br/>" //
+ "<b>Altim:</b> " + (int) selectedNote.altim + " m<br/>";
_infoArea.setText(picInfo);
if (wwjPanel != null)
wwjPanel.goTo(selectedNote.lon, selectedNote.lat, 1000.0, null, false);
} catch (Exception e) {
logger.error("error", e);
setNoProjectLabel();
}
}
private void selectGpsLog( GpsLog selectedLog ) {
try {
checkLoadedProject();
String startDateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(selectedLog.startTime));
String endDateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(selectedLog.endTime));
String picInfo = "<b>Gps log:</b> " + GeopaparazziUtilities.escapeHTML(selectedLog.text) + "<br/>" //
+ "<b>Start time:</b> " + startDateTimeString + "<br/>" //
+ "<b>End time:</b> " + endDateTimeString + "<br/>";
_infoArea.setText(picInfo);
loadGpsLogChart(selectedLog, currentSelectedProject.databaseFile);
Envelope env = null;
for( GpsPoint gpsPoint : selectedLog.points ) {
if (env == null) {
env = new Envelope(new Coordinate(gpsPoint.lon, gpsPoint.lat));
} else {
env.expandToInclude(gpsPoint.lon, gpsPoint.lat);
}
}
env.expandBy(0.01);
Sector sector = NwwUtilities.envelope2Sector(new ReferencedEnvelope(env, NwwUtilities.GPS_CRS));
if (wwjPanel != null)
wwjPanel.goTo(sector, false);
} catch (Exception e) {
logger.error("error", e);
setNoProjectLabel();
}
}
private void setNoProjectLabel() {
_infoArea.setText("<h1>No project selected</h1>");
// Label noModuleLabel = new Label(projectViewComposite, SWT.NONE);
// noModuleLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
// noModuleLabel.setData(RWT.MARKUP_ENABLED, Boolean.TRUE);
// noModuleLabel.setText("<span style='font:bold 26px Arial;'>" + NO_MODULE_SELECTED +
// "</span>");
// return noModuleLabel;
}
private void loadGpsLogChart( GpsLog log, File dbFile ) throws Exception {
try (SqliteDb db = new SqliteDb()) {
db.open(dbFile.getAbsolutePath());
IJGTConnection connection = db.getConnection();
log.points.clear();
DaoGpsLog.collectDataForLog(connection, log);
String logName = log.text;
int size = log.points.size();
List<Coordinate> coords = new ArrayList<>();
double runningDistance = 0;
for( int i = 0; i < size - 1; i++ ) {
GpsPoint p1 = log.points.get(i);
GpsPoint p2 = log.points.get(i + 1);
double lon1 = p1.lon;
double lat1 = p1.lat;
double altim1 = p1.altim;
double lon2 = p2.lon;
double lat2 = p2.lat;
double altim2 = p2.altim;
double distance = NwwUtilities.computeDistance(lat1, lon1, lat2, lon2);
runningDistance += distance;
if (i == 0) {
coords.add(new Coordinate(0.0, altim1));
}
coords.add(new Coordinate(runningDistance, altim2));
}
LineString lineString = GeometryUtilities.gf().createLineString(coords.toArray(new Coordinate[0]));
int lookAhead = 20;
if (lookAhead > coords.size()) {
lookAhead = 3;
}
double slide = 1;
FeatureSlidingAverage fsaElev = new FeatureSlidingAverage(lineString);
List<Coordinate> smoothedElev = fsaElev.smooth(lookAhead, false, slide);
if (smoothedElev == null) {
smoothedElev = coords;
}
double[] xProfile = new double[smoothedElev.size()];
double[] yProfile = new double[smoothedElev.size()];
for( int i = 0; i < xProfile.length; i++ ) {
Coordinate c = smoothedElev.get(i);
xProfile[i] = c.x;
yProfile[i] = c.y;
}
Scatter scatterProfile = new Scatter("Profile " + logName);
scatterProfile.addSeries("profile", xProfile, yProfile);
scatterProfile.setShowLines(true);
String colorQuery = "select " //
+ GpsLogsPropertiesTableFields.COLUMN_PROPERTIES_COLOR.getFieldName() + " from " + TABLE_GPSLOG_PROPERTIES
+ " where " + //
GpsLogsPropertiesTableFields.COLUMN_LOGID.getFieldName() + " = " + log.id;
String colorStr = RED_HEXA;
try (IJGTStatement newStatement = connection.createStatement();
IJGTResultSet result = newStatement.executeQuery(colorQuery);) {
newStatement.setQueryTimeout(30);
if (result.next()) {
colorStr = result.getString(1);
if (colorStr.equalsIgnoreCase("red")) {
colorStr = RED_HEXA;
}
}
if (colorStr == null || colorStr.length() == 0) {
colorStr = RED_HEXA;
}
}
Color color = Color.RED;
try {
color = Color.decode(colorStr);
} catch (Exception e) {
// ignore logger.error("Could not convert color: " + colorStr, e);
}
scatterProfile.setColors(new Color[]{color});
scatterProfile.setXLabel("progressive distance [m]");
scatterProfile.setYLabel("elevation [m]");
JFreeChart chart = scatterProfile.getChart();
ChartPanel chartPanel = new ChartPanel(chart, true);
_chartHolder.add(chartPanel, BorderLayout.CENTER);
}
}
/**
* Extract data from the db and add them to the map view.
*
* @param projectTemplate
* @return
* @throws Exception
*/
public void loadProjectData( ProjectInfo currentSelectedProject, boolean zoomTo ) throws Exception {
if (geopapDataLayer != null)
geopapDataLayer.removeAllRenderables();
Envelope bounds = new Envelope();
File dbFile = currentSelectedProject.databaseFile;
try (Connection connection = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath())) {
// NOTES
List<String[]> noteDataList = GeopaparazziUtilities.getNotesText(connection);
StringBuilder sb = new StringBuilder();
sb.append("\n\n// GP NOTES\n");
int index = 0;
PointPlacemarkAttributes notesAttributes = new PointPlacemarkAttributes();
// notesAttributes.setLabelMaterial(mFillMaterial);
// notesAttributes.setLineMaterial(mFillMaterial);
// notesAttributes.setUsePointAsDefaultImage(true);
notesAttributes.setImage(ImageCache.getInstance().getBufferedImage(ImageCache.NOTE));
notesAttributes.setLabelMaterial(new Material(Color.BLACK));
// notesAttributes.setScale(mMarkerSize);
for( String[] noteData : noteDataList ) {
// [lon, lat, altim, dateTimeString, text, descr]
double lon = Double.parseDouble(noteData[0]);
double lat = Double.parseDouble(noteData[1]);
String altim = noteData[2];
String date = noteData[3];
String text = noteData[4];
String descr = noteData[5];
PointPlacemark marker = new PointPlacemark(Position.fromDegrees(lat, lon, 0));
marker.setAltitudeMode(WorldWind.CLAMP_TO_GROUND);
marker.setLabelText(text + " (" + date + ")");
marker.setAttributes(notesAttributes);
if (geopapDataLayer != null)
geopapDataLayer.addRenderable(marker);
bounds.expandToInclude(lon, lat);
}
/*
* IMAGES
*/
PointPlacemarkAttributes imageAttributes = new PointPlacemarkAttributes();
imageAttributes.setImage(ImageCache.getInstance().getBufferedImage(ImageCache.DBIMAGE));
imageAttributes.setLabelMaterial(new Material(Color.GRAY));
for( org.jgrasstools.gears.io.geopaparazzi.geopap4.Image image : currentSelectedProject.images ) {
double lon = image.getLon();
double lat = image.getLat();
PointPlacemark marker = new PointPlacemark(Position.fromDegrees(lat, lon, 0));
marker.setAltitudeMode(WorldWind.CLAMP_TO_GROUND);
marker.setLabelText(image.getName());
marker.setAttributes(imageAttributes);
if (geopapDataLayer != null)
geopapDataLayer.addRenderable(marker);
bounds.expandToInclude(lon, lat);
}
try (Statement statement = connection.createStatement()) {
statement.setQueryTimeout(30); // set timeout to 30 sec.
String sql = "select " + //
GpsLogsTableFields.COLUMN_ID.getFieldName() + "," + //
GpsLogsTableFields.COLUMN_LOG_STARTTS.getFieldName() + "," + //
GpsLogsTableFields.COLUMN_LOG_ENDTS.getFieldName() + "," + //
GpsLogsTableFields.COLUMN_LOG_TEXT.getFieldName() + //
" from " + TABLE_GPSLOGS; //
boolean useGpsElev = _useGpsElevationsCheckbox.isSelected();
int altitudeMode = WorldWind.CLAMP_TO_GROUND;
if (useGpsElev) {
altitudeMode = WorldWind.ABSOLUTE;
}
// first get the logs
ResultSet rs = statement.executeQuery(sql);
while( rs.next() ) {
long id = rs.getLong(1);
long startDateTime = rs.getLong(2);
String startDateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(startDateTime));
long endDateTime = rs.getLong(3);
String endDateTimeString = ETimeUtilities.INSTANCE.TIME_FORMATTER_LOCAL.format(new Date(endDateTime));
String text = rs.getString(4);
// points
String query = "select " //
+ GpsLogsDataTableFields.COLUMN_DATA_LAT.getFieldName() + ","
+ GpsLogsDataTableFields.COLUMN_DATA_LON.getFieldName() + ","
+ GpsLogsDataTableFields.COLUMN_DATA_ALTIM.getFieldName() + ","
+ GpsLogsDataTableFields.COLUMN_DATA_TS.getFieldName()//
+ " from " + TABLE_GPSLOG_DATA + " where " + //
GpsLogsDataTableFields.COLUMN_LOGID.getFieldName() + " = " + id + " order by "
+ GpsLogsDataTableFields.COLUMN_DATA_TS.getFieldName();
List<Position> verticesList = new ArrayList<>();
try (Statement newStatement = connection.createStatement()) {
newStatement.setQueryTimeout(30);
ResultSet result = newStatement.executeQuery(query);
while( result.next() ) {
double lat = result.getDouble(1);
double lon = result.getDouble(2);
double elev = 0.0;
if (useGpsElev)
elev = result.getDouble(3);
Position pos = Position.fromDegrees(lat, lon, elev);
verticesList.add(pos);
bounds.expandToInclude(lon, lat);
}
}
// color
String colorQuery = "select " //
+ GpsLogsPropertiesTableFields.COLUMN_PROPERTIES_COLOR.getFieldName() + ","
+ GpsLogsPropertiesTableFields.COLUMN_PROPERTIES_WIDTH.getFieldName() + " from "
+ TABLE_GPSLOG_PROPERTIES + " where " + //
GpsLogsPropertiesTableFields.COLUMN_LOGID.getFieldName() + " = " + id;
String colorStr = RED_HEXA;
int lineWidth = 3;
try (Statement newStatement = connection.createStatement()) {
newStatement.setQueryTimeout(30);
ResultSet result = newStatement.executeQuery(colorQuery);
if (result.next()) {
colorStr = result.getString(1);
lineWidth = result.getInt(2);
if (colorStr.equalsIgnoreCase("red")) {
colorStr = RED_HEXA;
}
}
if (colorStr == null || colorStr.length() == 0) {
colorStr = RED_HEXA;
}
}
Color color = Color.RED;
try {
color = Color.decode(colorStr);
} catch (Exception e) {
// ignore logger.error("Could not convert color: " + colorStr, e);
}
BasicShapeAttributes lineAttributes = new BasicShapeAttributes();
lineAttributes.setOutlineMaterial(new Material(color));
lineAttributes.setOutlineWidth(lineWidth);
Path path = new Path(verticesList);
path.setAltitudeMode(altitudeMode);
path.setFollowTerrain(true);
path.setAttributes(lineAttributes);
if (geopapDataLayer != null)
geopapDataLayer.addRenderable(path);
}
}
}
if (zoomTo) {
bounds.expandBy(0.001);
Sector sector = NwwUtilities.envelope2Sector(new ReferencedEnvelope(bounds, NwwUtilities.GPS_CRS));
if (wwjPanel != null)
wwjPanel.goTo(sector, false);
}
currentLoadedProject = currentSelectedProject;
}
protected void editProjectData( ProjectInfo project ) throws Exception {
LinkedHashMap<String, String> metadataMap = new LinkedHashMap<>();
try (SqliteDb db = new SqliteDb()) {
db.open(currentSelectedProject.databaseFile.getAbsolutePath());
IJGTConnection connection = db.getConnection();
String sql = "select " + MetadataTableFields.COLUMN_KEY.getFieldName() + ", " + //
MetadataTableFields.COLUMN_VALUE.getFieldName() + " from " + TABLE_METADATA;
try (IJGTStatement statement = connection.createStatement(); IJGTResultSet rs = statement.executeQuery(sql);) {
statement.setQueryTimeout(30); // set timeout to 30 sec.
while( rs.next() ) {
String key = rs.getString(MetadataTableFields.COLUMN_KEY.getFieldName());
String value = rs.getString(MetadataTableFields.COLUMN_VALUE.getFieldName());
if (!key.endsWith("ts")) {
// timestamps can't be changed
metadataMap.put(key, value);
}
}
}
String title = "Edit Project Info";
String[] labels = metadataMap.keySet().toArray(new String[0]);
String[] defaultValues = metadataMap.values().toArray(new String[0]);
String[] result = GuiUtilities.showMultiInputDialog(this, title, labels, defaultValues, null);
if (result != null) {
try (IJGTStatement statement = connection.createStatement();) {
statement.setQueryTimeout(30); // set timeout to 30 sec.
for( int i = 0; i < labels.length; i++ ) {
String key = labels[i];
String textData = result[i];
if (textData == null) {
textData = "";
}
textData = ASpatialDb.escapeSql(textData);
String query = "update " + TABLE_METADATA + " set value='" + textData + "' where key='" + key + "';";
statement.executeUpdate(query);
}
}
String projectInfo = GeopaparazziUtilities.getProjectInfo(connection, true);
currentSelectedProject.metadata = projectInfo;
selectProjectInfo(currentSelectedProject);
}
}
}
protected abstract List<Action> makeGpsLogActions( final GpsLog selectedLog );
protected abstract List<Action> makeNotesActions( final Note selectedNote );
protected abstract List<Action> makeProjectAction( final ProjectInfo project );
protected abstract List<Action> makeImageAction( final Image selectedImage );
}