/* The MIT License (MIT)
*
* Copyright (c) 2015 Reinventing Geospatial, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.rgi.suite;
import com.rgi.suite.cli.HeadlessOptions;
import com.rgi.suite.cli.HeadlessRunner;
import com.rgi.suite.uielements.windows.PackagerWindow;
import com.rgi.suite.uielements.windows.TileReadersOptionWindow;
import com.rgi.suite.uielements.windows.TilerWindow;
import com.rgi.view.MapViewWindow;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import utility.PropertiesAction;
import utility.TileStoreUtility;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
/**
* Entry point for the program.
*
* @author Duff Means
* @author Steven D. Lander
*/
@SuppressWarnings({"OverlyComplexAnonymousInnerClass", "CloneableClassWithoutClone", "CloneableClassInSecureContext", "SerializableClassInSecureContext", "DeserializableClassInSecureContext", "SerializableHasSerializationMethods", "SerializableInnerClassWithNonSerializableOuterClass", "MagicNumber", "AnonymousInnerClassMayBeStatic"})
public final class GeoSuite
{
private static final String SETTINGS_FILE_NAME = "swagd.prefs";
private final Settings settings;
/**
* Code decision point for running in either GUI mode or headless (command-line) mode.
* <p>
* exit codes: 0 - exited normally
* 1 - cmd line exception, invalid arguments
* 2 - run time exception, see logs.
*
* @param args A string array of command line arguments.
*/
public static void main(final String[] args)
{
if(args != null && args.length > 0)
{
GeoSuite.runHeadless(args);
}
else
{
new GeoSuite();
}
}
private GeoSuite()
{
this.settings = new Settings(new File(Paths.get(System.getProperty("user.home"),
SETTINGS_FILE_NAME).toString()));
SwingUtilities.invokeLater(this::startGui);
}
@SuppressWarnings("deprecation")
private void startGui()
{
final JPanel contentPanel = new JPanel(new CardLayout());
final JPanel navPanel = new JPanel(new CardLayout());
final JFrame suiteWindow = new JFrame();
final Properties props = new Properties();
try(InputStream inputStream = ClassLoader.getSystemResourceAsStream("geosuite.properties"))
{
props.load(inputStream);
}
catch(final IllegalArgumentException | IOException exception)
{
JOptionPane.showMessageDialog(null, "SWAGD Suite", "Unable to load properties", JOptionPane.ERROR_MESSAGE);
System.out.println(exception.getMessage());
}
final Container contentPane = suiteWindow.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(contentPanel, BorderLayout.CENTER);
contentPane.add(navPanel, BorderLayout.SOUTH);
suiteWindow.setTitle("SWAGD Tiling and Packaging Suite");
suiteWindow.setSize(540, 240);
suiteWindow.setResizable(false);
//suiteWindow.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
suiteWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
suiteWindow.addWindowListener(new WindowAdapter()
{
@Override
public void windowClosing(final WindowEvent e)
{
final int option = JOptionPane.showConfirmDialog(suiteWindow, "Are you sure you want to exit?", "Confirm Exit", JOptionPane.YES_NO_OPTION);
if(option == JOptionPane.YES_OPTION)
{
suiteWindow.setVisible(false);
suiteWindow.dispose();
}
}
});
// main buttons
final JPanel mainButtonPanel = new JPanel(new GridBagLayout());
final GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1.0;
gbc.weighty = 1.0;
final JButton tileButton = new JButton(new PropertiesAction(props, "tile")
{
private static final long serialVersionUID = -3249428374853166484L;
@Override
public void actionPerformed(final ActionEvent e)
{
final JFrame frame = new TilerWindow(GeoSuite.this.getSettings());
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
tileButton.setHideActionText(true);
tileButton.setMargin(new Insets(0, 0, 0, 0));
final JButton gpkgButton = new JButton(new PropertiesAction(props, "gpkg")
{
private static final long serialVersionUID = -1836754318915912580L;
@Override
public void actionPerformed(final ActionEvent e)
{
final JFrame frame = new PackagerWindow(GeoSuite.this.getSettings());
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
gpkgButton.setHideActionText(true);
gpkgButton.setMargin(new Insets(0, 0, 0, 0));
final JButton viewButton = new JButton(new PropertiesAction(props, "view")
{
private static final long serialVersionUID = 1882624675173160883L;
private static final String LAST_LOCATION_SETTING_NAME = "ui.viewer.lastLocation";
@Override
public void actionPerformed(final ActionEvent e)
{
final String startDirectory = GeoSuite.this.getSettings()
.get(LAST_LOCATION_SETTING_NAME,
System.getProperty("user.home"));
final JFileChooser fileChooser = new JFileChooser(new File(startDirectory));
fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
fileChooser.setMultiSelectionEnabled(true);
fileChooser.addActionListener(chooseEvent -> {
if(JFileChooser.APPROVE_SELECTION.equals(chooseEvent.getActionCommand()))
{
final File[] files = fileChooser.getSelectedFiles();
if(files.length > 0)
{
GeoSuite.this.getSettings().set(LAST_LOCATION_SETTING_NAME, files[0].getParent());
GeoSuite.this.getSettings().save();
final TileReadersOptionWindow tileReadersOptionWindow = new TileReadersOptionWindow(TileStoreUtility.getTileStoreReaderAdapters(true,
files),
readers -> { final JFrame viewWindow = new MapViewWindow(readers);
viewWindow.setLocationRelativeTo(null);
viewWindow.setVisible(true);
});
if(tileReadersOptionWindow.needsInput())
{
tileReadersOptionWindow.setLocationRelativeTo(null);
tileReadersOptionWindow.setVisible(true);
}
else
{
tileReadersOptionWindow.execute();
}
}
}
});
fileChooser.showOpenDialog(suiteWindow);
}
});
viewButton.setHideActionText(true);
viewButton.setMargin(new Insets(0, 0, 0, 0));
mainButtonPanel.add(tileButton, gbc);
mainButtonPanel.add(gpkgButton, gbc);
mainButtonPanel.add(viewButton, gbc);
contentPanel.add(mainButtonPanel);
suiteWindow.setLocationRelativeTo(null);
suiteWindow.setVisible(true);
}
/**
* Parses command line arguments and launches the appropriate functionality
*
* @param args - cmd line argument string from main method.
*/
private static void runHeadless(final String[] args)
{
final Logger logger = Logger.getLogger("RGISuite.logger");
logger.setUseParentHandlers(false);
logger.setLevel(Level.ALL);
final ConsoleHandler handler = new ConsoleHandler();
final Formatter formatter = new Formatter()
{
@Override
public String format(final LogRecord record)
{
return String.valueOf(new Date()) + ' ' + record.getLevel() + ' ' + record.getMessage() +
System.getProperty("line.separator");
}
};
handler.setFormatter(formatter);
logger.addHandler(handler);
final HeadlessOptions opts = new HeadlessOptions(logger);
final CmdLineParser parser = new CmdLineParser(opts);
try
{
parser.parseArgument(args);
if(opts.isValid())
{
final ExecutorService executor = Executors.newFixedThreadPool(1); //only 1 background thread supported
final Runnable runner = new HeadlessRunner(opts, logger);
logger.log(Level.INFO, "Begining tile generation:");
executor.execute(runner);
}
}
catch(final RuntimeException error)
{
logger.log(Level.SEVERE, error.getMessage());
}
catch(final CmdLineException cmdError)
{
logger.log(Level.SEVERE, "Error Parsing Arguments." + cmdError.getMessage());
parser.printUsage(System.out);
}
}
public Settings getSettings()
{
return this.settings;
}
}