/***
* Copyright (c) 2008, Endless Loop Software, Inc.
*
* This file is part of EgoNet.
*
* EgoNet 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.
*
* EgoNet 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.egonet.gui.author;
import org.egonet.model.Shared;
import org.egonet.model.question.*;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;
import javax.swing.text.DefaultEditorKit;
import org.egonet.exceptions.CorruptedInterviewException;
import org.egonet.gui.MDIChildFrame;
import org.egonet.mdi.MDIContext;
import org.egonet.model.question.Question;
import org.egonet.util.CatchingAction;
import org.egonet.util.EgonetAnalytics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.egonet.model.question.StudyQuestion;
public class EgoFrame extends MDIChildFrame implements Observer, InternalFrameListener {
final private static Logger logger = LoggerFactory.getLogger(EgoFrame.class);
/**
* Changes based on jTabbedPane_stateChanged, which is activated when tabs are clicked
*/
Class<? extends Question> curTab = StudyQuestion.class;
Class<? extends Question> lastTab = StudyQuestion.class;
private final EgoNet egoNet;
private JPanel contentPane;
private final JMenuBar jEgonetMenuBar = new JMenuBar();
private final JMenu jMenuFile = new JMenu("File");
private final JMenuItem jMenuFileNew = new JMenuItem("New Study");
private final JMenuItem jMenuFileOpen = new JMenuItem("Open Study");
private final JMenuItem jMenuFileClose = new JMenuItem("Close Study");
private final JMenuItem jMenuFileImport = new JMenuItem("Import Questions...");
private final JMenuItem jMenuFileExport = new JMenuItem("Export Questions...");
private final JMenuItem jMenuFileExportStudy = new JMenuItem("Export Study As...");
private final JMenuItem jMenuFileSaveAs = new JMenuItem("Save Study As...");
private final JMenuItem jMenuFileSave = new JMenuItem("Save Study");
private final JMenuItem jMenuFileExit = new JMenuItem("Quit");
private final JMenu jMenuEdit = new JMenu("Edit");
private final JMenuItem jMenuEditCut = new JMenuItem(new DefaultEditorKit.CutAction());
private final JMenuItem jMenuEditCopy = new JMenuItem(new DefaultEditorKit.CopyAction());
private final JMenuItem jMenuEditPaste = new JMenuItem(new DefaultEditorKit.PasteAction());
private final JTabbedPane jTabbedPane = new JTabbedPane();
private final BorderLayout borderLayout1 = new BorderLayout();
private final StudyPanel study_panel;
private final Map<Class<? extends Question>,EgoQPanel> questionPanel;
// Construct the frame
public EgoFrame(EgoNet egoNet)
{
try {
this.egoNet = egoNet;
study_panel = new StudyPanel(egoNet);
questionPanel = new HashMap<Class<? extends Question>,EgoQPanel>();
questionPanel.put(EgoQuestion.class, new AuthoringQuestionPanel(egoNet, EgoQuestion.class));
questionPanel.put(AlterPromptQuestion.class, new PromptPanel(egoNet, AlterPromptQuestion.class));
questionPanel.put(AlterQuestion.class, new AuthoringQuestionPanel(egoNet, AlterQuestion.class));
questionPanel.put(AlterPairQuestion.class, new AuthoringQuestionPanel(egoNet, AlterPairQuestion.class));
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
jbInit();
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
// Component initialization
private void jbInit() throws Exception {
// Listen for window closing
//this.addWindowListener(new CloseListener());
this.addInternalFrameListener(this);
//fixme
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setResizable(true);
contentPane = new JPanel();
contentPane.setLayout(borderLayout1);
setContentPane(contentPane);
setTitle("Study Design Tool");
jMenuFileExit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
KeyEvent.VK_Q, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
jMenuFileNew.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
KeyEvent.VK_N, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
jMenuFileOpen.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
KeyEvent.VK_O, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
jMenuFileClose.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
KeyEvent.VK_W, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
jMenuEditCopy.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
KeyEvent.VK_C, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
jMenuEditCut.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
KeyEvent.VK_X, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
jMenuEditPaste.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
KeyEvent.VK_V, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
jMenuEditCopy.setText("Copy");
jMenuEditCut.setText("Cut");
jMenuEditPaste.setText("Paste");
jMenuFile.add(jMenuFileNew);
jMenuFile.add(jMenuFileOpen);
jMenuFile.add(jMenuFileClose);
jMenuFile.addSeparator();
jMenuFile.add(jMenuFileImport);
jMenuFile.add(jMenuFileExport);
jMenuFile.add(jMenuFileExportStudy);
jMenuFile.addSeparator();
jMenuFile.add(jMenuFileSave);
jMenuFile.add(jMenuFileSaveAs);
jMenuFile.addSeparator();
jMenuFile.add(jMenuFileExit);
jMenuEdit.add(jMenuEditCut);
jMenuEdit.add(jMenuEditCopy);
jMenuEdit.add(jMenuEditPaste);
jEgonetMenuBar.add(jMenuFile);
jEgonetMenuBar.add(jMenuEdit);
this.setJMenuBar(jEgonetMenuBar);
jTabbedPane.setTabPlacement(JTabbedPane.TOP);
jTabbedPane.add(study_panel, "Study");
for (Class<? extends Question> qT : Shared.questionClasses) {
if(qT.equals(StudyQuestion.class))
continue;
jTabbedPane.add(questionPanel.get(qT), Question.getNiceName(qT));
}
contentPane.add(jTabbedPane);
/***********************************************************************
* Action Listeners for Menu Events
*/
jMenuFileNew.addActionListener(new CatchingAction("jMenuFileNew") {
public void safeActionPerformed(ActionEvent e) throws Exception {
jMenuFileNew_actionPerformed(e);
}
});
jMenuFileOpen.addActionListener(new CatchingAction("jMenuFileOpen") {
public void safeActionPerformed(ActionEvent e) throws Exception {
jMenuFileOpen_actionPerformed(e);
}
});
jMenuFileClose.addActionListener(new CatchingAction("jMenuFileClose") {
public void safeActionPerformed(ActionEvent e) throws Exception {
jMenuFileClose_actionPerformed(e);
}
});
jMenuFileSave.addActionListener(new CatchingAction("jMenuFileSave") {
public void safeActionPerformed(ActionEvent e) throws Exception {
jMenuFileSave_actionPerformed(e);
}
});
jMenuFileExportStudy.addActionListener(new CatchingAction("jMenuFileExportStudy") {
public void safeActionPerformed(ActionEvent e) throws Exception {
jMenuFileExportStudy_actionPerformed(e);
}
});
jMenuFileSaveAs.addActionListener(new CatchingAction("jMenuFileSaveAs") {
public void safeActionPerformed(ActionEvent e) throws Exception {
jMenuFileSaveAs_actionPerformed(e);
}
});
jMenuFileImport.addActionListener(new CatchingAction("jMenuFileImport") {
public void safeActionPerformed(ActionEvent e) throws Exception {
jMenuFileImport_actionPerformed(e);
}
});
jMenuFileExport.addActionListener(new CatchingAction("jMenuFileExport") {
public void safeActionPerformed(ActionEvent e) throws Exception {
jMenuFileExport_actionPerformed(e);
}
});
jMenuFileExit.addActionListener(new CatchingAction("jMenuFileExit") {
public void safeActionPerformed(ActionEvent e) throws Exception {
jMenuFileExit_actionPerformed(e);
}
});
/***********************************************************************
* Change Listener for tabs
*/
jTabbedPane.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
try {
jTabbedPane_stateChanged(e);
} catch (IOException ex)
{
throw new RuntimeException(ex);
}
}
});
/* Fill panel, initialize frame */
egoNet.getStorage().createNewStudy();
fillCurrentPanel();
pack();
setMinimumSize(getPreferredSize());
setMaximizable(true);
setIconifiable(true);
setClosable(true);
egoNet.getStudy().setModified(false);
updateMenus();
}
/***************************************************************************
* Updates menus to take dirty question and study into account
*/
public void updateMenus() {
if (egoNet.getStorage().getStudyFile() == null) {
jMenuFileImport.setEnabled(false);
jMenuFileClose.setEnabled(false);
jMenuFileSave.setEnabled(false);
jMenuFileExportStudy.setEnabled(false);
jMenuFileSaveAs.setEnabled(false);
jMenuFileExport.setEnabled(false);
jTabbedPane.setEnabledAt(1, false);
jTabbedPane.setEnabledAt(2, false);
jTabbedPane.setEnabledAt(3, false);
jTabbedPane.setEnabledAt(4, false);
jTabbedPane.setSelectedIndex(0);
} else {
jMenuFileImport.setEnabled(true);
jMenuFileClose.setEnabled(true);
jMenuFileSave.setEnabled(egoNet.getStudy().isCompatible()
&& egoNet.getStudy().isModified());
jMenuFileSaveAs.setEnabled(true);
jMenuFileExportStudy.setEnabled(true);
jMenuFileExport.setEnabled(true);
jTabbedPane.setEnabledAt(1, true);
jTabbedPane.setEnabledAt(2, true);
jTabbedPane.setEnabledAt(3, true);
jTabbedPane.setEnabledAt(4, true);
}
}
// split the file menu functionality out into a class of functionality
// and a class of the UI
/**
* New Study menu handler
*
* @param e
* Menu UI Event
* @throws IOException
*/
private void jMenuFileNew_actionPerformed(ActionEvent e) throws IOException {
boolean ok = closeStudyFile();
if (ok) {
egoNet.getStorage().newStudyFiles();
fillCurrentPanel();
egoNet.getStudy().setModified(false);
egoNet.getStudy().setCompatible(true);
egoNet.getStudy().addObserver(this);
updateMenus();
}
}
/***************************************************************************
* Open Study menu handler
*
* @param e
* Menu UI Event
* @throws IOException
*/
private void jMenuFileOpen_actionPerformed(ActionEvent e) throws IOException {
boolean ok = closeStudyFile();
if (ok) {
egoNet.getStorage().selectStudy();
fillCurrentPanel();
egoNet.getStudy().setModified(false);
egoNet.getStudy().setCompatible(true);
egoNet.getStudy().addObserver(this);
updateMenus();
}
}
private void jMenuFileClose_actionPerformed(ActionEvent e) throws IOException {
boolean ok = closeStudyFile();
if (ok) {
egoNet.getStorage().createNewStudy();
fillCurrentPanel();
egoNet.getStudy().addObserver(this);
egoNet.getStudy().setModified(false);
}
}
private void jMenuFileImport_actionPerformed(ActionEvent e) throws Exception {
egoNet.getStorage().importQuestions();
fillCurrentPanel();
}
private void jMenuFileExport_actionPerformed(ActionEvent e) {
egoNet.getStorage().exportQuestions();
}
private void jMenuFileSave_actionPerformed(ActionEvent e) throws IOException {
EgonetAnalytics.track("save study"); // track!
if (egoNet.getStorage().getStudyFile() == null) {
jMenuFileSaveAs_actionPerformed(e);
} else {
egoNet.getStorage().saveStudyFile();
egoNet.getStudy().setModified(false);
}
}
private void jMenuFileExportStudy_actionPerformed(ActionEvent e) throws IOException, CorruptedInterviewException {
egoNet.getStorage().exportStudy(false);
}
private void jMenuFileSaveAs_actionPerformed(ActionEvent e) throws IOException {
egoNet.getStorage().saveAsStudyFile();
fillStudyPanel();
egoNet.getStudy().addObserver(this);
egoNet.getStudy().setModified(false);
egoNet.getStudy().setCompatible(true);
}
// File | Exit action performed
public void jMenuFileExit_actionPerformed(ActionEvent e) {
try {
boolean exit = closeStudyFile();
if (exit) {
dispose();
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
/**
* Closes question file. If changes made gives user the option of saving.
*
* @return False iff user cancels save, True otherwise
* @throws IOException
*/
public boolean closeStudyFile() throws IOException {
boolean exit = true;
if (egoNet.getStudy().isModified()) {
int confirm = JOptionPane
.showConfirmDialog(
this,
"There are unsaved changes to the study. Would you like to save the study now?",
"Save Study Changes",
JOptionPane.YES_NO_CANCEL_OPTION);
if (confirm == JOptionPane.YES_OPTION) {
jMenuFileSave_actionPerformed(null);
} else if (confirm == JOptionPane.CANCEL_OPTION) {
exit = false;
}
}
return exit;
}
public void fillCurrentPanel() throws IOException {
boolean sd = egoNet.getStudy().isModified();
boolean sc = egoNet.getStudy().isCompatible();
if (curTab == StudyQuestion.class) {
study_panel.fillPanel();
} else {
questionPanel.get(curTab).fillPanel();
}
egoNet.getStudy().setModified(sd);
egoNet.getStudy().setCompatible(sc);
}
public void fillStudyPanel() throws IOException {
boolean sd = egoNet.getStudy().isModified();
if (curTab == StudyQuestion.class) {
study_panel.fillPanel();
}
egoNet.getStudy().setModified(sd);
}
private void jTabbedPane_stateChanged(ChangeEvent e) throws IOException
{
lastTab = curTab;
Component selectedTab = jTabbedPane.getSelectedComponent();
if(selectedTab instanceof StudyPanel)
{
curTab = StudyQuestion.class;
} else {
curTab = ((EgoQPanel)selectedTab).questionType;
}
if ((lastTab == StudyQuestion.class) && (curTab != lastTab)) {
egoNet.getStudy().validateQuestions();
}
if (curTab == StudyQuestion.class) {
study_panel.fillPanel();
} else {
questionPanel.get(curTab).fillPanel();
}
}
protected void setWaitCursor(boolean waitCursor) {
if (waitCursor) {
this.getGlassPane().setVisible(true);
this.getGlassPane().setCursor(
Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
} else {
this.getGlassPane().setCursor(
Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
this.getGlassPane().setVisible(false);
}
}
class CloseListener extends WindowAdapter {
/*
* (non-Javadoc)
*
* @see java.awt.event.WindowListener#windowClosed(java.awt.event.WindowEvent)
*/
public void windowClosing(WindowEvent arg0) {
logger.info("Window close event received");
try {
jMenuFileExit_actionPerformed(null);
} catch (Throwable cause)
{
throw new RuntimeException(cause);
}
}
}
/*
* (non-Javadoc)
*
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void update(Observable o, Object arg) {
updateMenus();
}
public void focusActivated() {
//logger.info(this.getTitle() + " activated");
}
public void focusDeactivated() {
//logger.info(this.getTitle() + " deactivated");
}
public JInternalFrame getInternalFrame() {
return this;
}
public void setMdiContext(MDIContext context) {
}
public void internalFrameActivated(InternalFrameEvent e) {
}
public void internalFrameClosed(InternalFrameEvent e) {
}
public void internalFrameClosing(InternalFrameEvent e) {
jMenuFileExit_actionPerformed(null);
}
public void internalFrameDeactivated(InternalFrameEvent e) {
}
public void internalFrameDeiconified(InternalFrameEvent e) {
}
public void internalFrameIconified(InternalFrameEvent e) {
}
public void internalFrameOpened(InternalFrameEvent e) {
}
}