package info.opencards.ui.actions;
import info.opencards.CardFileBackend;
import info.opencards.OpenCards;
import info.opencards.Utils;
import info.opencards.core.*;
import info.opencards.learnstrats.ltm.LTMProcessManager;
import info.opencards.learnstrats.ltm.RefreshProcessManager;
import info.opencards.learnstrats.ltm.SM2;
import info.opencards.ui.CardFileSelectionListener;
import info.opencards.ui.LearnManagerUI;
import info.opencards.ui.SMLearnDialog;
import org.junit.Test;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.io.File;
import java.util.*;
/**
* DOCUMENT ME!
*
* @author Holger Brandl
*/
public class StartLearningAction extends AbstractAction implements CardFileSelectionListener {
private final LearnManagerUI learnManUI;
private List<CardFile> curSelCardFiles;
private boolean wasAltPressed;
private boolean wasCtrlPressed;
public StartLearningAction(LearnManagerUI learnManUI) {
this.learnManUI = learnManUI;
updateModKeyState();
}
public void updateModKeyState() {
// update the name of the action
ResourceBundle rb = Utils.getRB();
if (learnManUI.isCtrlPressed()) {
String newFlag = " +'" + rb.getString("CardTableModel.numNewCards").replace("#", "").trim() + "'";
putValue(NAME, rb.getString("StartLearningAction.StartLearning") + newFlag);
} else if (learnManUI.isShiftPressed()) {
putValue(NAME, rb.getString("StartLearningAction.StartRefreshing"));
} else {
putValue(NAME, rb.getString("StartLearningAction.StartLearning"));
}
}
public void actionPerformed(ActionEvent e) {
wasAltPressed = learnManUI.isShiftPressed();
wasCtrlPressed = learnManUI.isCtrlPressed();
// start the learning session
learnCardFiles(curSelCardFiles);
}
public void cardFileSelectionChanged(List<CardFile> curSelCardFiles) {
this.curSelCardFiles = curSelCardFiles;
}
void learnCardFiles(final Collection<CardFile> curFiles) {
Utils.log("initiating learning session for: " + curFiles.toString());
//todo disabled for now, should be removed properly later
// // first synchronize files if preLTM-Syncing is enabled in the OC-settings
// boolean doPreLtmSync = Utils.getPrefs().getBoolean(GlobLearnSettings.DO_PRE_LTM_SYNC, GlobLearnSettings.DO_PRE_LTM_SYNC_DEFAULT);
// if (doPreLtmSync) {
// CardFileSyncAction syncAction = new CardFileSyncAction(null, null);
// syncAction.setCardFiles(new ArrayList<CardFile>(curFiles));
//
// Utils.log("running pre-session synchronization");
// syncAction.actionPerformed(null);
//
// // wait for the dialog to finish (this will block the ui but anyway
// while (syncAction.getSyncDialog().isVisible()) {
// Utils.sleep(100);
// }
// }
// now learn the cards
final ItemValuater itemValuater = new SMLearnDialog();
final LearnMethodFactory factory = SM2.getFactory();
// select between refreshing and real ltm-learning
final LTMProcessManager processManager;
if (wasAltPressed)
processManager = new RefreshProcessManager(itemValuater, factory);
else {
processManager = new LTMProcessManager(itemValuater, factory);
processManager.setIncludeAllNew(wasCtrlPressed);
}
OpenCards.getInstance().getLearnPanel().setControls(itemValuater);
OpenCards.showLearnView();
// Utils.log("setuping schedule");
processManager.setupSchedule(curFiles);
processManager.addLearnProcessManagerProcessListener(new LearnProcListener() {
public void processFinished(boolean wasInterrupted) {
Utils.log("processFinished interrupt=" + wasInterrupted);
if (!wasInterrupted) {
// check if there were any new cards detected (if this is the case ask whether these files should be
// learned now)
// Note: it is a known defect, that cards which were added
// a) while learning cards
// AND
// b) where added behind (in terms of slide index) after the slides queried slides after creation
// ... WON'T be detected. The cause is the only optional sync which is used to keep OC in sync
// with changes in the impress-presentation.
// Although this is a minor bug, we probably won't fix it to avoid the necessary (and performance
// decreasing) synchronize-operation.
// LTMProcessManager newCardsDummyScheduler = new LTMProcessManager(itemValuater, factory);
final Map<CardFile, List<Item>> skippedItems = new HashMap<CardFile, List<Item>>(processManager.getSkippedItems());
processManager.setupSchedule(curFiles);
// remove items from scheduler that were skipped for this session
for (CardFile fileWithSkippedItems : skippedItems.keySet()) {
List<Item> newFileItems = processManager.getScheduledItems(fileWithSkippedItems);
if (newFileItems == null)
continue;
for (Item skippedItem : skippedItems.get(fileWithSkippedItems)) {
processManager.unschdeduleItem(fileWithSkippedItems, skippedItem);
}
}
if (processManager.hasScheduledItems()) {
Utils.log("found new items after session: " + processManager.toString());
String newCardsMsg = Utils.getRB().getString("StartLearningAction.newCardsDetected.msg");
String newCardsTitle = Utils.getRB().getString("StartLearningAction.newCardsDetected.title");
int answer = JOptionPane.showConfirmDialog(null, newCardsMsg, newCardsTitle, JOptionPane.YES_NO_OPTION);
if (answer == JOptionPane.YES_OPTION) {
// we do the most straighforward thing here which is to use the same approach
// again: we just instantiate another StartLearningAction and trigger it immediately
// new StartLearningAction(learnManUI, backend).learnCardFiles(curFiles);
processManager.startProcessing();
return; // necessary because otherwise the learnMainUI would be made visible
}
}
}
// make the gui visible again
OpenCards.showCategoryView();
}
});
processManager.startProcessing();
// this is (and needs to be!!) all non-blocking because we're in the awt-thread while running this method!
}
@Test
public void testStartLearning() {
CardFileBackend backend = CardFileBackend.getBackend();
File tempFile = Utils.createTempCopy(new File("testdata/experimental design.ppt"));
CardFile cardFile = new CardFile(tempFile);
cardFile.setSerializer(backend.getSerializer());
StartLearningAction learningAction = new StartLearningAction(null);
learningAction.learnCardFiles(new ArrayList<CardFile>(Arrays.asList(cardFile)));
}
}