package uk.co.bytemark.vm.enigma.inquisition.gui.editor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import org.jdom.DocType;
import org.jdom.Document;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import uk.co.bytemark.vm.enigma.inquisition.gui.images.Icons;
import uk.co.bytemark.vm.enigma.inquisition.gui.misc.QuizConfig;
import uk.co.bytemark.vm.enigma.inquisition.gui.quiz.QuizFrame;
import uk.co.bytemark.vm.enigma.inquisition.gui.quizchooser.ReturnCallback;
import uk.co.bytemark.vm.enigma.inquisition.gui.quizchooser.SuffixFileFilter;
import uk.co.bytemark.vm.enigma.inquisition.misc.Constants;
import uk.co.bytemark.vm.enigma.inquisition.questions.QuestionSet;
import uk.co.bytemark.vm.enigma.inquisition.questions.QuestionSetManager;
import uk.co.bytemark.vm.enigma.inquisition.questions.xml.XmlQuestionSetParser;
import uk.co.bytemark.vm.enigma.inquisition.quiz.QuizState;
public class QuestionEditor extends JFrame implements DirtyingActionListener {
private static final String NO_FILE_NAME = null;
private static final QuestionSet NO_QUESTION_SET = null;
private String fileName = NO_FILE_NAME;
private QuestionSet baseQuestionSet = NO_QUESTION_SET;
private final QuestionEditorMainPanel questionEditorMainPanel;
public QuestionEditor() {
if (Icons.FAVICON.isAvailable())
setIconImage(Icons.FAVICON.getImage());
questionEditorMainPanel = new QuestionEditorMainPanel();
questionEditorMainPanel.setDirtyingActionListener(this);
add(questionEditorMainPanel);
setUpMenu();
newQuestionSet();
setTitleBar();
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
performExitProtocol();
}
});
}
private void setTitleBar() {
String title = "Inquisition Question Editor: ";
if (fileName == NO_FILE_NAME)
title += "(No filename)";
else
title += fileName;
if (isDirty())
title += " [Unsaved]";
setTitle(title);
}
private boolean isDirty() {
return !getQuestionSet().equals(baseQuestionSet);
}
private void setUpMenu() {
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem newMenuItem = new JMenuItem("New");
newMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
boolean proceed = performSaveProtocolIfNecessary();
if (proceed) {
newQuestionSet();
setTitleBar();
}
}
});
fileMenu.add(newMenuItem);
JMenuItem openMenuItem = new JMenuItem("Open...");
openMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
boolean proceed = performSaveProtocolIfNecessary();
if (proceed) {
QuestionSet questionSet = openQuestionSet();
if (questionSet != NO_QUESTION_SET) {
questionEditorMainPanel.setQuestionSet(questionSet);
}
}
setTitleBar();
}
});
fileMenu.add(openMenuItem);
JMenuItem saveMenuItem = new JMenuItem("Save");
saveMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (fileName == NO_FILE_NAME) {
doSaveAs();
} else {
doSave(fileName);
}
setTitleBar();
}
});
fileMenu.add(saveMenuItem);
JMenuItem saveAsMenuItem = new JMenuItem("Save as...");
saveAsMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
doSaveAs();
setTitleBar();
}
});
fileMenu.add(saveAsMenuItem);
JMenuItem exitMenuItem = new JMenuItem("Exit");
exitMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
performExitProtocol();
}
});
fileMenu.add(exitMenuItem);
menuBar.add(fileMenu);
JMenu questionsMenu = new JMenu("Questions");
JMenuItem runQuizItem = new JMenuItem("Start quiz on these questions");
runQuizItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
runQuiz();
}
});
questionsMenu.add(runQuizItem);
menuBar.add(questionsMenu);
setJMenuBar(menuBar);
}
private void runQuiz() {
QuestionSet questionSet = getQuestionSet();
QuizState quizState = new QuizState(questionSet, QuizConfig.createWithTimer(false, true, questionSet
.getRecommendedTimeForAllQuestions()));
QuizFrame quizFrame = new QuizFrame(quizState, ReturnCallback.NO_OP_RETURN_CALLBACK);
quizFrame.setVisible(true);
}
private void performExitProtocol() {
boolean proceed = performSaveProtocolIfNecessary();
if (proceed) {
dispose();
}
}
private boolean performSaveProtocolIfNecessary() {
boolean proceed;
if (isDirty()) {
int saveStatus = JOptionPane.showConfirmDialog(QuestionEditor.this,
"Do you want to save the current question set?", "Exit Question Editor",
JOptionPane.YES_NO_CANCEL_OPTION);
if (saveStatus == JOptionPane.YES_OPTION) {
boolean saved = doSaveAs();
proceed = saved;
} else if (saveStatus == JOptionPane.NO_OPTION) {
proceed = true;
} else { // JOptionPane.CANCEL_OPTION
proceed = false;
}
} else {
proceed = true;
}
return proceed;
}
private QuestionSet openQuestionSet() { // TODO: Duplicate code with QuizFrame
JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogTitle("Open Questions File");
SuffixFileFilter.setSoleFileFilter(fileChooser, Constants.QUESTION_SET_FILE_FILTER);
if (fileChooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION)
return NO_QUESTION_SET;
String fileNameToOpen = fileChooser.getSelectedFile().getAbsolutePath();
InputStream stream = null;
try {
QuestionSet questionSet;
stream = new FileInputStream(fileNameToOpen);
questionSet = QuestionSetManager.getQuestionSetFromInputStream(stream);
this.fileName = fileNameToOpen;
this.baseQuestionSet = questionSet;
return questionSet;
} catch (ParseException e) {
JOptionPane.showMessageDialog(this, "Could not parse " + fileNameToOpen, "Could not parse file",
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(this, "Could not open " + fileNameToOpen, "Could not open file",
JOptionPane.ERROR_MESSAGE);
} finally {
try {
if (stream != null)
stream.close();
} catch (IOException e) {
// Not much we can do about it...
}
}
return NO_QUESTION_SET;
}
private boolean doSaveAs() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogTitle("Save In-Progress Quiz");
SuffixFileFilter.setSoleFileFilter(fileChooser, Constants.QUESTION_SET_FILE_FILTER);
int resultStatus = fileChooser.showSaveDialog(this);
if (resultStatus != JFileChooser.APPROVE_OPTION) {
return false;
}
String questionSetFileName = fileChooser.getSelectedFile().getAbsolutePath();
File questionSetFile = new File(questionSetFileName);
if (!Constants.QUESTION_SET_FILE_FILTER.accept(questionSetFile)) {
questionSetFileName = Constants.QUESTION_SET_FILE_FILTER.addSuffixTo(questionSetFileName);
questionSetFile = new File(questionSetFileName);
}
if (questionSetFile.exists()) {
int confirmStatus = JOptionPane.showConfirmDialog(this, "'" + questionSetFile.getAbsolutePath()
+ "' exists. Do you want to overwrite it?", "Confirm Overwrite", JOptionPane.OK_CANCEL_OPTION);
if (confirmStatus != JOptionPane.OK_OPTION) {
return false;
}
}
boolean saved = doSave(questionSetFileName);
return saved;
}
private boolean doSave(String questionSetFileName) {
QuestionSet questionSet = getQuestionSet();
Document doc = new XmlQuestionSetParser().asXmlDocument(questionSet);
doc.setDocType(new DocType("QuestionSet", "inquisitionQuestions.dtd"));
XMLOutputter outputter = new XMLOutputter();
Format format = Format.getPrettyFormat();
outputter.setFormat(format);
try {
OutputStream outputStream = new FileOutputStream(new File(questionSetFileName));
outputter.output(doc, outputStream);
} catch (IOException e) {
JOptionPane.showMessageDialog(this, "Could not save questions '" + questionSetFileName + "' due to error '"
+ e.getMessage() + "'", "Could not save questions", JOptionPane.ERROR_MESSAGE);
return false;
}
fileName = questionSetFileName;
baseQuestionSet = questionSet;
return true;
}
private QuestionSet getQuestionSet() {
return questionEditorMainPanel.getQuestionSet();
}
private void newQuestionSet() {
fileName = NO_FILE_NAME;
questionEditorMainPanel.setUpNewQuestionSet();
baseQuestionSet = getQuestionSet();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new QuestionEditor();
frame.pack();
frame.setVisible(true);
}
});
}
public void dirtyingActionHappened() {
setTitleBar();
}
}