/***
* 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 java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.egonet.exceptions.DuplicateQuestionException;
import org.egonet.gui.interview.ClientQuestionPanel;
import org.egonet.model.question.AlterPromptQuestion;
import org.egonet.model.question.Question;
/**
* Generic Panel creation and handling routines for question editing
*/
public class PromptPanel extends EgoQPanel
{
private boolean inUpdate;
private final JSplitPane question_split = new JSplitPane();
private final JList<Question> question_list = new JList<Question>();
private final JScrollPane question_list_scroll = new JScrollPane(question_list);
private final JPanel question_panel_right = new RightPanel();
private final JLabel question_title_label = new JLabel("Title:");
private final JLabel question_question_label = new JLabel("Question:");
private final JLabel question_citation_label = new JLabel("Citation:");
private final JLabel question_follows_label = new JLabel("Follows Question:");
private final JTextArea question_question_field = new NoTabTextArea();
private final JTextArea question_citation_field = new NoTabTextArea();
private final JTextField question_title_field = new JTextField();
private final JButton question_new_button = new JButton("New");
private final JButton question_preview_button = new JButton("Preview");
private final JComboBox<Question> question_follows_menu = new JComboBox<Question>();
private final JButton question_delete_button = new JButton("Delete");
private final Border listBorder;
private final EgoNet egoNet;
/**
* Generates Panel for question editing to insert in file tab window
*
* @param type Type of questions on Page (e.g. Alter Questions)
* @param parent parent frame for referencing composed objects
*/
public PromptPanel(EgoNet egoNet, Class<? extends Question> type) throws Exception
{
super(type);
this.egoNet = egoNet;
question_question_field.setName("question_question_field");
question_citation_field.setName("question_citation_field");
question_title_field.setName("question_title_field");
listBorder = BorderFactory.createCompoundBorder(
new TitledBorder(new EtchedBorder(EtchedBorder.RAISED,Color.white,new Color(178, 178, 178)),
Question.getNiceName(questionType)),
BorderFactory.createEmptyBorder(10,10,10,10));
jbInit();
}
/**
* Component initialization
*
* @throws Exception
*/
private void jbInit() throws Exception
{
inUpdate = true;
// Configure Split Frame
question_split.setMinimumSize(new Dimension(430, 330));
question_split.setPreferredSize(new Dimension(430, 330));
question_split.setResizeWeight(.33);
question_split.setDividerLocation(.33);
question_list_scroll.setRequestFocusEnabled(false);
question_split.add(question_list_scroll, JSplitPane.LEFT);
question_split.add(question_panel_right, JSplitPane.RIGHT);
this.setLayout(new GridLayout());
// Configure List
question_list_scroll.setBorder(listBorder);
question_list_scroll.setMinimumSize(new Dimension(150, 150));
question_list_scroll.setPreferredSize(new Dimension(150, 150));
question_list_scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
question_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
question_list.setCellRenderer(new QuestionListCellRenderer<Question>());
// Configure question fields
question_panel_right.setLayout(new GridBagLayout());
question_question_field.setMaximumSize(new Dimension(280, 64));
question_question_field.setMinimumSize(new Dimension(72, 16));
question_question_field.setPreferredSize(new Dimension(72, 16));
question_question_field.setLineWrap(true);
question_question_field.setRows(1);
question_question_field.setTabSize(4);
question_question_field.setWrapStyleWord(true);
question_citation_field.setMaximumSize(new Dimension(280, 64));
question_citation_field.setMinimumSize(new Dimension(72, 16));
question_citation_field.setPreferredSize(new Dimension(72, 16));
question_citation_field.setLineWrap(true);
question_citation_field.setRows(1);
question_citation_field.setTabSize(4);
question_citation_field.setWrapStyleWord(true);
/* Question Layout */
question_panel_right.add(question_title_label, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST,
GridBagConstraints.HORIZONTAL, new Insets(10, 10, 10, 10), 0, 0));
question_panel_right.add(question_title_field, new GridBagConstraints(1, 0, 2, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(10, 10, 10, 10), 0, 4));
question_panel_right.add(question_question_label, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(10, 10, 10, 10), 0, 0));
question_panel_right.add(new JScrollPane(question_question_field), new GridBagConstraints(1, 1, 2, 2, 0.0, 0.4,
GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(10, 10, 10, 10), 0, 0));
question_panel_right.add(question_citation_label, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(10, 10, 10, 10), 0, 0));
question_panel_right.add(new JScrollPane(question_citation_field), new GridBagConstraints(1, 3, 2, 2, 0.0, 0.3,
GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(10, 10, 10, 10), 0, 0));
question_panel_right.add(question_new_button, new GridBagConstraints(0, 7, 1, 1, 0.33, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(10, 10, 10, 10), 0, 0));
question_panel_right.add(question_preview_button, new GridBagConstraints(1, 7, 1, 1, 0.33, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(10, 10, 10, 10), 0, 0));
question_panel_right.add(question_delete_button, new GridBagConstraints(2, 7, 1, 1, 0.33, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(10, 10, 10, 10), 0, 0));
question_panel_right.add(question_follows_label, new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(10, 10, 10, 10), 0, 0));
question_panel_right.add(question_follows_menu, new GridBagConstraints(1, 5, 1, 1, 0.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 10, 10, 10), 0, 0));
DefaultListModel<Question> listModel = new DefaultListModel<Question>();
question_list.setModel(listModel);
egoNet.getStudy().fillList(questionType, listModel);
question_list.getSelectionModel().addListSelectionListener(new ListSelectionListener()
{
public void valueChanged(ListSelectionEvent e)
{
question_list_selectionChanged(e);
}
});
question_new_button.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e) {
question_new_button_actionPerformed(e);
}
});
question_preview_button.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
ClientQuestionPanel.showPreview(
question_title_field.getText(),question_question_field.getText(),
AlterPromptQuestion.class,null,null);
}
});
question_delete_button.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
question_delete_button_actionPerformed(e);
}
});
question_follows_menu.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
question_follows_menu_actionPerformed(e);
}
});
question_title_field.getDocument().addDocumentListener(new DocumentListener()
{
public void insertUpdate(DocumentEvent e)
{
questionTitleEvent();
}
public void changedUpdate(DocumentEvent e)
{
questionTitleEvent();
}
public void removeUpdate(DocumentEvent e)
{
questionTitleEvent();
}
});
question_question_field.getDocument().addDocumentListener(new DocumentListener()
{
public void insertUpdate(DocumentEvent e)
{
questionTextEvent();
}
public void changedUpdate(DocumentEvent e)
{
questionTextEvent();
}
public void removeUpdate(DocumentEvent e)
{
questionTextEvent();
}
});
question_citation_field.getDocument().addDocumentListener(new DocumentListener()
{
public void insertUpdate(DocumentEvent e)
{
questionCitationEvent();
}
public void changedUpdate(DocumentEvent e)
{
questionCitationEvent();
}
public void removeUpdate(DocumentEvent e)
{
questionCitationEvent();
}
});
add(question_split);
inUpdate = false;
}
/**
* Updates right side question fields when the selection changes
*
* @param e event generated by selection change.
*/
public void question_list_selectionChanged(ListSelectionEvent e)
{
if (!inUpdate)
{
questionUpdate();
}
}
/****
* fill List with appropriate questions Set other fields to selected
* question
*/
public void fillPanel()
{
//logger.info("fillPanel() called in PromptPanel but questionType was " + questionType + " and curTab was " + egoNet.getFrame().curTab);
if (questionType == egoNet.getFrame().curTab)
{
storageUpdate();
questionUpdate();
}
}
/**
* Called when file changes to load new questions into list
*/
void storageUpdate()
{
inUpdate = true;
if (questionType == egoNet.getFrame().curTab)
{
((DefaultListModel) question_list.getModel()).removeAllElements();
egoNet.getStudy().fillList(questionType, (DefaultListModel<Question>)question_list.getModel());
}
inUpdate = false;
}
void questionUpdate()
{
inUpdate = true;
/** @todo Use List Data Listener? */
if (questionType.equals(egoNet.getFrame().curTab)) {
int index = question_list.getSelectedIndex();
if ((question_list.getModel().getSize() > 0) && (index == -1))
{
index = 0;
}
question_follows_menu.removeAllItems();
question_follows_menu.addItem(egoNet.getStudy().getFirstQuestion());
for (int i = 0; i < question_list.getModel().getSize(); i++)
{
if (i != index)
{
question_follows_menu.addItem(question_list.getModel().getElementAt(i));
}
}
question_list.setSelectedIndex(index);
Question q = (Question) question_list.getSelectedValue();
if (q != null)
{
question_question_field.setText(q.text);
question_citation_field.setText(q.citation);
question_title_field.setText(q.title);
question_follows_menu.setSelectedIndex(index);
question_question_field.setEditable(true);
question_citation_field.setEditable(true);
question_title_field.setEditable(true);
question_delete_button.setEnabled(true);
question_follows_menu.setEnabled(true);
}
else
{
question_question_field.setText(null);
question_citation_field.setText(null);
question_title_field.setText(null);
question_question_field.setEditable(false);
question_citation_field.setEditable(false);
question_title_field.setEditable(false);
question_delete_button.setEnabled(false);
question_follows_menu.setEnabled(false);
}
}
inUpdate = false;
}
/****
* Clear all on screen editable fields Generally called when a new survey is
* started
*/
public void clearPanel()
{
inUpdate = true;
((DefaultListModel) question_list.getModel()).removeAllElements();
inUpdate = false;
}
/****
* Document event handler used to read text fields
*
* @param e Document Event
*/
private void questionTitleEvent()
{
Question q = (Question) question_list.getSelectedValue();
String s;
if ((q != null) && !inUpdate)
{
s = question_title_field.getText().trim();
if ((q.title == null) || (!q.title.equals(s)))
{
q.title = question_title_field.getText().trim();
egoNet.getStudy().setModified(true);
question_list.repaint();
}
}
}
/****
* Document event handler used to read text fields
*
* @param e Document Event
*/
private void questionTextEvent()
{
Question q = (Question) question_list.getSelectedValue();
String s;
if ((q != null) && !inUpdate)
{
s = question_question_field.getText().trim();
if ((q.text == null) || (!q.text.equals(s)))
{
q.text = question_question_field.getText().trim();
egoNet.getStudy().setModified(true);
}
}
}
/****
* Document event handler used to read text fields
*
* @param e Document Event
*/
private void questionCitationEvent()
{
Question q = (Question) question_list.getSelectedValue();
String s;
if ((q != null) && !inUpdate)
{
s = question_citation_field.getText().trim();
if ((q.citation == null) || (!q.citation.equals(s)))
{
q.citation = question_citation_field.getText().trim();
egoNet.getStudy().setModified(true);
}
}
}
void question_new_button_actionPerformed(ActionEvent e) {
Question q;
try { q = questionType.newInstance(); } catch (Exception ex) { throw new RuntimeException(ex); }
q.title = new String("Untitled Question");
try
{
egoNet.getStudy().addQuestion(q);
}
catch (DuplicateQuestionException e1)
{
throw new RuntimeException(e1);
}
fillPanel();
question_list.setSelectedValue(q, true);
question_title_field.requestFocus();
question_title_field.setSelectionStart(0);
question_title_field.setSelectionEnd(question_title_field.getText().length());
}
void question_delete_button_actionPerformed(ActionEvent e)
{
Question q = (Question) question_list.getSelectedValue();
if (q != null)
{
int confirm = JOptionPane.showConfirmDialog(egoNet.getFrame(), "Permanently remove this questions?",
"Delete Question", JOptionPane.OK_CANCEL_OPTION);
if (confirm == JOptionPane.OK_OPTION)
{
egoNet.getStudy().removeQuestion(q);
fillPanel();
}
}
}
/**
* Changes order of questions
*
* @param e UI event
*/
void question_follows_menu_actionPerformed(ActionEvent e)
{
if (!inUpdate)
{
Question follows = (Question) question_follows_menu.getSelectedItem();
Question q = (Question) question_list.getSelectedValue();
egoNet.getStudy().moveQuestionAfter(q, follows);
fillPanel();
}
}
}