package edu.kit.pse.ws2013.routekit.views;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import javax.swing.Box;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.filechooser.FileFilter;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import edu.kit.pse.ws2013.routekit.controllers.ManagementActions;
import edu.kit.pse.ws2013.routekit.controllers.MapManagerController;
import edu.kit.pse.ws2013.routekit.map.StreetMap;
import edu.kit.pse.ws2013.routekit.models.ProfileMapCombination;
import edu.kit.pse.ws2013.routekit.models.ProgressReporter;
import edu.kit.pse.ws2013.routekit.profiles.Profile;
import edu.kit.pse.ws2013.routekit.util.TimeUtil;
/**
* Displays the window of the map management on the screen.
*/
public class MapManagerView extends JDialog {
private static final long serialVersionUID = 1L;
private JComboBox<Object> mapname;
private DefaultListModel<String> listenModell;
private JList<String> profile;
private JFileChooser fileChooser = new JFileChooser();
private JButton importButton;
private JButton update;
private JButton delete;
private int listenerCheck = 0;
private MapManagerController mmc;
private final KeyListener escEnterListener = new KeyAdapter() {
@Override
public void keyPressed(java.awt.event.KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_ENTER:
ok();
break;
case KeyEvent.VK_ESCAPE:
dispose();
break;
}
};
};
/**
* A constructor that creates a new MapManagerView.
* <p>
* This constructor does <i>not</i> call {@link #setVisible(boolean)
* setVisible(true)}, i. e. it doesn’t block.
*/
public MapManagerView(Window parent, MapManagerController mmc,
StreetMap currentMap, Set<StreetMap> maps,
Set<Profile> currentMapProfiles) {
super(parent, "Kartenverwaltung", ModalityType.APPLICATION_MODAL);
this.mmc = mmc;
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setSize(600, 400);
setLocationRelativeTo(getParent());
setResizable(false);
fileChooser.setFileFilter(new FileFilter() {
@Override
public boolean accept(File f) {
return f.isDirectory() || f.getName().endsWith(".osm");
}
@Override
public String getDescription() {
return "OSM (*.osm)";
}
});
JPanel contentPane = new JPanel(new BorderLayout());
JPanel north = initNorthPane();
JPanel center = initCenterPane();
JPanel south = initSouthPane();
contentPane.add(north, BorderLayout.NORTH);
contentPane.add(south, BorderLayout.SOUTH);
contentPane.add(center, BorderLayout.CENTER);
setContentPane(contentPane);
addKeyListener(escEnterListener);
contentPane.addKeyListener(escEnterListener);
setAvailableMaps(maps);
setCurrentMap(currentMap, currentMapProfiles);
}
private JPanel initNorthPane() {
JPanel north = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
north.setBackground(Color.WHITE);
north.addKeyListener(escEnterListener);
JLabel map = new JLabel("Karte auswählen:");
mapname = new JComboBox<>();
mapname.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (listenerCheck == 0) {
if (mapname.getSelectedItem() == null) {
return;
} else {
mmc.changeMap((String) mapname.getSelectedItem());
}
}
}
});
mapname.setMinimumSize(new Dimension(250, 26));
mapname.setPreferredSize(new Dimension(250, 26));
mapname.addKeyListener(escEnterListener);
north.add(map);
north.add(mapname);
return north;
}
private JPanel initCenterPane() {
JPanel center = new JPanel(new BorderLayout(10, 10));
center.setBackground(Color.WHITE);
JPanel buttons = initButtonsPane();
JPanel mapProfile = initMapProfilePane();
mapProfile.addKeyListener(escEnterListener);
center.add(buttons, BorderLayout.NORTH);
center.add(mapProfile, BorderLayout.CENTER);
JPanel space = new JPanel();
space.setBackground(Color.WHITE);
center.add(space, BorderLayout.WEST);
return center;
}
private JPanel initSouthPane() {
JPanel south = new JPanel(new FlowLayout(FlowLayout.RIGHT));
south.setBackground(Color.WHITE);
JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ok();
}
});
south.add(okButton);
JButton cancel = new JButton("Abbrechen");
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
south.add(cancel);
return south;
}
private JPanel initButtonsPane() {
JPanel buttons = new JPanel(new FlowLayout(FlowLayout.LEFT));
buttons.setBackground(Color.WHITE);
importButton = new JButton("Importieren");
importButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JButton pathButton = new JButton("Suche...");
final JTextField path = new JTextField(20);
pathButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fileChooser.showDialog(MapManagerView.this,
"Importieren");
if (fileChooser.getSelectedFile() == null) {
return;
}
path.setText(fileChooser.getSelectedFile()
.getAbsolutePath());
}
});
JTextField name = new JTextField(20);
JPanel myPanel = new JPanel();
myPanel.add(pathButton);
myPanel.add(new JLabel("Pfad:"));
myPanel.add(path);
myPanel.add(Box.createHorizontalStrut(15));
myPanel.add(new JLabel("Name der Karte:"));
myPanel.add(name);
do {
int result = JOptionPane.showConfirmDialog(
MapManagerView.this, myPanel,
"Eingabe Pfad und Name",
JOptionPane.OK_CANCEL_OPTION);
if (result != JOptionPane.OK_OPTION
|| path.getText().isEmpty()
|| name.getText().isEmpty()) {
return;
}
try {
File newfile = new File(path.getText());
mmc.importMap(name.getText(), newfile);
break;
} catch (IllegalArgumentException ex) {
JOptionPane
.showMessageDialog(
MapManagerView.this,
"Ungültiger Name – bitte geben Sie einen anderen Namen ein.",
"Fehler", JOptionPane.ERROR_MESSAGE);
continue;
} catch (FileNotFoundException ex) {
JOptionPane
.showMessageDialog(
MapManagerView.this,
"Datei existiert nicht – bitte geben Sie einen gültigen Dateinamen ein.",
"Fehler", JOptionPane.ERROR_MESSAGE);
continue;
}
} while (true);
}
});
buttons.add(importButton);
update = new JButton("Aktualisieren");
buttons.add(update);
update.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JButton pathUpdateButton = new JButton("Suche...");
final JTextField pathUpdate = new JTextField(20);
pathUpdateButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fileChooser.showDialog(MapManagerView.this,
"Aktualisieren");
if (fileChooser.getSelectedFile() == null) {
return;
}
pathUpdate.setText(fileChooser.getSelectedFile()
.getAbsolutePath());
}
});
JPanel myPanel = new JPanel();
myPanel.add(pathUpdateButton);
myPanel.add(new JLabel("Pfad:"));
myPanel.add(pathUpdate);
int result = JOptionPane.showConfirmDialog(MapManagerView.this,
myPanel, "Eingabe Pfad", JOptionPane.OK_CANCEL_OPTION);
if (result == JOptionPane.OK_OPTION) {
if (!pathUpdate.getText().equals("")) {
File newfile = new File(pathUpdate.getText());
try {
mmc.importMap((String) mapname.getSelectedItem(),
newfile);
} catch (FileNotFoundException e1) {
JOptionPane
.showMessageDialog(
MapManagerView.this,
"Datei existiert nicht – bitte geben Sie einen gültigen Dateinamen ein.",
"Fehler", JOptionPane.ERROR_MESSAGE);
}
}
}
}
});
delete = new JButton("Löschen");
delete.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
mmc.deleteCurrentMap();
}
});
buttons.add(delete);
return buttons;
}
private JPanel initMapProfilePane() {
JPanel mapProfile = new JPanel(new BorderLayout(10, 10));
mapProfile.setBackground(Color.WHITE);
JPanel addDelete = initAddDelete();
listenModell = new DefaultListModel<String>();
profile = new JList<String>(listenModell);
profile.setBackground(Color.lightGray);
profile.addKeyListener(escEnterListener);
mapProfile.add(new JLabel("Profile für diese Karte:"),
BorderLayout.NORTH);
mapProfile.add(addDelete, BorderLayout.EAST);
mapProfile.add(new JScrollPane(profile), BorderLayout.CENTER);
return mapProfile;
}
private JPanel initAddDelete() {
JPanel addDelete = new JPanel(new FlowLayout(FlowLayout.LEFT));
addDelete.setBackground(Color.WHITE);
JButton addProfile = new JButton("Hinzufügen");
addProfile.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
mmc.addProfile();
}
});
addDelete.add(addProfile);
JButton remove = new JButton("Entfernen");
remove.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (profile.getSelectedValue() != null) {
mmc.removeProfile(profile.getSelectedValue());
}
}
});
addDelete.add(remove);
addDelete.setPreferredSize(new Dimension(130, 200));
return addDelete;
}
/**
* Sets the maps that can be currently selected.
*
* @param maps
* The available maps.
*/
public void setAvailableMaps(Set<StreetMap> maps) {
listenerCheck++;
mapname.removeAllItems();
List<StreetMap> sortedMaps = new ArrayList<>(maps);
Collections.sort(sortedMaps, new Comparator<StreetMap>() {
@Override
public int compare(StreetMap o1, StreetMap o2) {
return o1.getName().compareTo(o2.getName());
}
});
for (StreetMap m : sortedMaps) {
mapname.addItem(m.getName());
}
listenerCheck--;
}
/**
* Sets the current map to the specified map, updates the list of profiles
* for the selected map, enable / disable the „Import“- und
* „Löschen“-Buttons depending on whether it is a default map or not.
*
* @param map
* The new map.
* @param profiles
* The profiles for the new map.
*/
public void setCurrentMap(StreetMap map, Set<Profile> profiles) {
listenerCheck++;
listenModell.clear();
List<Profile> sortedProfiles = new ArrayList<>(profiles);
Collections.sort(sortedProfiles, new Comparator<Profile>() {
@Override
public int compare(Profile o1, Profile o2) {
return o1.getName().compareTo(o2.getName());
}
});
for (Profile p : sortedProfiles) {
listenModell.addElement(p.getName());
}
mapname.setSelectedItem(map.getName());
if (map.isDefault()) {
delete.setEnabled(false);
update.setEnabled(false);
} else {
delete.setEnabled(true);
update.setEnabled(true);
}
listenerCheck--;
}
private class Dialog extends JDialog {
private static final long serialVersionUID = 1L;
private JButton ok;
public boolean clickedOk = false;
public Dialog(Window parent) {
super(parent, "Kartenverwaltung", ModalityType.APPLICATION_MODAL);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLocationRelativeTo(getParent());
setResizable(false);
JPanel contentPane = new JPanel(new BorderLayout());
JPanel center = initDialogCenterPane();
JPanel south = initDialogSouthPane();
if (center == null) {
// no changes, don’t show the dialog
clickedOk = true;
dispose();
return;
}
contentPane.add(center, BorderLayout.CENTER);
contentPane.add(south, BorderLayout.SOUTH);
setContentPane(contentPane);
pack();
new Thread("MapManagerView Button Timeout Thread") {
{
setDaemon(true);
}
@Override
public void run() {
final int timeout;
if (java.lang.management.ManagementFactory
.getRuntimeMXBean().getInputArguments().toString()
.indexOf("jdwp") >= 0) {
timeout = 0;
} else {
timeout = 5;
}
try {
for (int sek = timeout; sek >= 1; sek--) {
ok.setText("OK (" + sek + ")");
Thread.sleep(1000);
}
} catch (InterruptedException a) {
}
ok.setText("OK");
ok.setEnabled(true);
}
}.start();
setLocationRelativeTo(parent);
setVisible(true);
}
private JPanel initDialogSouthPane() {
JPanel buttons = new JPanel(new FlowLayout(FlowLayout.CENTER, 10,
10));
buttons.setBackground(Color.WHITE);
ok = new JButton("OK");
ok.setEnabled(false);
ok.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
clickedOk = true;
dispose();
}
});
JButton cancel = new JButton("Abbrechen");
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
buttons.add(ok);
buttons.add(cancel);
return buttons;
}
private JPanel initDialogCenterPane() {
JPanel information = new JPanel();
information.setBackground(Color.WHITE);
JTextPane textPane = new JTextPane();
StringBuilder text = new StringBuilder(
"Sie haben die folgenden Operationen ausgewählt:\n");
ManagementActions diff = mmc.getChanges();
int i = 0;
Set<StreetMap> deletedMaps = diff.getDeletedMaps();
Set<? extends StreetMap> newOrUpdatedMaps = diff
.getNewOrUpdatedMaps();
Set<ProfileMapCombination> deletedPrecalculations = diff
.getDeletedPrecalculations();
Set<ProfileMapCombination> newPrecalculations = diff
.getNewPrecalculations();
if (!deletedMaps.isEmpty()) {
text.append(++i);
text.append(". Löschen der folgenden Karten:\n");
for (StreetMap map : deletedMaps) {
text.append(" • ");
text.append(map.getName());
text.append('\n');
}
}
if (!newOrUpdatedMaps.isEmpty()) {
text.append(++i);
text.append(". Hinzufügen oder Aktualisieren der folgenden Karten:\n");
for (StreetMap map : newOrUpdatedMaps) {
text.append(" • ");
text.append(map.getName());
text.append('\n');
}
}
if (!deletedPrecalculations.isEmpty()) {
text.append(++i);
text.append(". Löschen der folgenden Vorberechnungen:\n");
int interval = 0;
for (ProfileMapCombination precalculation : deletedPrecalculations) {
text.append(" • ");
text.append(precalculation.getStreetMap().getName());
text.append(" + ");
text.append(precalculation.getProfile().getName());
text.append('\n');
interval += precalculation.getCalculationTime();
}
if (interval > 0) {
text.append(" (diese Vorberechnungen benötigten insgesamt");
TimeUtil.timeSpanString(text, interval);
text.append(")\n");
}
}
if (!newPrecalculations.isEmpty()) {
text.append(++i);
text.append(". Neu Berechnen der folgenden Vorberechnungen:\n");
for (ProfileMapCombination precalculation : newPrecalculations) {
text.append(" • ");
text.append(precalculation.getStreetMap().getName());
text.append(" + ");
text.append(precalculation.getProfile().getName());
text.append('\n');
}
}
if (i == 0) {
// diff is completely empty, dispose immediately
return null;
}
text.append("Sind Sie sicher, dass Sie diese Operationen durchführen wollen?");
textPane.setText(text.toString());
Font displayFont = new Font("Serif", Font.ROMAN_BASELINE, 14);
StyledDocument doc = textPane.getStyledDocument();
SimpleAttributeSet center = new SimpleAttributeSet();
StyleConstants.setAlignment(center, StyleConstants.ALIGN_LEFT);
doc.setParagraphAttributes(0, doc.getLength(), center, false);
textPane.setEditable(false);
textPane.setFont(displayFont);
information.add(textPane);
return information;
}
}
private void ok() {
if (new Dialog(MapManagerView.this).clickedOk) {
ProgressDialog p = new ProgressDialog(MapManagerView.this, true);
ProgressReporter reporter = new ProgressReporter();
reporter.addProgressListener(p);
reporter.pushTask("Speichere Änderungen");
mmc.saveAllChanges(reporter);
p.setVisible(true);
MapManagerView.this.dispose();
}
}
}