package com.socrata.datasync.ui;
import com.socrata.datasync.PublishMethod;
import com.socrata.datasync.Utils;
import com.socrata.datasync.config.userpreferences.UserPreferencesJava;
import com.socrata.datasync.job.GISJob;
import com.socrata.datasync.job.JobStatus;
import com.socrata.datasync.model.ControlFileModel;
import com.socrata.datasync.model.DatasetModel;
import com.socrata.datasync.validation.GISJobValidity;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
public class GISJobTab implements JobTab {
private static final int DATASET_ID_TEXTFIELD_WIDTH = 160;
private static final int JOB_COMMAND_TEXTFIELD_WIDTH = 212;
private static final int JOB_FILE_TEXTFIELD_WIDTH = 263;
private static final int JOB_TEXTFIELD_HEIGHT = 26;
private static final int JOB_FIELD_VGAP = 5;
private static final FlowLayout FLOW_RIGHT = new FlowLayout(FlowLayout.LEFT, 0, JOB_FIELD_VGAP);
private static final String DEFAULT_RUN_JOB_COMMAND = "(Generates when job is saved)";
private static final String BROWSE_BUTTON_TEXT = "Browse...";
private static final String JOB_FILE_NAME = "Socrata GIS Job";
public static final String JOB_FILE_EXTENSION = "gij";
private static final int HELP_ICON_TOP_PADDING = 12;
private static final String FILE_TO_PUBLISH_TIP_TEXT = "GeoJSON, kml/kmz, or zipped shape file containing the data to be published";
private static final String DATASET_ID_TIP_TEXT = "<html><body style='width: 300px'>The identifier in the form of xxxx-xxxx (e.g. n38h-y5wp) " +
"of the Socrata dataset where the data will be published</body></html>";
private static final String RUN_COMMAND_TIP_TEXT = "<html><body style='width: 300px'>After saving the job this field will be populated with a command-line command that can be used to run the job." +
" This command can be input into tools such as the Windows Task Scheduler or ETL tools to run the job automatically.</body></html>";
public static final String COPY_TO_CLIPBOARD_BUTTON_TEXT = "Copy to clipboard";
private String jobFileLocation;
//Rest of the code assumes that this is never null. Adding to avoid null pointer exception when job initialization fails.
private JLabel jobTabTitleLabel = new JLabel("Untitled GIS Job");
private JTextField datasetIDTextField;
private JTextField fileToPublishTextField;
private JTextField runCommandTextField;
private ControlFileModel controlFileModel;
private DatasetModel datasetModel;
private JFrame mainFrame;
private JPanel jobPanel;
// build Container with all tab components populated with given job data
public GISJobTab(GISJob job, JFrame containingFrame) {
mainFrame = containingFrame;
// build tab panel form
jobPanel = new JPanel(new GridLayout(5,2));
addFileToPublishFieldToJobPanel();
addDatasetIdFieldToJobPanel();
addRunCommandFieldToJobPanel();
loadJobDataIntoUIFields(job);
}
private void addRunCommandFieldToJobPanel() {
jobPanel.add(UIUtility.generateLabelWithHelpBubble(
"Step 3 - Copy command for later (optional)", RUN_COMMAND_TIP_TEXT, HELP_ICON_TOP_PADDING));
JPanel runCommandTextFieldContainer = new JPanel(FLOW_RIGHT);
runCommandTextField = new JTextField(DEFAULT_RUN_JOB_COMMAND);
runCommandTextField.setPreferredSize(new Dimension(
JOB_COMMAND_TEXTFIELD_WIDTH, JOB_TEXTFIELD_HEIGHT));
runCommandTextField.setEditable(false);
runCommandTextField.addMouseListener(new JobCommandTextFieldListener());
runCommandTextFieldContainer.add(runCommandTextField);
JButton copyJobCommandButton = new JButton(COPY_TO_CLIPBOARD_BUTTON_TEXT);
copyJobCommandButton.addActionListener(new CopyJobCommandListener());
runCommandTextFieldContainer.add(copyJobCommandButton);
jobPanel.add(runCommandTextFieldContainer);
}
private void addDatasetIdFieldToJobPanel() {
jobPanel.add(UIUtility.generateLabelWithHelpBubble(
"Step 2 - Enter Dataset ID to update", DATASET_ID_TIP_TEXT, HELP_ICON_TOP_PADDING));
JPanel datasetIDTextFieldContainer = new JPanel(FLOW_RIGHT);
datasetIDTextField = new JTextField();
datasetIDTextField.setPreferredSize(new Dimension(
DATASET_ID_TEXTFIELD_WIDTH, JOB_TEXTFIELD_HEIGHT));
RegenerateControlFileListener regenerateListener = new RegenerateControlFileListener();
datasetIDTextField.addActionListener(regenerateListener);
datasetIDTextField.addFocusListener(regenerateListener);
datasetIDTextFieldContainer.add(datasetIDTextField);
jobPanel.add(datasetIDTextFieldContainer);
}
private void addFileToPublishFieldToJobPanel() {
jobPanel.add(
UIUtility.generateLabelWithHelpBubble("Step 1 - Select file to publish", FILE_TO_PUBLISH_TIP_TEXT, HELP_ICON_TOP_PADDING));
JPanel fileSelectorContainer = new JPanel(FLOW_RIGHT);
fileToPublishTextField = new JTextField();
fileToPublishTextField.setPreferredSize(new Dimension(
JOB_FILE_TEXTFIELD_WIDTH, JOB_TEXTFIELD_HEIGHT));
fileSelectorContainer.add(fileToPublishTextField);
JFileChooser fileToPublishChooser = new JFileChooser();
JButton openButton = new JButton(BROWSE_BUTTON_TEXT);
FileToPublishSelectorListener chooserListener = new FileToPublishSelectorListener(
fileToPublishChooser, fileToPublishTextField);
openButton.addActionListener(chooserListener);
fileSelectorContainer.add(openButton);
RegenerateControlFileListener regenerateListener = new RegenerateControlFileListener();
fileToPublishTextField.addActionListener(regenerateListener);
fileToPublishTextField.addFocusListener(regenerateListener);
jobPanel.add(fileSelectorContainer);
}
private void loadJobDataIntoUIFields(GISJob job) {
try {
datasetIDTextField.setText(job.getDatasetID());
fileToPublishTextField.setText(job.getFileToPublish());
jobFileLocation = job.getPathToSavedFile();
// if this is an existing job (meaning the job was opened from a file)
// then populate the scheduler command textfield
if (!jobFileLocation.equals("")) {
runCommandTextField.setText(Utils.getRunJobCommand(jobFileLocation));
}
jobTabTitleLabel = new JLabel(job.getJobFilename());
} catch (Exception e) {
JOptionPane.showMessageDialog(mainFrame, "Error: " + e.getMessage());
}
}
public JPanel getTabPanel() {
return jobPanel;
}
public JobStatus runJobNow() {
GISJob jobToRun = new GISJob();
jobToRun.setDatasetID(datasetIDTextField.getText());
jobToRun.setFileToPublish(fileToPublishTextField.getText());
jobToRun.setPublishMethod(PublishMethod.replace);
jobToRun.setUserAgentClient();
//MAGIC
return jobToRun.run();
}
public void saveJob() {
// Save job data
GISJob newGISJob = new GISJob();
newGISJob.setDatasetID(datasetIDTextField.getText());
newGISJob.setFileToPublish(fileToPublishTextField.getText());
newGISJob.setPublishMethod(PublishMethod.replace);
newGISJob.setPathToSavedFile(jobFileLocation);
GISJobValidity.validateLayerMapping(newGISJob);
// TODO If an existing file was selected WARN user of overwriting
// if first time saving this job: Open dialog box to select "Save as..." location
// otherwise save to existing file
boolean updateJobCommandTextField = false;
String selectedJobFileLocation = jobFileLocation;
if (selectedJobFileLocation.equals("")) {
JFileChooser savedJobFileChooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter(
JOB_FILE_NAME + " (*." + JOB_FILE_EXTENSION + ")", JOB_FILE_EXTENSION);
savedJobFileChooser.setFileFilter(filter);
if (savedJobFileChooser.showSaveDialog(mainFrame) == JFileChooser.APPROVE_OPTION) {
File file = savedJobFileChooser.getSelectedFile();
selectedJobFileLocation = file.getAbsolutePath();
if (!selectedJobFileLocation.endsWith("." + JOB_FILE_EXTENSION)) {
selectedJobFileLocation += "." + JOB_FILE_EXTENSION;
}
jobFileLocation = selectedJobFileLocation;
newGISJob.setPathToSavedFile(selectedJobFileLocation);
jobTabTitleLabel.setText(newGISJob.getJobFilename());
updateJobCommandTextField = true;
}
}
saveJobAsFile(newGISJob, updateJobCommandTextField, selectedJobFileLocation);
}
private void saveJobAsFile(GISJob newGISJob,
boolean updateJobCommandTextField,
String selectedJobFileLocation) {
try {
newGISJob.writeToFile(selectedJobFileLocation);
// Update job tab title label
jobTabTitleLabel.setText(Utils.getFilename(selectedJobFileLocation));
// Update the textfield with new command
if(updateJobCommandTextField) {
String runJobCommand = Utils.getRunJobCommand(
newGISJob.getPathToSavedFile());
runCommandTextField.setText(runJobCommand);
}
} catch (IOException e) {
JOptionPane.showMessageDialog(mainFrame,
"Error saving " + selectedJobFileLocation + ": " + e.getMessage());
}
}
public JLabel getJobTabTitleLabel() {
return jobTabTitleLabel;
}
public String getJobFileLocation() {
return jobFileLocation;
}
private class FileToPublishSelectorListener implements ActionListener {
JFileChooser fileChooser;
JTextField filePathTextField;
public FileToPublishSelectorListener(JFileChooser chooser, JTextField textField) {
fileChooser = chooser;
filePathTextField = textField;
fileChooser.setFileFilter(
UIUtility.getFileChooserFilter(GISJobValidity.allowedGeoFileToPublishExtensions));
}
public void actionPerformed(ActionEvent e) {
if (fileChooser.showOpenDialog(mainFrame) == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
filePathTextField.setText(file.getAbsolutePath());
}
// If open command was cancelled by user: do nothing
}
}
private class RegenerateControlFileListener extends FocusAdapter implements ActionListener {
@Override
public void focusLost(FocusEvent e){
if (!e.isTemporary()) {
setRegenerateControlFile();
}
}
public void actionPerformed(ActionEvent e) {
setRegenerateControlFile();
}
//Set the right variables so that the control file is regenerated when going to the mapping dialog
//TODO: Consider paying attention to these at run job time as well
private void setRegenerateControlFile(){
controlFileModel = null;
datasetModel = null;
}
}
private class JobCommandTextFieldListener implements MouseListener {
@Override
public void mouseClicked(MouseEvent e) {
JTextField jobCommandTextField = (JTextField) e.getSource();
jobCommandTextField.selectAll();
}
@Override
public void mouseExited(MouseEvent e) { }
@Override
public void mouseEntered(MouseEvent e) { }
@Override
public void mousePressed(MouseEvent e) { }
@Override
public void mouseReleased(MouseEvent e) { }
}
private class CopyJobCommandListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
String runJobCommand = runCommandTextField.getText();
UIUtility.copyToClipboard(runJobCommand);
}
}
}