/*
* Created by JFormDesigner on Thu Sep 06 23:30:59 CEST 2007
*/
package info.opencards.ui;
import info.opencards.CardFileBackend;
import info.opencards.Utils;
import info.opencards.core.*;
import info.opencards.ui.actions.HelpAction;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
/**
* @author Holger Brandl
*/
public class AbstractLearnDialog extends JPanel implements ItemValuater, KeyEventPostProcessor {
private SlideManager presProxy;
Item curItem;
private static final String SCORE_CONTROLS = "scoreControls";
private static final String SHOW_CONTROLS = "showControls";
// normally only the current learn-method will be registerd as scoring listener to this method
private final List<ScoringListener> scoringListeners = new ArrayList<ScoringListener>();
public final static int SCORE_1 = 1;
private final static int SCORE_2 = 2;
private final static int SCORE_3 = 3;
private final static int SCORE_4 = 4;
public final static int SCORE_5 = 5;
public static final int INVALID_ITEM = -123;
public static final int SKIP_ITEM = -124;
public static final int SESSION_INTERRUPTED = -125;
private boolean doIgnoreScoresUntilNewItem;
private boolean disableKeyPP;
private boolean wasAlreadyCanceled;
protected AbstractLearnDialog() {
initComponents();
ResourceBundle bundle = Utils.getRB();
oneButton.setAction(new ScoreAction(bundle.getString("AbstractLearnDialog.oneButton.text"), SCORE_1));
twoButton.setAction(new ScoreAction(bundle.getString("AbstractLearnDialog.twoButton.text"), SCORE_2));
threeButton.setAction(new ScoreAction(bundle.getString("AbstractLearnDialog.threeButton.text"), SCORE_3));
fourButton.setAction(new ScoreAction(bundle.getString("AbstractLearnDialog.fourButton.text"), SCORE_4));
fiveButton.setAction(new ScoreAction(bundle.getString("AbstractLearnDialog.fiveButton.text"), SCORE_5));
controlContainer.add(showControlsContainer, SHOW_CONTROLS);
controlContainer.add(scoreButtonsContainer, SCORE_CONTROLS);
// addWindowListener(new WindowAdapter() {
//
// public void windowClosed(WindowEvent e) {
// KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(AbstractLearnDialog.this);
// }
// });
helpButton.setAction(getHelpAction());
}
protected HelpAction getHelpAction() {
return new HelpAction("ltm.html");
}
public boolean postProcessKeyEvent(KeyEvent e) {
if (!e.paramString().startsWith("KEY_RELEASED") || disableKeyPP)
return false;
switch (e.getKeyCode()) {
case KeyEvent.VK_ESCAPE:
cancelLearningButtonActionPerformed();
break;
case KeyEvent.VK_UP:
skipCardButtonActionPerformed();
break;
// case KeyEvent.VK_C:
// // open the configuration dialog for the current item
// if (e.getKeyCode() == KeyEvent.VK_C && e.isControlDown()) {
// disableKeyPP = true;
// showItemConfigDialog();
// }
}
if (!isShowingComplete()) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
case KeyEvent.VK_RIGHT:
case KeyEvent.VK_DOWN:
showCompleteCardButtonActionPerformed();
break;
}
return true;
}
return false;
}
protected boolean isShowingComplete() {
return scoreButtonsContainer.isShowing();
}
public void score(Item item) {
doIgnoreScoresUntilNewItem = false;
curItem = item;
boolean showSuccessful = presProxy.showCardQuestion(curItem);
if (showSuccessful) {
((CardLayout) controlContainer.getLayout()).first(controlContainer);
// titleLabel.setText((Utils.getRB().getString("AbstractLearnDialog.title.choose")));
// ((TitledBorder)controlContainer.getBorder()).setTitle(Utils.getRB().getString("AbstractLearnDialog.title.choose"));
// ((TitledBorder)controlContainer.getBorder()).setTitle("");
((TitledBorder) controlContainer.getBorder()).setTitle(Utils.getRB().getString("AbstractLearnDialog.recall.title"));
repaint();
showCompleteCardButton.requestFocusInWindow();
} else {
processInvalidItem();
}
}
void processInvalidItem() {
publishItemScore(AbstractLearnDialog.INVALID_ITEM);
}
public void prepareLearnSession() {
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(this);
}
public void prepareFileSession(CardFile cardFile) {
// get an appropriate slide manager
presProxy = CardFileBackend.getBackend().getSlideManager(cardFile);
presProxy.openCardFile(cardFile);
}
public void startFileSession(CardFile cardFile, ItemCollection cardItemCollection) {
Utils.log("starting file session : " + cardFile.toString());
// presProxy.openCardFile(cardFile);
// --> moved to prepareFileSession. this will make OC to sync with the already open file and not with the
// closed one, which should descrease the file-transition tiem
// now renable all controls
enableControls(true);
progressBar.setIndeterminate(false);
presProxy.startFileSession(cardItemCollection);
}
private void enableControls(boolean doEnable) {
oneButton.setEnabled(doEnable);
twoButton.setEnabled(doEnable);
threeButton.setEnabled(doEnable);
fourButton.setEnabled(doEnable);
fiveButton.setEnabled(doEnable);
skipCardButton.setEnabled(doEnable);
showCompleteCardButton.setEnabled(doEnable);
oneButton.paintImmediately(oneButton.getBounds());
}
private void disableControls() {
enableControls(false);
// set progress bar state
progressBar.setIndeterminate(true);
progressBar.setString(Utils.getRB().getString("AbstractLearnDialog.loadingNextFile"));
}
public void finishedFileSession(CardFile cardFile) {
presProxy.stopFileSession();
// disable all controls and set status to 'loading'
disableControls();
}
public void finishedLearnSession() {
if (presProxy != null) {
presProxy.stopLearnSession();
}
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(this);
}
/**
* Informs all registered scoring listeners about current event. (Normally this will be only the used LearnMethod).
* <p/>
* The method is synchronized to make that sure that 'doIgnoreScoresUntilNewItem' is set correctly.
* <p/>
* This method is invoked exactly one for each item being processed. It is invoked only via awt-events like pressed
* buttons or keys.
*/
synchronized void publishItemScore(final int score) {
if (doIgnoreScoresUntilNewItem) { // if a score is currently being processed do nothing but wait for the next item
System.err.println("ignore item score because of pending thread");
return;
}
System.err.println("processs item score " + score);
doIgnoreScoresUntilNewItem = true;
final Item scoreItem = curItem;
// The thread is necessary to decouple the awt-thread from possible time consuming operations like (file IO,
// synchronization, scheduler-setup, card-file switsching). Basically it just publishes an event code to the
// used learn-method which will pursue the necessary action.
// new Thread() {
//
// public void run() {
// super.run();
// although we loop here to keep all as general as posisble, the only scoring listener that is
// currently used is the learnMethod (Leitner or UltraShortSM2)
for (int i = 0; i < scoringListeners.size(); i++) {
scoringListeners.get(i).itemScored(scoreItem, score);
}
// }
// }.start();
}
synchronized void cancelLearningButtonActionPerformed() {
if (wasAlreadyCanceled)
return;
wasAlreadyCanceled = true;
// used until oc 0.16, but removed to avoid multiple acess to the Impress from different threads in an unsynced manner
//showCompleteCardButtonActionPerformed();
publishItemScore(SESSION_INTERRUPTED);
}
protected void showCompleteCardButtonActionPerformed() {
boolean wasSuccessful = presProxy.showCompleteCard(curItem);
((TitledBorder) controlContainer.getBorder()).setTitle(Utils.getRB().getString("AbstractLearnDialog.title"));
repaint();
((CardLayout) controlContainer.getLayout()).last(controlContainer);
invalidate();
if (!wasSuccessful) {
processInvalidItem();
}
}
void skipCardButtonActionPerformed() {
presProxy.showCompleteCard(curItem);
publishItemScore(SKIP_ITEM);
}
public void updateStatus(int completeness, String msg) {
progressBar.setValue(completeness);
progressBar.setString(msg);
}
/**
* Adds a new listener.
*/
public void addScoringListener(ScoringListener l) {
if (l == null || scoringListeners.contains(l))
return;
scoringListeners.add(l);
}
/**
* Removes a listener.
*/
public void removeScoringListener(ScoringListener l) {
if (l == null)
return;
scoringListeners.remove(l);
}
private void showItemConfigDialog() {
// we create a new thread here to avoid a blocking of the awt thread.
new Thread() {
public void run() {
super.run();
List<FlashCard> dummyCardList = Arrays.asList(curItem.getFlashCard());
CardFilePropsDialog propsDialog = new CardFilePropsDialog(null, AbstractLearnDialog.this.presProxy.getCurCardFile(), dummyCardList);
propsDialog.setIsLTMProps(AbstractLearnDialog.this instanceof SMLearnDialog);
propsDialog.setVisible(true);
// this hacks around the problem
try {
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
disableKeyPP = false;
}
}.start();
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
// Generated using JFormDesigner non-commercial license
ResourceBundle bundle = ResourceBundle.getBundle("info.opencards.translation");
controlContainer = new JPanel();
JPanel panel1 = new JPanel();
JPanel panel3 = new JPanel();
JPanel panel4 = new JPanel();
progressBar = new JProgressBar();
panel6 = new JPanel();
helpButton = new JButton();
skipCardButton = new JButton();
button1 = new JButton();
learnGraphContainer = new JPanel();
twoButton = new JButton();
oneButton = new JButton();
threeButton = new JButton();
fourButton = new JButton();
fiveButton = new JButton();
scoreButtonsContainer = new JPanel();
showControlsContainer = new JPanel();
showCompleteCardButton = new JButton();
JButton cancelLearningButton = new JButton();
//======== this ========
setLayout(new GridBagLayout());
((GridBagLayout) getLayout()).columnWidths = new int[]{0, 0};
((GridBagLayout) getLayout()).rowHeights = new int[]{0, 0, 0, 0};
((GridBagLayout) getLayout()).columnWeights = new double[]{1.0, 1.0E-4};
((GridBagLayout) getLayout()).rowWeights = new double[]{1.0, 0.0, 0.0, 1.0E-4};
//======== controlContainer ========
{
controlContainer.setBorder(new TitledBorder(bundle.getString("LearnDialog.controlContainer.border")));
controlContainer.setLayout(new CardLayout());
}
add(controlContainer, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0));
//======== panel1 ========
{
panel1.setLayout(new BorderLayout());
//======== panel3 ========
{
panel3.setLayout(new BorderLayout());
//======== panel4 ========
{
panel4.setLayout(new BorderLayout());
//---- progressBar ----
progressBar.setStringPainted(true);
panel4.add(progressBar, BorderLayout.CENTER);
//======== panel6 ========
{
panel6.setLayout(new FlowLayout());
//---- helpButton ----
helpButton.setText(bundle.getString("General.help"));
panel6.add(helpButton);
//---- skipCardButton ----
skipCardButton.setText(bundle.getString("AbstractLearnDialog.skipCardButton.txt"));
skipCardButton.addActionListener(e -> skipCardButtonActionPerformed());
panel6.add(skipCardButton);
//---- button1 ----
button1.setText(bundle.getString("LearnDialog.button1.text"));
button1.addActionListener(e -> cancelLearningButtonActionPerformed());
panel6.add(button1);
}
panel4.add(panel6, BorderLayout.EAST);
}
panel3.add(panel4, BorderLayout.SOUTH);
}
panel1.add(panel3, BorderLayout.CENTER);
}
add(panel1, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0));
//======== learnGraphContainer ========
{
learnGraphContainer.setLayout(new BorderLayout());
}
add(learnGraphContainer, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0));
//---- twoButton ----
twoButton.setText(bundle.getString("AbstractLearnDialog.twoButton.text"));
twoButton.setFont(twoButton.getFont().deriveFont(twoButton.getFont().getSize() + 4f));
//---- oneButton ----
oneButton.setText(bundle.getString("AbstractLearnDialog.oneButton.text"));
oneButton.setFont(oneButton.getFont().deriveFont(oneButton.getFont().getSize() + 4f));
//---- threeButton ----
threeButton.setText(bundle.getString("AbstractLearnDialog.threeButton.text"));
threeButton.setFont(threeButton.getFont().deriveFont(threeButton.getFont().getSize() + 4f));
//---- fourButton ----
fourButton.setText(bundle.getString("AbstractLearnDialog.fourButton.text"));
fourButton.setFont(fourButton.getFont().deriveFont(fourButton.getFont().getSize() + 4f));
//---- fiveButton ----
fiveButton.setText(bundle.getString("AbstractLearnDialog.fiveButton.text"));
fiveButton.setFont(fiveButton.getFont().deriveFont(fiveButton.getFont().getSize() + 4f));
//======== scoreButtonsContainer ========
{
scoreButtonsContainer.setMinimumSize(new Dimension(0, 50));
scoreButtonsContainer.setPreferredSize(new Dimension(0, 50));
scoreButtonsContainer.setLayout(new BorderLayout());
}
//======== showControlsContainer ========
{
showControlsContainer.setLayout(new GridBagLayout());
((GridBagLayout) showControlsContainer.getLayout()).columnWidths = new int[]{0, 0};
((GridBagLayout) showControlsContainer.getLayout()).rowHeights = new int[]{0, 0};
((GridBagLayout) showControlsContainer.getLayout()).columnWeights = new double[]{1.0, 1.0E-4};
((GridBagLayout) showControlsContainer.getLayout()).rowWeights = new double[]{1.0, 1.0E-4};
//---- showCompleteCardButton ----
showCompleteCardButton.setText(bundle.getString("AbstractLearnDialog.showCompleteCardButton.text"));
showCompleteCardButton.setFont(showCompleteCardButton.getFont().deriveFont(showCompleteCardButton.getFont().getSize() + 4f));
showCompleteCardButton.addActionListener(e -> showCompleteCardButtonActionPerformed());
showControlsContainer.add(showCompleteCardButton, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0));
}
//---- cancelLearningButton ----
cancelLearningButton.setText(bundle.getString("AbstractLearnDialog.cancelLearningButton.text"));
cancelLearningButton.addActionListener(e -> cancelLearningButtonActionPerformed());
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
// Generated using JFormDesigner non-commercial license
protected JPanel controlContainer;
protected JProgressBar progressBar;
private JPanel panel6;
private JButton helpButton;
private JButton skipCardButton;
private JButton button1;
protected JPanel learnGraphContainer;
protected JButton twoButton;
protected JButton oneButton;
protected JButton threeButton;
protected JButton fourButton;
protected JButton fiveButton;
protected JPanel scoreButtonsContainer;
protected JPanel showControlsContainer;
private JButton showCompleteCardButton;
// JFormDesigner - End of variables declaration //GEN-END:variables
class ScoreAction extends AbstractAction {
private final int actionScore;
public ScoreAction(String name, int actionScore) {
super(name);
this.actionScore = actionScore;
putValue(NAME, name);
}
public void actionPerformed(ActionEvent e) {
publishItemScore(actionScore);
}
public int getActionScore() {
return actionScore;
}
}
}