Logo Search packages:      
Sourcecode: pauker version File versions  Download package

PaukerFrame.java

/*
 * PaukerFrame.java
 *
 * Created on 5. Juni 2001, 22:19
 */

package pauker.program.gui.swing;

import edu.stanford.ejalbert.BrowserLauncher;
import edu.stanford.ejalbert.exception.BrowserLaunchingInitializingException;
import edu.stanford.ejalbert.exception.UnsupportedOperatingSystemException;
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.KeyboardFocusManager;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import java.util.zip.GZIPOutputStream;
import javax.help.HelpBroker;
import javax.help.HelpSet;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.LayoutFocusTraversalPolicy;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.border.TitledBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Document;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import pauker.program.Batch;
import pauker.program.Card;
import pauker.program.CardSide;
import pauker.program.Lesson;
import pauker.program.LongTermBatch;
import pauker.program.Pauker;
import pauker.program.SearchEngine;
import pauker.program.SearchHit;
import pauker.program.SummaryBatch;
import tools.PathNodeDiff;

/**
 *
 * @author Ronny.Standtke@gmx.net
 */
00099 public class PaukerFrame
        extends JFrame
        implements DocumentListener, PropertyChangeListener {

    /**
     * Pauker's red color
     */
00106     public static final Color RED = new Color(255, 180, 180);
    /**
     * Pauker's yellow color
     */
00110     public static final Color YELLOW = new Color(255, 255, 180);
    /**
     * Pauker's green color
     */
00114     public static final Color GREEN = new Color(180, 255, 180);
    /**
     * Pauker's blue color
     */
00118     public static final Color BLUE = new Color(180, 180, 255);
    /**
     * Pauker's default font
     */
00122     public static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 12);
    /**
     * Pauker's strings
     */
00126     public static final ResourceBundle STRINGS =
            ResourceBundle.getBundle("pauker/Strings");
    private static final int MAX_RECENT_FILES = 4;
    private static final Logger logger =
            Logger.getLogger(PaukerFrame.class.getName());
    private boolean somethingChanged;
    private boolean recentFilesHaveChanged;
    private static boolean modalDialogVisible;
    private final FileFilter xmlFileFilter;
    private final FileFilter csvFileFilter;
    private final Toolkit defautToolkit;
    // program settings
    private static final String preferencesPathName = "/org/pauker";
    private Pauker.RepeatingStrategy repeatingStrategy;
    private Pauker.PutbackStrategy putBackStrategy;
    private int ustmTime;
    private int stmTime;
    private boolean matchCase;
    private boolean lineWrapping;
    private int splitOrientation;
    private int searchLimit;
    private boolean playRingTone;
    private final List<String> recentFiles;
    private String lastAccessedDirectory;
    private final boolean showTimer;
    private final Font frontSideFont;
    private final Color frontSideForeground;
    private final Color frontSideBackground;
    private final Font reverseSideFont;
    private final Color reverseSideForeground;
    private final Color reverseSideBackground;
    private final boolean repeatByTyping;
    private boolean keepNewCardDialogOpen;
    private final String titleString;
    private String currentTitle;
    private String currentFileName;
    private final OpenFileDialog openFileDialog;
    private final JFileChooser saveFileChooser;
    private String stmTimeString;
    private int currentUSTMTime;
    private int currentSTMTime;
    private final AudioClip ringTone;
    private final Timer ustmTimer = new Timer(1000, new ActionListener() {

        public void actionPerformed(ActionEvent evt) {
            currentUSTMTime++;
            if (currentUSTMTime < getUstmTime()) {
                ustmTimerProgressBar.setValue((100 * currentUSTMTime) / getUstmTime());
                ustmTimerProgressBar.setString(currentUSTMTime + " / " + getUstmTime() + " " + STRINGS.getString("Seconds"));
            } else {
                ustmTimer.stop();
                ustmTimerProgressBar.setValue(0);
                ustmTimerProgressBar.setString("");
                if (Pauker.getLearningPhase() == Pauker.LearningPhase.WAITING_FOR_USTM) {
                    setState(Frame.NORMAL);
                    toFront();
                    defautToolkit.beep();
                    if (isPlayRingTone()) {
                        ringTone.play();
                    }
                    repeatUSTMCards();
                }
            }
        }
    });
    private final Timer stmTimer = new Timer(1000, new ActionListener() {

        public void actionPerformed(ActionEvent evt) {
            currentSTMTime++;
            if (currentSTMTime < getStmTime()) {
                stmTimerProgressBar.setValue((100 * currentSTMTime) / getStmTime());
                String currentTimeString = getMinSecString(currentSTMTime);
                stmTimerProgressBar.setString(currentTimeString + " / " +
                        stmTimeString + " " + STRINGS.getString("Minutes"));
                if (Pauker.getLearningPhase() == Pauker.LearningPhase.WAITING_FOR_STM) {
                    setTitle(currentTimeString + " " + currentTitle);
                }
            } else {
                stmTimer.stop();
                stmTimerProgressBar.setValue(0);
                stmTimerProgressBar.setString("");
                if (Pauker.getLearningPhase() == Pauker.LearningPhase.WAITING_FOR_STM) {
                    setState(Frame.NORMAL);
                    toFront();
                    defautToolkit.beep();
                    if (isPlayRingTone()) {
                        ringTone.play();
                    }
                    repeatSTMCards();
                }
            }
        }
    });

    private static String getMinSecString(int seconds) {
        int minuntes = seconds / 60;
        int remainingSeconds = seconds - minuntes * 60;
        return (minuntes + ":" + (remainingSeconds < 10 ? "0" : "") + remainingSeconds);
    }
    private final Timer expirationTimer = new Timer(60000, new ActionListener() {

        public void actionPerformed(ActionEvent evt) {
            currentLesson.refreshExpiration();
            statisticPanel.setLesson(currentLesson);
            if (Pauker.getLearningPhase() == Pauker.LearningPhase.NOTHING) {
                repeatCardsButton.setEnabled(currentLesson.getNumberOfExpiredCards() > 0);
            }
        }
    });
    private Lesson currentLesson;
    private Card currentCard;
    private HelpBroker helpbroker;
    private final TitledBorder batchPanelBorder;
    private final BatchListModel batchListModel;
    private final BatchListCellRenderer batchListCellRenderer;
    private Batch loadedBatch;
    private SearchDialog searchDialog;
    private NewCardDialog newCardDialog;
    private final Document aboutDocument;
    private boolean settingAboutText;
    private final SearchEngine searchEngine;
    private int searchPatternLength;
    private Random random;
    private Card.Element fontDialogSide;

    /** Creates new form JPauker */
00252     public PaukerFrame() {

        KeyboardFocusManager currentKeyboardFocusManager =
                KeyboardFocusManager.getCurrentKeyboardFocusManager();
        currentKeyboardFocusManager.addPropertyChangeListener(this);

        currentLesson = new Lesson();

        // init our search engine for similar cards
        searchEngine = new SearchEngine();

        // load preferences
        recentFiles = new ArrayList<String>();
        Preferences preferences =
                Preferences.userRoot().node(preferencesPathName);
        for (int i = 0; i < MAX_RECENT_FILES; i++) {
            String recentFile = preferences.get("RECENT_FILE_" + i, null);
            if (recentFile == null) {
                break;
            } else {
                recentFiles.add(recentFile);
                recentFilesHaveChanged = true;
            }
        }
        lastAccessedDirectory = preferences.get("LAST_DIRECTORY", "");
        showTimer = preferences.getBoolean("SHOW_TIMER", true);
        repeatingStrategy = Pauker.RepeatingStrategy.values()[preferences.getInt("REPEATING_STRATEGY",
                Pauker.RepeatingStrategy.OLDEST_FIRST.ordinal())];
        putBackStrategy = Pauker.PutbackStrategy.values()[preferences.getInt("PUTBACK_STRATEGY",
                Pauker.PutbackStrategy.ON_TOP.ordinal())];
        ustmTime = preferences.getInt("USTM_TIME", Pauker.USTM_TIME);
        stmTime = preferences.getInt("STM_TIME", Pauker.STM_TIME);
        matchCase = preferences.getBoolean("MATCH_CASE", true);
        lineWrapping = preferences.getBoolean("LINE_WRAPPING", false);
        splitOrientation = preferences.getInt("SPLIT_ORIENTATION",
                JSplitPane.HORIZONTAL_SPLIT);
        searchLimit = preferences.getInt("SEARCH_LIMIT", 1);
        searchEngine.setSearchLimit(searchLimit);
        playRingTone = preferences.getBoolean("PLAY_RINGTONE", true);
        int dividerLocation = preferences.getInt("MAIN_DIVIDER_LOCATION", -1);

        String frontSideFontFamily =
                preferences.get("FRONTSIDE_FONT_FAMILY", "Default");
        int frontSideFontStyle =
                preferences.getInt("FRONTSIDE_FONT_STYLE", Font.PLAIN);
        int frontSizeFontSize = preferences.getInt("FRONTSIDE_FONT_SIZE", 12);
        frontSideFont = new Font(
                frontSideFontFamily, frontSideFontStyle, frontSizeFontSize);
        int frontSideForegroundRGB = preferences.getInt(
                "FRONTSIDE_FOREGROUND", Color.BLACK.getRGB());
        frontSideForeground = new Color(frontSideForegroundRGB);
        int frontSideBackgroundRGB = preferences.getInt(
                "FRONTSIDE_BACKGROUND", Color.WHITE.getRGB());
        frontSideBackground = new Color(frontSideBackgroundRGB);

        String reverseSideFontFamily =
                preferences.get("REVERSESIDE_FONT_FAMILY", "Default");
        int reverseSideFontStyle =
                preferences.getInt("REVERSESIDE_FONT_STYLE", Font.PLAIN);
        int reverseSizeFontSize =
                preferences.getInt("REVERSESIDE_FONT_SIZE", 12);
        reverseSideFont = new Font(reverseSideFontFamily,
                reverseSideFontStyle, reverseSizeFontSize);
        int reverseSideForegroundRGB = preferences.getInt(
                "REVERSESIDE_FOREGROUND", Color.BLACK.getRGB());
        reverseSideForeground = new Color(reverseSideForegroundRGB);
        int reverseSideBackgroundRGB = preferences.getInt(
                "REVERSESIDE_BACKGROUND", Color.WHITE.getRGB());
        reverseSideBackground = new Color(reverseSideBackgroundRGB);
        repeatByTyping = preferences.getBoolean("REPEAT_BY_TYPING", false);
        keepNewCardDialogOpen =
                preferences.getBoolean("KEEP_NEW_CARD_WINDOW_OPEN", false);
        String toolbarConstraints =
                preferences.get("TOOLBAR_CONSTRAINTS", "North");
        boolean toolbarVisible =
                preferences.getBoolean("TOOLBAR_VISIBLE", true);
        int sideInt = preferences.getInt("FONT_DIALOG_SIDE", 0);
        fontDialogSide = Card.Element.values()[sideInt];

        // init some vars
        String versionString = STRINGS.getString("Pauker_Version");
        titleString = MessageFormat.format(
                STRINGS.getString("ProgramTitle"), versionString);
        ringTone = Applet.newAudioClip(
                getClass().getResource("/pauker/sounds/phone.wav"));
        defautToolkit = Toolkit.getDefaultToolkit();

        initComponents();

        // place toolbar at saved position
        if (toolbarConstraints.equals(BorderLayout.NORTH)) {
            getContentPane().add(toolBar, BorderLayout.NORTH);
        } else if (toolbarConstraints.equals(BorderLayout.WEST)) {
            toolBar.setOrientation(JToolBar.VERTICAL);
            getContentPane().add(toolBar, BorderLayout.WEST);
        } else if (toolbarConstraints.equals(BorderLayout.SOUTH)) {
            getContentPane().add(toolBar, BorderLayout.SOUTH);
        } else if (toolbarConstraints.equals(BorderLayout.EAST)) {
            toolBar.setOrientation(JToolBar.VERTICAL);
            getContentPane().add(toolBar, BorderLayout.EAST);
        }
        // toolbar visibility
        showToolBarMenuItem.setSelected(toolbarVisible);

        // our own version of JList
        batchListCellRenderer = new BatchListCellRenderer(
                this, batchList.getSelectionBackground());
        batchListModel = new BatchListModel();
        batchList.setCellRenderer(batchListCellRenderer);
        batchList.setModel(batchListModel);

        setIconImage(new ImageIcon(
                getClass().getResource("/pauker/icons/icon.png")).getImage());
        currentTitle = titleString;

        // set Mnemonics
        fileMenu.setMnemonic(STRINGS.getString("File_Mnemonic").charAt(0));
        extraMenu.setMnemonic(STRINGS.getString("Extra_Mnemonic").charAt(0));
        helpMenu.setMnemonic(STRINGS.getString("Help_Mnemonic").charAt(0));

        // we have our own FocusTraversalPolicy
        setFocusTraversalPolicy(new MyFocusTraversalPolicy());

        statisticPanel.setPaukerFrame(this);
        showTimerCheckBox.setSelected(showTimer);

        // init card layouts
        showPanel(cardPanel, "overviewPanel");
        showPanel(lessonPanel, "aboutPanel");

        batchPanelBorder = (TitledBorder) batchPanel.getBorder();

        // !!! IMPORTANT !!!
        // call setLineWrap() only after creating batchListCellRenderer
        // otherwise we get NPE's
        setLineWrap(lineWrapping);

        Dimension smallDimension = new Dimension(10, 10);
        aboutPanel.setPreferredSize(smallDimension);
        batchListPanel.setPreferredSize(smallDimension);

        // set minimun height
        Dimension statisticPanelSize = statisticPanel.getSize();
        statisticPanelSize.width = 10;
        statisticPanel.setMinimumSize(statisticPanelSize);

        aboutDocument = aboutTextArea.getDocument();
        aboutDocument.addDocumentListener(this);

        xmlFileFilter = new FileFilter() {

            public boolean accept(File file) {
                if (file.isDirectory()) {
                    return true;
                }
                String path = file.getPath().toLowerCase();
                return (path.endsWith(".xml.gz") ||
                        path.endsWith(".pau.gz") ||
                        path.endsWith(".pau"));
            }

            public String getDescription() {
                return STRINGS.getString("PaukerFileFilter_Description");
            }
        };
        csvFileFilter = new FileFilter() {

            public boolean accept(File file) {
                if (file.isDirectory()) {
                    return true;
                }
                return file.getPath().toLowerCase().endsWith(".csv");
            }

            public String getDescription() {
                return STRINGS.getString("CSVFileFilter_Description");
            }
        };

        openFileDialog = new OpenFileDialog(this, xmlFileFilter, csvFileFilter);
        int openFileDialogWidth =
                preferences.getInt("OPEN_FILE_DIALOG_WIDTH", -1);
        int openFileDialogHeigth =
                preferences.getInt("OPEN_FILE_DIALOG_HEIGTH", -1);
        if ((openFileDialogWidth != -1) && (openFileDialogHeigth != -1)) {
            openFileDialog.setSize(openFileDialogWidth, openFileDialogHeigth);
        }

        saveFileChooser = new JFileChooser();
        saveFileChooser.addChoosableFileFilter(xmlFileFilter);
        saveFileChooser.addChoosableFileFilter(csvFileFilter);
        saveFileChooser.setFileFilter(xmlFileFilter);
        FileChooserAccessory fileChooserAccessory = new FileChooserAccessory();
        saveFileChooser.setAccessory(fileChooserAccessory);
        saveFileChooser.addPropertyChangeListener(fileChooserAccessory);
        saveFileChooser.setFileView(new PaukerFileView());

        // activate help
        try {
            ClassLoader classLoader =
                    Thread.currentThread().getContextClassLoader();
            URL helpSetURL =
                    HelpSet.findHelpSet(classLoader, "pauker/help/HelpSet.hs");
            HelpSet helpSet = new HelpSet(classLoader, helpSetURL);
            helpbroker = helpSet.createHelpBroker();
        } catch (Exception exception) {
            logger.log(Level.SEVERE, "could not init Java help", exception);
        }

        Action focusTypingOKButtonAction = new AbstractAction() {

            public void actionPerformed(ActionEvent event) {
                typingOKButton.requestFocusInWindow();
            }
        };

        KeyStroke tabKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);

        InputMap inputMap = repeatingInsertTextArea.getInputMap();
        inputMap.put(tabKeyStroke, "tabAction");
        ActionMap actionMap = repeatingInsertTextArea.getActionMap();
        actionMap.put("tabAction", focusTypingOKButtonAction);

        // assemble reasonable sizes of statistics panel
        Dimension preferredStatisticSize = statisticPanel.getPreferredSize();
        statisticPanel.setMinimumSize(preferredStatisticSize);
        Dimension newSize = new Dimension(preferredStatisticSize);
        newSize.height = 220;
        statisticPanel.setPreferredSize(newSize);

        expirationTimer.start();

        pack();

        if (dividerLocation != -1) {
            int minimumDividerLocation = splitPane.getMinimumDividerLocation();
            int maximumDividerLocation = splitPane.getMaximumDividerLocation();
            if ((0 < dividerLocation) &&
                    (dividerLocation < minimumDividerLocation)) {
                splitPane.setDividerLocation(minimumDividerLocation);
            } else if ((maximumDividerLocation < dividerLocation)) {
                splitPane.setDividerLocation(maximumDividerLocation);
            } else {
                splitPane.setDividerLocation(dividerLocation);
            }
        }
    }

    /**
     * returns the orientation of the split between the card sides
     * @return the orientation of the split between the card sides
     */
00504     public int getSplitOrientation() {
        return splitOrientation;
    }

    /**
     * sets the orientation of the split between the card sides
     * @param splitOrientation the orientation of the split between the card
     * sides
     */
00513     public void setSplitOrientation(int splitOrientation) {
        this.splitOrientation = splitOrientation;
    }

    /**
     * returns true, if automatic line wrapping should be used, false otherwise
     * @return true, if automatic line wrapping should be used, false otherwise
     */
00521     public boolean isLineWrapping() {
        return lineWrapping;
    }

    /**
     * determines if automatic line wrapping should be used
     * @param lineWrapping true, if automatic line wrapping should be used,
     * false otherwise
     */
00530     public void setLineWrapping(boolean lineWrapping) {
        this.lineWrapping = lineWrapping;
    }

    /**
     * opens a URL via BrowserLauncher in the favorite browser of the user
     * @param url
     */
00538     public static void openUrlInBrowser(String url) {
        try {
            List browserList = Arrays.asList(new Object[]{
                        "FireFox", "Konqueror", "Mozilla", "Opera"
                    });
            BrowserLauncher launcher = new BrowserLauncher();
            launcher.openURLinBrowser(browserList, url);
        } catch (BrowserLaunchingInitializingException ex) {
            logger.log(Level.SEVERE, "could not open URL in browser", ex);
        } catch (UnsupportedOperatingSystemException ex) {
            logger.log(Level.SEVERE, "could not open URL in browser", ex);
        }
    }

    /**
     * executes a lazy string change on a text field (i.e. the string is not
     * changed if the new text is equal)
     * @param textField the text field
     * @param newText the new text
     */
00558     public static void lazyStringChange(JTextField textField, String newText) {
        if (!textField.getText().equals(newText)) {
            textField.setText(newText);
        }
    }

    /**
     * executes a lazy string change on a label (i.e. the string is not changed
     * if the new text is equal)
     * @param label the label
     * @param newText the new text
     */
00570     public static void lazyStringChange(JLabel label, String newText) {
        if (!label.getText().equals(newText)) {
            label.setText(newText);
        }
    }

    /** returns the currently active/loaded lesson
     * @return the currently active/loaded lesson
     */
00579     public Lesson getCurrentLesson() {
        return currentLesson;
    }

    /**
     * fills a text area with a card side
     * @param cardSide the card side
     * @param textComponent the text component
     * @param resetCaret if true, the caret is set to position 0
     */
00589     public static void fillTextComponentWithCardSide(CardSide cardSide,
            JTextComponent textComponent, boolean resetCaret) {

        // content change (never lazy)
        textComponent.setText(cardSide.getText());
        if (resetCaret) {
            textComponent.setCaretPosition(0);
        }

        setFontAndOrientation(cardSide, textComponent);

        // lazy foregroundColor change
        Color foregroundColor = cardSide.getForegroundColor();
        if (foregroundColor == null) {
            foregroundColor = Color.black;
        }
        Color oldForegroundColor = textComponent.getForeground();
        if (!oldForegroundColor.equals(foregroundColor)) {
            textComponent.setForeground(foregroundColor);
        }

        // lazy backgroundColor change
        Color backgroundColor = cardSide.getBackgroundColor();
        if (backgroundColor == null) {
            backgroundColor = Color.white;
        }
        Color oldBackgroundColor = textComponent.getBackground();
        if (!oldBackgroundColor.equals(backgroundColor)) {
            textComponent.setBackground(backgroundColor);
        }
    }

    private static void setFontAndOrientation(
            CardSide cardSide, JTextComponent textComponent) {
        // lazy font change
        Font font = cardSide.getFont();
        if (font == null) {
            font = PaukerFrame.DEFAULT_FONT;
        }
        Font oldFont = textComponent.getFont();
        if (!oldFont.equals(font)) {
            textComponent.setFont(font);
        }

        // lazy orientation change
        ComponentOrientation orientation = cardSide.getOrientation();
        if (orientation == null) {
            orientation = ComponentOrientation.LEFT_TO_RIGHT;
        }
        ComponentOrientation oldOrientation =
                textComponent.getComponentOrientation();
        if (!oldOrientation.equals(orientation)) {
            textComponent.setComponentOrientation(orientation);
        }
    }

    /** inserts a <code>newCard</code> into the current lesson
     * @param newCard the new card
     */
00648     public void addCard(Card newCard) {
        currentLesson.addCard(newCard);

        // update statistics
        statisticPanel.setLesson(currentLesson);

        // update batch list
        if (batchList.isShowing() &&
                ((loadedBatch == currentLesson.getSummaryBatch()) ||
                (loadedBatch == currentLesson.getUnlearnedBatch()))) {
            batchListModel.cardAdded();
            updateBatchListButtons();
            batchList.ensureIndexIsVisible(batchListModel.getSize() - 1);
        }

        // update searchEngine
        searchEngine.index(newCard);

        learnNewCardsButton.setEnabled(true);
        searchButton.setEnabled(true);
        boolean hasSeveralCards = loadedBatch.getNumberOfCards() > 0;
        sortButton.setEnabled(hasSeveralCards);
        randomizeButton.setEnabled(hasSeveralCards);

        somethingHasChanged();
    }

    /**
     * must be called when something changed at the current lesson that must be
     * saved before exiting Pauker
     */
00679     public void somethingHasChanged() {
        if (!somethingChanged) {
            somethingChanged = true;
            currentTitle = '*' + currentTitle;
            setTitle(currentTitle);
            if (Pauker.getLearningPhase() == Pauker.LearningPhase.NOTHING) {
                saveButton.setEnabled(true);
                saveMenuItem.setEnabled(true);
            }
        }
    }

    /**
     * searches a certain string pattern on a card side
     * @param pattern the pattern to search for
     * @param cardSide the card side to search
     * @param matchCase if true, the case of the pattern is considered
     * @return
     */
00698     public boolean search(String pattern, Card.Element cardSide,
            boolean matchCase) {
        searchPatternLength = pattern.length();
        boolean patternFound = loadedBatch.search(pattern, matchCase, cardSide);
        if (patternFound) {
            scrollToCurrentSearchHit();
        }
        batchPanel.repaint();
        return patternFound;
    }

    /**
     * returns the length of the current search pattern
     * @return the length of the current search pattern
     */
00713     public int getSearchPatternLength() {
        return searchPatternLength;
    }

    /**
     * returns the current search hit
     * @return the current search hit
     */
00721     public SearchHit getCurrentSearchHit() {
        if (loadedBatch == null) {
            return null;
        }
        return loadedBatch.getCurrentSearchHit();
    }

    /**
     * continues searching
     * @param forward if true, searching continues forwards, otherwise backwards
     * @return true, if a search hit was found, false otherwise
     */
00733     public boolean continueSearch(boolean forward) {
        if (loadedBatch.continueSearch(forward)) {
            scrollToCurrentSearchHit();
            batchPanel.repaint();
            return true;
        }
        return false;
    }

    private void scrollToCurrentSearchHit() {
        SearchHit currentSearchHit = loadedBatch.getCurrentSearchHit();
        if (currentSearchHit != null) {
            Card card = currentSearchHit.getCard();
            int index = loadedBatch.indexOf(card);
            batchList.ensureIndexIsVisible(index);
        }
    }

    /**
     * sets the card side to search for
     * @param cardSide the card side to search for
     */
00755     public void setSearchCardSide(Card.Element cardSide) {
        if (loadedBatch.setSearchCardSide(cardSide)) {
            scrollToCurrentSearchHit();
            batchPanel.repaint();
        }
    }

    /**
     * defines if searching should take the case into consideration
     * @param matchCase if true, searching takes the case into consideration,
     * if false, searching ignores the case 
     */
00767     public void setMatchCase(boolean matchCase) {
        if (loadedBatch.setMatchCase(matchCase)) {
            scrollToCurrentSearchHit();
            batchPanel.repaint();
        }
    }

    /**
     * stops searching
     */
00777     public void stopSearching() {
        if (loadedBatch != null) {
            loadedBatch.stopSearching();
            batchPanel.repaint();
        }
    }

    /**
     * loads a batch
     * @param batch the batch to load
     */
00788     public void loadBatch(Batch batch) {

        showPanel(lessonPanel, "batchPanel");

        // set batch list border title
        if (batch == currentLesson.getSummaryBatch()) {
            batchPanelBorder.setTitle(STRINGS.getString("Summary"));
        } else if (batch == currentLesson.getUnlearnedBatch()) {
            batchPanelBorder.setTitle(STRINGS.getString("Not_learned"));
        } else if (batch instanceof LongTermBatch) {
            LongTermBatch longTermBatch = (LongTermBatch) batch;
            int batchNumber = longTermBatch.getBatchNumber();
            String title = STRINGS.getString("Batch") + ' ' + (batchNumber + 1);
            batchPanelBorder.setTitle(title);
        } else {
            throw new RuntimeException("unknown batch type: " + batch);
        }
        batchPanel.repaint();

        // apply current search setting to new batch
        if (loadedBatch != null) {
            String searchPattern = loadedBatch.getSearchPattern();
            if ((searchPattern == null) || (searchPattern.length() == 0)) {
                batch.stopSearching();
            } else {
                boolean batchMatchCase = loadedBatch.isMatchCase();
                Card.Element searchSide = loadedBatch.getSearchSide();
                batch.search(searchPattern, batchMatchCase, searchSide);
            }
        }

        loadedBatch = batch;

        // refill list
        batchListModel.setBatch(batch);
        batchList.clearSelection();

        updateBatchListButtons();
    }

    public void changedUpdate(DocumentEvent documentEvent) {
        this.textChanged(documentEvent);
    }

    public void insertUpdate(DocumentEvent documentEvent) {
        this.textChanged(documentEvent);
    }

    public void removeUpdate(DocumentEvent documentEvent) {
        this.textChanged(documentEvent);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
00846     private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        sortingMenuHeaderPanel = new javax.swing.JPanel();
        sortingLabel = new javax.swing.JLabel();
        sortingPopupMenu = new javax.swing.JPopupMenu();
        jSeparator1 = new javax.swing.JSeparator();
        ascendingMenu = new javax.swing.JMenu();
        ascendingFrontMenuItem = new javax.swing.JMenuItem();
        ascendingBackMenuItem = new javax.swing.JMenuItem();
        ascendingBatchMenuItem = new javax.swing.JMenuItem();
        ascendingLearnedMenuItem = new javax.swing.JMenuItem();
        ascendingExpiredMenuItem = new javax.swing.JMenuItem();
        ascendingRepeatMenuItem = new javax.swing.JMenuItem();
        descendingMenu = new javax.swing.JMenu();
        descendingFrontMenuItem = new javax.swing.JMenuItem();
        descendingBackMenuItem = new javax.swing.JMenuItem();
        descendingBatchMenuItem = new javax.swing.JMenuItem();
        descendingLearnedMenuItem = new javax.swing.JMenuItem();
        descendingExpiredMenuItem = new javax.swing.JMenuItem();
        descendingRepeatMenuItem = new javax.swing.JMenuItem();
        learningMenuHeaderPanel = new javax.swing.JPanel();
        learningLabel = new javax.swing.JLabel();
        learningPopupMenu = new javax.swing.JPopupMenu();
        jSeparator5 = new javax.swing.JSeparator();
        remeberMenuItem = new javax.swing.JMenuItem();
        typeMenuItem = new javax.swing.JMenuItem();
        questionPanel = new javax.swing.JPanel();
        questionLabel = new javax.swing.JLabel();
        explanationLabel = new javax.swing.JLabel();
        toolBarPopupMenu = new javax.swing.JPopupMenu();
        hideToolBarMenuItem = new javax.swing.JMenuItem();
        toolBar = new javax.swing.JToolBar();
        newButton = new javax.swing.JButton();
        openButton = new javax.swing.JButton();
        saveButton = new javax.swing.JButton();
        splitPane = new javax.swing.JSplitPane();
        statisticPanel = new pauker.program.gui.swing.StatisticPanel();
        cardPanel = new javax.swing.JPanel();
        overviewPanel = new javax.swing.JPanel();
        buttonPanel = new javax.swing.JPanel();
        addCardButton = new javax.swing.JButton();
        learnNewCardsButton = new javax.swing.JButton();
        repeatCardsButton = new javax.swing.JButton();
        lessonPanel = new javax.swing.JPanel();
        aboutPanel = new javax.swing.JPanel();
        aboutScrollPane = new javax.swing.JScrollPane();
        aboutTextArea = new javax.swing.JTextArea();
        batchPanel = new javax.swing.JPanel();
        cardsButtonPanel = new javax.swing.JPanel();
        editCardButton = new javax.swing.JButton();
        fontButton = new javax.swing.JButton();
        learningMethodButton = new javax.swing.JButton();
        upButton = new javax.swing.JButton();
        downButton = new javax.swing.JButton();
        sortButton = new javax.swing.JButton();
        randomizeButton = new javax.swing.JButton();
        instantRepeatButton = new javax.swing.JButton();
        forgetButton = new javax.swing.JButton();
        removeCardButton = new javax.swing.JButton();
        searchButton = new javax.swing.JButton();
        batchListPanel = new javax.swing.JPanel();
        batchListScrollPane = new javax.swing.JScrollPane();
        batchList = new pauker.program.gui.swing.UpdateLayoutList();
        learningPanel = new javax.swing.JPanel();
        learningCardPanel = new javax.swing.JPanel();
        USTMLearningPanel = new javax.swing.JPanel();
        ustmSplitPane = new javax.swing.JSplitPane();
        ustmFrontSidePanel = new javax.swing.JPanel();
        ustmFrontSideLabel = new javax.swing.JLabel();
        ustmFrontSideScrollPane = new javax.swing.JScrollPane();
        ustmFrontSideTextArea = new javax.swing.JTextArea();
        ustmReverseSidePanel = new javax.swing.JPanel();
        ustmReverseSideLabel = new javax.swing.JLabel();
        ustmReverseSideScrollPane = new javax.swing.JScrollPane();
        ustmReverseSideTextArea = new javax.swing.JTextArea();
        jSeparator2 = new javax.swing.JSeparator();
        editWhileMemorizingButton = new javax.swing.JButton();
        switchUSTMLayoutButton = new javax.swing.JButton();
        removeUstmButton = new javax.swing.JButton();
        nextNewCardButton = new javax.swing.JButton();
        repeatingPanel = new javax.swing.JPanel();
        repeatingSplitPane = new javax.swing.JSplitPane();
        repeatingFrontSidePanel = new javax.swing.JPanel();
        repeatingCardFrontSideLabel = new javax.swing.JLabel();
        repeatingFrontSideScrollPane = new javax.swing.JScrollPane();
        repeatingFrontSideTextArea = new javax.swing.JTextArea();
        repeatingReverseSidePanel = new javax.swing.JPanel();
        repeatingCardReverseSideLabel = new javax.swing.JLabel();
        repeatingCardPanel = new javax.swing.JPanel();
        repeatingAskPanel = new javax.swing.JPanel();
        repeatingHintLabel = new javax.swing.JLabel();
        repeatingShowPanel = new javax.swing.JPanel();
        repeatingReverseSideScrollPane = new javax.swing.JScrollPane();
        repeatingReverseSideTextArea = new javax.swing.JTextArea();
        repeatingInsertPanel = new javax.swing.JPanel();
        repeatingInsertScrollPane = new javax.swing.JScrollPane();
        repeatingInsertTextArea = new javax.swing.JTextArea();
        jSeparator3 = new javax.swing.JSeparator();
        editWhileRepeatingButton = new javax.swing.JButton();
        switchRepeatingLayoutButton = new javax.swing.JButton();
        removeRepeatingButton = new javax.swing.JButton();
        repeatingButtonCardPanel = new javax.swing.JPanel();
        questionButtonPanel = new javax.swing.JPanel();
        didYouKnowLabel = new javax.swing.JLabel();
        repeatingYesButton = new javax.swing.JButton();
        repeatingNoButton = new javax.swing.JButton();
        showMeButtonPanel = new javax.swing.JPanel();
        showMeButton = new javax.swing.JButton();
        typingOKPanel = new javax.swing.JPanel();
        insertReverseSideLabel = new javax.swing.JLabel();
        typingOKButton = new javax.swing.JButton();
        waitForUSTMPanel = new javax.swing.JPanel();
        waitForUSTMLabel = new javax.swing.JLabel();
        repeatUSTMButton = new javax.swing.JButton();
        waitForSTMPanel = new javax.swing.JPanel();
        waitForSTMLabel = new javax.swing.JLabel();
        repeatSTMButton = new javax.swing.JButton();
        transitionPanel = new javax.swing.JPanel();
        transitoinIconLabel = new javax.swing.JLabel();
        transitionExplanationLabel = new javax.swing.JLabel();
        transitionOKButton = new javax.swing.JButton();
        typingErrorPanel = new javax.swing.JPanel();
        infoLabel = new javax.swing.JLabel();
        typingErrorSplitPane = new javax.swing.JSplitPane();
        inputPanel = new javax.swing.JPanel();
        inputLabel = new javax.swing.JLabel();
        inputScrollPane = new javax.swing.JScrollPane();
        inputTextArea = new javax.swing.JTextArea();
        reversePanel = new javax.swing.JPanel();
        reverseLabel = new javax.swing.JLabel();
        reverseScrollPane = new javax.swing.JScrollPane();
        reverseTextArea = new javax.swing.JTextArea();
        editTypingErrorButton = new javax.swing.JButton();
        moveBackButton = new javax.swing.JButton();
        ignoreErrorButton = new javax.swing.JButton();
        learningStatusPanel = new javax.swing.JPanel();
        timerPanel = new javax.swing.JPanel();
        pauseLearningToggleButton = new javax.swing.JToggleButton();
        cancelLearningButton = new javax.swing.JButton();
        showTimerCheckBox = new javax.swing.JCheckBox();
        timerCardPanel = new javax.swing.JPanel();
        fullTimerPanel = new javax.swing.JPanel();
        timerGridPanel1 = new javax.swing.JPanel();
        ustmTimerLabel = new javax.swing.JLabel();
        stmTimerLabel = new javax.swing.JLabel();
        timerGridPanel2 = new javax.swing.JPanel();
        ustmTimerProgressBar = new javax.swing.JProgressBar();
        stmTimerProgressBar = new javax.swing.JProgressBar();
        noTimerPanel = new javax.swing.JPanel();
        cancelRepeatingPanel = new javax.swing.JPanel();
        cancelRepeatingButton = new javax.swing.JButton();
        mainMenuBar = new javax.swing.JMenuBar();
        fileMenu = new javax.swing.JMenu();
        newMenuItem = new javax.swing.JMenuItem();
        openMenuItem = new javax.swing.JMenuItem();
        importMenuItem = new javax.swing.JMenuItem();
        recentFilesMenu = new javax.swing.JMenu();
        separator1 = new javax.swing.JSeparator();
        saveMenuItem = new javax.swing.JMenuItem();
        saveAsMenuItem = new javax.swing.JMenuItem();
        separator4 = new javax.swing.JSeparator();
        resetMenuItem = new javax.swing.JMenuItem();
        flipCardSidesMenuItem = new javax.swing.JMenuItem();
        separator2 = new javax.swing.JSeparator();
        exitMenuItem = new javax.swing.JMenuItem();
        extraMenu = new javax.swing.JMenu();
        addCardsMenuitem = new javax.swing.JMenuItem();
        configureMenuItem = new javax.swing.JMenuItem();
        showToolBarMenuItem = new javax.swing.JCheckBoxMenuItem();
        helpMenu = new javax.swing.JMenu();
        helpMenuItem = new javax.swing.JMenuItem();
        jSeparator4 = new javax.swing.JSeparator();
        aboutLessonMenuItem = new javax.swing.JMenuItem();
        aboutProgramMenuItem = new javax.swing.JMenuItem();
        donateMenuItem = new javax.swing.JMenuItem();

        sortingMenuHeaderPanel.setLayout(new java.awt.GridBagLayout());

        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("pauker/Strings"); // NOI18N
        sortingLabel.setText(bundle.getString("Sorting")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(2, 10, 2, 10);
        sortingMenuHeaderPanel.add(sortingLabel, gridBagConstraints);

        sortingPopupMenu.add(sortingMenuHeaderPanel);
        sortingPopupMenu.setName("sortingPopupMenu"); // NOI18N
        sortingPopupMenu.add(jSeparator1);

        ascendingMenu.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/ascending.png"))); // NOI18N
        ascendingMenu.setText(bundle.getString("Sort_Ascending")); // NOI18N

        ascendingFrontMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/frontSide.png"))); // NOI18N
        ascendingFrontMenuItem.setText(bundle.getString("By_FrontSide")); // NOI18N
        ascendingFrontMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                ascendingFrontMenuItemActionPerformed(evt);
            }
        });
        ascendingMenu.add(ascendingFrontMenuItem);

        ascendingBackMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/reverseSide.png"))); // NOI18N
        ascendingBackMenuItem.setText(bundle.getString("By_ReverseSide")); // NOI18N
        ascendingBackMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                ascendingBackMenuItemActionPerformed(evt);
            }
        });
        ascendingMenu.add(ascendingBackMenuItem);

        ascendingBatchMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/batchAscending.png"))); // NOI18N
        ascendingBatchMenuItem.setText(bundle.getString("By_Batchnumber")); // NOI18N
        ascendingBatchMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                ascendingBatchMenuItemActionPerformed(evt);
            }
        });
        ascendingMenu.add(ascendingBatchMenuItem);

        ascendingLearnedMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/icon.png"))); // NOI18N
        ascendingLearnedMenuItem.setText(bundle.getString("By_LearnedDate")); // NOI18N
        ascendingLearnedMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                ascendingLearnedMenuItemActionPerformed(evt);
            }
        });
        ascendingMenu.add(ascendingLearnedMenuItem);

        ascendingExpiredMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/expired.png"))); // NOI18N
        ascendingExpiredMenuItem.setText(bundle.getString("By_Expiration")); // NOI18N
        ascendingExpiredMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                ascendingExpiredMenuItemActionPerformed(evt);
            }
        });
        ascendingMenu.add(ascendingExpiredMenuItem);

        ascendingRepeatMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/brain_and_key.png"))); // NOI18N
        ascendingRepeatMenuItem.setText(bundle.getString("By_Repeating_Method")); // NOI18N
        ascendingRepeatMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                ascendingRepeatMenuItemActionPerformed(evt);
            }
        });
        ascendingMenu.add(ascendingRepeatMenuItem);

        sortingPopupMenu.add(ascendingMenu);

        descendingMenu.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/descending.png"))); // NOI18N
        descendingMenu.setText(bundle.getString("Sort_Descending")); // NOI18N
        descendingMenu.setName("descendingMenu"); // NOI18N

        descendingFrontMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/frontSide.png"))); // NOI18N
        descendingFrontMenuItem.setText(bundle.getString("By_FrontSide")); // NOI18N
        descendingFrontMenuItem.setName("descendingFrontMenuItem"); // NOI18N
        descendingFrontMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                descendingFrontMenuItemActionPerformed(evt);
            }
        });
        descendingMenu.add(descendingFrontMenuItem);

        descendingBackMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/reverseSide.png"))); // NOI18N
        descendingBackMenuItem.setText(bundle.getString("By_ReverseSide")); // NOI18N
        descendingBackMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                descendingBackMenuItemActionPerformed(evt);
            }
        });
        descendingMenu.add(descendingBackMenuItem);

        descendingBatchMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/batchDescending.png"))); // NOI18N
        descendingBatchMenuItem.setText(bundle.getString("By_Batchnumber")); // NOI18N
        descendingBatchMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                descendingBatchMenuItemActionPerformed(evt);
            }
        });
        descendingMenu.add(descendingBatchMenuItem);

        descendingLearnedMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/icon.png"))); // NOI18N
        descendingLearnedMenuItem.setText(bundle.getString("By_LearnedDate")); // NOI18N
        descendingLearnedMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                descendingLearnedMenuItemActionPerformed(evt);
            }
        });
        descendingMenu.add(descendingLearnedMenuItem);

        descendingExpiredMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/expired.png"))); // NOI18N
        descendingExpiredMenuItem.setText(bundle.getString("By_Expiration")); // NOI18N
        descendingExpiredMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                descendingExpiredMenuItemActionPerformed(evt);
            }
        });
        descendingMenu.add(descendingExpiredMenuItem);

        descendingRepeatMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/brain_and_key.png"))); // NOI18N
        descendingRepeatMenuItem.setText(bundle.getString("By_Repeating_Method")); // NOI18N
        descendingRepeatMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                descendingRepeatMenuItemActionPerformed(evt);
            }
        });
        descendingMenu.add(descendingRepeatMenuItem);

        sortingPopupMenu.add(descendingMenu);

        learningMenuHeaderPanel.setLayout(new java.awt.GridBagLayout());

        learningLabel.setText(bundle.getString("Repeating_Method")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(2, 10, 2, 10);
        learningMenuHeaderPanel.add(learningLabel, gridBagConstraints);

        learningPopupMenu.add(learningMenuHeaderPanel);
        learningPopupMenu.add(jSeparator5);

        remeberMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/smallbrain.png"))); // NOI18N
        remeberMenuItem.setText(bundle.getString("Repeat_By_Remembering")); // NOI18N
        remeberMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                remeberMenuItemActionPerformed(evt);
            }
        });
        learningPopupMenu.add(remeberMenuItem);

        typeMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/key_enter.png"))); // NOI18N
        typeMenuItem.setText(bundle.getString("Repeat_By_Typing")); // NOI18N
        typeMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                typeMenuItemActionPerformed(evt);
            }
        });
        learningPopupMenu.add(typeMenuItem);

        questionPanel.setLayout(new java.awt.GridBagLayout());

        questionLabel.setText("Question");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        questionPanel.add(questionLabel, gridBagConstraints);

        explanationLabel.setFont(explanationLabel.getFont().deriveFont(explanationLabel.getFont().getStyle() & ~java.awt.Font.BOLD, explanationLabel.getFont().getSize()-1));
        explanationLabel.setText("Explanation");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(10, 0, 0, 0);
        questionPanel.add(explanationLabel, gridBagConstraints);

        hideToolBarMenuItem.setText(bundle.getString("Hide_ToolBar")); // NOI18N
        hideToolBarMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                hideToolBarMenuItemActionPerformed(evt);
            }
        });
        toolBarPopupMenu.add(hideToolBarMenuItem);

        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        setTitle(titleString);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                exitForm(evt);
            }
            public void windowOpened(java.awt.event.WindowEvent evt) {
                formWindowOpened(evt);
            }
        });

        toolBar.setComponentPopupMenu(toolBarPopupMenu);
        toolBar.setName(bundle.getString("Pauker_Toolbar")); // NOI18N

        newButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/filenew_big.png"))); // NOI18N
        newButton.setToolTipText(bundle.getString("JPauker.newMenuItem.text")); // NOI18N
        newButton.setFocusPainted(false);
        newButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
        newButton.setName("newButton"); // NOI18N
        newButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newButtonActionPerformed(evt);
            }
        });
        toolBar.add(newButton);

        openButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/fileopen_big.png"))); // NOI18N
        openButton.setToolTipText(bundle.getString("JPauker.openMenuItem.text")); // NOI18N
        openButton.setFocusPainted(false);
        openButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
        openButton.setName("openButton"); // NOI18N
        openButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openButtonActionPerformed(evt);
            }
        });
        toolBar.add(openButton);

        saveButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/filesave_big.png"))); // NOI18N
        saveButton.setToolTipText(bundle.getString("JPauker.saveMenuItem.text")); // NOI18N
        saveButton.setEnabled(false);
        saveButton.setFocusPainted(false);
        saveButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
        saveButton.setName("saveButton"); // NOI18N
        saveButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveButtonActionPerformed(evt);
            }
        });
        toolBar.add(saveButton);

        getContentPane().add(toolBar, java.awt.BorderLayout.NORTH);

        splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        splitPane.setContinuousLayout(true);
        splitPane.setName("splitPane"); // NOI18N
        splitPane.setOneTouchExpandable(true);
        splitPane.setLeftComponent(statisticPanel);

        cardPanel.setLayout(new java.awt.CardLayout());

        overviewPanel.setLayout(new java.awt.GridBagLayout());

        buttonPanel.setLayout(new java.awt.GridBagLayout());

        addCardButton.setFont(addCardButton.getFont().deriveFont(addCardButton.getFont().getStyle() & ~java.awt.Font.BOLD, addCardButton.getFont().getSize()-1));
        addCardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/newCard.gif"))); // NOI18N
        addCardButton.setText(bundle.getString("Add_Card")); // NOI18N
        addCardButton.setFocusPainted(false);
        addCardButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        addCardButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        addCardButton.setName("addCardButton"); // NOI18N
        addCardButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/newCard_Animated.gif"))); // NOI18N
        addCardButton.setRolloverSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/newCard_Animated.gif"))); // NOI18N
        addCardButton.setSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/newCard_Animated.gif"))); // NOI18N
        addCardButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        addCardButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addCardButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 1.0;
        buttonPanel.add(addCardButton, gridBagConstraints);

        learnNewCardsButton.setFont(learnNewCardsButton.getFont().deriveFont(learnNewCardsButton.getFont().getStyle() & ~java.awt.Font.BOLD, learnNewCardsButton.getFont().getSize()-1));
        learnNewCardsButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/learn.png"))); // NOI18N
        learnNewCardsButton.setText(bundle.getString("Learn_New_Cards")); // NOI18N
        learnNewCardsButton.setEnabled(false);
        learnNewCardsButton.setFocusPainted(false);
        learnNewCardsButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        learnNewCardsButton.setName("learnNewCardsButton"); // NOI18N
        learnNewCardsButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        learnNewCardsButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                learnNewCardsButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
        buttonPanel.add(learnNewCardsButton, gridBagConstraints);

        repeatCardsButton.setFont(repeatCardsButton.getFont().deriveFont(repeatCardsButton.getFont().getStyle() & ~java.awt.Font.BOLD, repeatCardsButton.getFont().getSize()-1));
        repeatCardsButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/repeat.png"))); // NOI18N
        repeatCardsButton.setText(bundle.getString("Repeat_Expired_Cards")); // NOI18N
        repeatCardsButton.setEnabled(false);
        repeatCardsButton.setFocusPainted(false);
        repeatCardsButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        repeatCardsButton.setName("repeatCardsButton"); // NOI18N
        repeatCardsButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        repeatCardsButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                repeatCardsButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
        buttonPanel.add(repeatCardsButton, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(12, 5, 5, 0);
        overviewPanel.add(buttonPanel, gridBagConstraints);

        lessonPanel.setLayout(new java.awt.CardLayout());

        aboutPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(bundle.getString("Lesson_Description"))); // NOI18N
        aboutPanel.setName("aboutPanel"); // NOI18N
        aboutPanel.setLayout(new java.awt.GridLayout(1, 0));

        aboutScrollPane.setViewportView(aboutTextArea);

        aboutPanel.add(aboutScrollPane);

        lessonPanel.add(aboutPanel, "aboutPanel");

        batchPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(bundle.getString("Summary"))); // NOI18N
        batchPanel.setName("batchPanel"); // NOI18N
        batchPanel.setLayout(new java.awt.GridBagLayout());

        cardsButtonPanel.setLayout(new java.awt.GridBagLayout());

        editCardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/edit.png"))); // NOI18N
        editCardButton.setToolTipText(bundle.getString("Edit_Card")); // NOI18N
        editCardButton.setEnabled(false);
        editCardButton.setFocusPainted(false);
        editCardButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        editCardButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editCardButtonActionPerformed(evt);
            }
        });
        cardsButtonPanel.add(editCardButton, new java.awt.GridBagConstraints());

        fontButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/fonts.png"))); // NOI18N
        fontButton.setToolTipText(bundle.getString("Set_Font")); // NOI18N
        fontButton.setEnabled(false);
        fontButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        fontButton.setName("fontButton"); // NOI18N
        fontButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fontButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
        cardsButtonPanel.add(fontButton, gridBagConstraints);

        learningMethodButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/brain_and_key.png"))); // NOI18N
        learningMethodButton.setToolTipText(bundle.getString("Repeating_Method")); // NOI18N
        learningMethodButton.setEnabled(false);
        learningMethodButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        learningMethodButton.setName("learningMethodButton"); // NOI18N
        learningMethodButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                learningMethodButtonMousePressed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
        cardsButtonPanel.add(learningMethodButton, gridBagConstraints);

        upButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/up.png"))); // NOI18N
        upButton.setToolTipText(bundle.getString("Move_Cards_Up")); // NOI18N
        upButton.setEnabled(false);
        upButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        upButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                upButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 7, 0, 0);
        cardsButtonPanel.add(upButton, gridBagConstraints);

        downButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/down.png"))); // NOI18N
        downButton.setToolTipText(bundle.getString("Move_Cards_Down")); // NOI18N
        downButton.setEnabled(false);
        downButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        downButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                downButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
        cardsButtonPanel.add(downButton, gridBagConstraints);

        sortButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/ascending.png"))); // NOI18N
        sortButton.setToolTipText(bundle.getString("Sorting")); // NOI18N
        sortButton.setEnabled(false);
        sortButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        sortButton.setName("sortButton"); // NOI18N
        sortButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                sortButtonMousePressed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
        cardsButtonPanel.add(sortButton, gridBagConstraints);

        randomizeButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/random.png"))); // NOI18N
        randomizeButton.setToolTipText(bundle.getString("Mix_Batch")); // NOI18N
        randomizeButton.setEnabled(false);
        randomizeButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        randomizeButton.setName("randomizeButton"); // NOI18N
        randomizeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                randomizeButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
        cardsButtonPanel.add(randomizeButton, gridBagConstraints);

        instantRepeatButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/keduca.png"))); // NOI18N
        instantRepeatButton.setToolTipText(bundle.getString("Instant_Repeating")); // NOI18N
        instantRepeatButton.setEnabled(false);
        instantRepeatButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        instantRepeatButton.setName("instantRepeatButton"); // NOI18N
        instantRepeatButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                instantRepeatButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 7, 0, 0);
        cardsButtonPanel.add(instantRepeatButton, gridBagConstraints);

        forgetButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/back.png"))); // NOI18N
        forgetButton.setToolTipText(bundle.getString("Move_Cards_Back_To_Unlearned_Batch")); // NOI18N
        forgetButton.setEnabled(false);
        forgetButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        forgetButton.setName("forgetButton"); // NOI18N
        forgetButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                forgetButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
        cardsButtonPanel.add(forgetButton, gridBagConstraints);

        removeCardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/16x16/remove.png"))); // NOI18N
        removeCardButton.setToolTipText(bundle.getString("Remove_Card")); // NOI18N
        removeCardButton.setEnabled(false);
        removeCardButton.setFocusPainted(false);
        removeCardButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        removeCardButton.setName("removeCardButton"); // NOI18N
        removeCardButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeCardButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
        cardsButtonPanel.add(removeCardButton, gridBagConstraints);

        searchButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/filefind.png"))); // NOI18N
        searchButton.setToolTipText(bundle.getString("Search")); // NOI18N
        searchButton.setEnabled(false);
        searchButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        searchButton.setName("searchButton"); // NOI18N
        searchButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                searchButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(0, 7, 0, 0);
        cardsButtonPanel.add(searchButton, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 5);
        batchPanel.add(cardsButtonPanel, gridBagConstraints);

        batchListPanel.setLayout(new java.awt.GridLayout(1, 0));

        batchList.setName("batchList"); // NOI18N
        batchList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                batchListMouseClicked(evt);
            }
        });
        batchList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                batchListValueChanged(evt);
            }
        });
        batchListScrollPane.setViewportView(batchList);

        batchListPanel.add(batchListScrollPane);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        batchPanel.add(batchListPanel, gridBagConstraints);

        lessonPanel.add(batchPanel, "batchPanel");

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        overviewPanel.add(lessonPanel, gridBagConstraints);

        cardPanel.add(overviewPanel, "overviewPanel");

        learningPanel.setLayout(new java.awt.GridBagLayout());

        learningCardPanel.setLayout(new java.awt.CardLayout());

        USTMLearningPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, bundle.getString("Try_To_Memorize_Card"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Dialog", 0, 11), new java.awt.Color(255, 12, 145))); // NOI18N
        USTMLearningPanel.setLayout(new java.awt.GridBagLayout());

        ustmSplitPane.setResizeWeight(0.5);
        ustmSplitPane.setContinuousLayout(true);

        ustmFrontSidePanel.setLayout(new java.awt.GridBagLayout());

        ustmFrontSideLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        ustmFrontSideLabel.setText(bundle.getString("Card_Frontside")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        ustmFrontSidePanel.add(ustmFrontSideLabel, gridBagConstraints);

        ustmFrontSideScrollPane.setName("ustmFrontSideScrollPane"); // NOI18N

        ustmFrontSideTextArea.setBackground(java.awt.Color.lightGray);
        ustmFrontSideTextArea.setEditable(false);
        ustmFrontSideTextArea.setRows(5);
        ustmFrontSideTextArea.setWrapStyleWord(true);
        ustmFrontSideScrollPane.setViewportView(ustmFrontSideTextArea);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        ustmFrontSidePanel.add(ustmFrontSideScrollPane, gridBagConstraints);

        ustmSplitPane.setLeftComponent(ustmFrontSidePanel);

        ustmReverseSidePanel.setLayout(new java.awt.GridBagLayout());

        ustmReverseSideLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        ustmReverseSideLabel.setText(bundle.getString("Card_ReverseSide")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        ustmReverseSidePanel.add(ustmReverseSideLabel, gridBagConstraints);

        ustmReverseSideScrollPane.setName("ustmReverseSideScrollPane"); // NOI18N

        ustmReverseSideTextArea.setBackground(java.awt.Color.lightGray);
        ustmReverseSideTextArea.setEditable(false);
        ustmReverseSideTextArea.setRows(5);
        ustmReverseSideTextArea.setWrapStyleWord(true);
        ustmReverseSideScrollPane.setViewportView(ustmReverseSideTextArea);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        ustmReverseSidePanel.add(ustmReverseSideScrollPane, gridBagConstraints);

        ustmSplitPane.setRightComponent(ustmReverseSidePanel);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        USTMLearningPanel.add(ustmSplitPane, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
        USTMLearningPanel.add(jSeparator2, gridBagConstraints);

        editWhileMemorizingButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/edit.png"))); // NOI18N
        editWhileMemorizingButton.setToolTipText(bundle.getString("Edit_Card")); // NOI18N
        editWhileMemorizingButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        editWhileMemorizingButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editWhileMemorizingButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        USTMLearningPanel.add(editWhileMemorizingButton, gridBagConstraints);

        switchUSTMLayoutButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/view_top_bottom_16.png"))); // NOI18N
        switchUSTMLayoutButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        switchUSTMLayoutButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                switchUSTMLayoutButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        USTMLearningPanel.add(switchUSTMLayoutButton, gridBagConstraints);

        removeUstmButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/16x16/remove.png"))); // NOI18N
        removeUstmButton.setToolTipText(bundle.getString("Remove_Card")); // NOI18N
        removeUstmButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        removeUstmButton.setName("removeUstmButton"); // NOI18N
        removeUstmButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeUstmButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        USTMLearningPanel.add(removeUstmButton, gridBagConstraints);

        nextNewCardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/forward.png"))); // NOI18N
        nextNewCardButton.setText(bundle.getString("Next_Card")); // NOI18N
        nextNewCardButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
        nextNewCardButton.setName("nextNewCardButton"); // NOI18N
        nextNewCardButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                nextNewCardButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        USTMLearningPanel.add(nextNewCardButton, gridBagConstraints);

        learningCardPanel.add(USTMLearningPanel, "USTMLearningPanel");

        repeatingPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(bundle.getString("Repeat_Cards"))); // NOI18N
        repeatingPanel.setLayout(new java.awt.GridBagLayout());

        repeatingSplitPane.setResizeWeight(0.5);
        repeatingSplitPane.setContinuousLayout(true);

        repeatingFrontSidePanel.setLayout(new java.awt.GridBagLayout());

        repeatingCardFrontSideLabel.setText(bundle.getString("Card_Frontside")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        repeatingFrontSidePanel.add(repeatingCardFrontSideLabel, gridBagConstraints);

        repeatingFrontSideScrollPane.setName("repeatingFrontSideScrollPane"); // NOI18N

        repeatingFrontSideTextArea.setBackground(java.awt.Color.lightGray);
        repeatingFrontSideTextArea.setEditable(false);
        repeatingFrontSideTextArea.setWrapStyleWord(true);
        repeatingFrontSideTextArea.setName("repeatingFrontSideTextArea"); // NOI18N
        repeatingFrontSideScrollPane.setViewportView(repeatingFrontSideTextArea);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        repeatingFrontSidePanel.add(repeatingFrontSideScrollPane, gridBagConstraints);

        repeatingSplitPane.setLeftComponent(repeatingFrontSidePanel);

        repeatingReverseSidePanel.setLayout(new java.awt.GridBagLayout());

        repeatingCardReverseSideLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        repeatingCardReverseSideLabel.setText(bundle.getString("Card_ReverseSide")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        repeatingReverseSidePanel.add(repeatingCardReverseSideLabel, gridBagConstraints);

        repeatingCardPanel.setLayout(new java.awt.CardLayout());

        repeatingAskPanel.setLayout(new java.awt.GridBagLayout());

        repeatingHintLabel.setForeground(new java.awt.Color(255, 12, 145));
        repeatingHintLabel.setText(bundle.getString("Try_To_Remember_The_Reverse_Side")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        repeatingAskPanel.add(repeatingHintLabel, gridBagConstraints);

        repeatingCardPanel.add(repeatingAskPanel, "repeatingAskPanel");

        repeatingShowPanel.setLayout(new java.awt.GridBagLayout());

        repeatingReverseSideScrollPane.setName("repeatingReverseSideScrollPane"); // NOI18N

        repeatingReverseSideTextArea.setBackground(java.awt.Color.lightGray);
        repeatingReverseSideTextArea.setEditable(false);
        repeatingReverseSideTextArea.setWrapStyleWord(true);
        repeatingReverseSideScrollPane.setViewportView(repeatingReverseSideTextArea);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        repeatingShowPanel.add(repeatingReverseSideScrollPane, gridBagConstraints);

        repeatingCardPanel.add(repeatingShowPanel, "repeatingShowPanel");

        repeatingInsertPanel.setLayout(new java.awt.GridBagLayout());

        repeatingInsertTextArea.setWrapStyleWord(true);
        repeatingInsertTextArea.setName("repeatingInsertTextArea"); // NOI18N
        repeatingInsertScrollPane.setViewportView(repeatingInsertTextArea);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        repeatingInsertPanel.add(repeatingInsertScrollPane, gridBagConstraints);

        repeatingCardPanel.add(repeatingInsertPanel, "repeatingInsertPanel");

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        repeatingReverseSidePanel.add(repeatingCardPanel, gridBagConstraints);

        repeatingSplitPane.setRightComponent(repeatingReverseSidePanel);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        repeatingPanel.add(repeatingSplitPane, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
        repeatingPanel.add(jSeparator3, gridBagConstraints);

        editWhileRepeatingButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/edit.png"))); // NOI18N
        editWhileRepeatingButton.setToolTipText(bundle.getString("Edit_Card")); // NOI18N
        editWhileRepeatingButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        editWhileRepeatingButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editWhileRepeatingButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        repeatingPanel.add(editWhileRepeatingButton, gridBagConstraints);

        switchRepeatingLayoutButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/view_top_bottom_16.png"))); // NOI18N
        switchRepeatingLayoutButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        switchRepeatingLayoutButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                switchRepeatingLayoutButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        repeatingPanel.add(switchRepeatingLayoutButton, gridBagConstraints);

        removeRepeatingButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/16x16/remove.png"))); // NOI18N
        removeRepeatingButton.setToolTipText(bundle.getString("Remove_Card")); // NOI18N
        removeRepeatingButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        removeRepeatingButton.setName("removeRepeatingButton"); // NOI18N
        removeRepeatingButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeRepeatingButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        repeatingPanel.add(removeRepeatingButton, gridBagConstraints);

        repeatingButtonCardPanel.setLayout(new java.awt.CardLayout());

        questionButtonPanel.setLayout(new java.awt.GridBagLayout());

        didYouKnowLabel.setText(bundle.getString("Did_You_Know_It")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        questionButtonPanel.add(didYouKnowLabel, gridBagConstraints);

        repeatingYesButton.setText(bundle.getString("Yes")); // NOI18N
        repeatingYesButton.setName("repeatingYesButton"); // NOI18N
        repeatingYesButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                repeatingYesButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        questionButtonPanel.add(repeatingYesButton, gridBagConstraints);

        repeatingNoButton.setText(bundle.getString("No")); // NOI18N
        repeatingNoButton.setName("repeatingNoButton"); // NOI18N
        repeatingNoButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                repeatingNoButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 5);
        questionButtonPanel.add(repeatingNoButton, gridBagConstraints);

        repeatingButtonCardPanel.add(questionButtonPanel, "questionButtonPanel");

        showMeButtonPanel.setLayout(new java.awt.GridBagLayout());

        showMeButton.setText(bundle.getString("Show_Me")); // NOI18N
        showMeButton.setName("showMeButton"); // NOI18N
        showMeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                showMeButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 5);
        showMeButtonPanel.add(showMeButton, gridBagConstraints);

        repeatingButtonCardPanel.add(showMeButtonPanel, "showMeButtonPanel");

        typingOKPanel.setLayout(new java.awt.GridBagLayout());

        insertReverseSideLabel.setForeground(java.awt.Color.red);
        insertReverseSideLabel.setText(bundle.getString("Insert_Reverse_Side")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        typingOKPanel.add(insertReverseSideLabel, gridBagConstraints);

        typingOKButton.setText(bundle.getString("OK")); // NOI18N
        typingOKButton.setName("typingOKButton"); // NOI18N
        typingOKButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                typingOKButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 5);
        typingOKPanel.add(typingOKButton, gridBagConstraints);

        repeatingButtonCardPanel.add(typingOKPanel, "typingOKPanel");

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 0, 5, 0);
        repeatingPanel.add(repeatingButtonCardPanel, gridBagConstraints);

        learningCardPanel.add(repeatingPanel, "repeatingPanel");

        waitForUSTMPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        waitForUSTMPanel.setLayout(new java.awt.GridBagLayout());

        waitForUSTMLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        waitForUSTMLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/animated-hourglass.gif"))); // NOI18N
        waitForUSTMLabel.setText(bundle.getString("USTM_Time_Is_Still_Running")); // NOI18N
        waitForUSTMLabel.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        waitForUSTMLabel.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(10, 10, 0, 10);
        waitForUSTMPanel.add(waitForUSTMLabel, gridBagConstraints);

        repeatUSTMButton.setText(bundle.getString("Do_Not_Care_Hurry_Up")); // NOI18N
        repeatUSTMButton.setName("repeatUSTMButton"); // NOI18N
        repeatUSTMButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                repeatUSTMButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
        gridBagConstraints.insets = new java.awt.Insets(25, 0, 10, 0);
        waitForUSTMPanel.add(repeatUSTMButton, gridBagConstraints);

        learningCardPanel.add(waitForUSTMPanel, "waitForUSTMPanel");

        waitForSTMPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        waitForSTMPanel.setName("waitForSTMPanel"); // NOI18N
        waitForSTMPanel.setLayout(new java.awt.GridBagLayout());

        waitForSTMLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        waitForSTMLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/animated-hourglass.gif"))); // NOI18N
        waitForSTMLabel.setText(bundle.getString("STM_Time_Is_Still_Running")); // NOI18N
        waitForSTMLabel.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        waitForSTMLabel.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(10, 10, 0, 10);
        waitForSTMPanel.add(waitForSTMLabel, gridBagConstraints);

        repeatSTMButton.setText(bundle.getString("Do_Not_Care_Hurry_Up")); // NOI18N
        repeatSTMButton.setName("repeatSTMButton"); // NOI18N
        repeatSTMButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                repeatSTMButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(25, 0, 10, 0);
        waitForSTMPanel.add(repeatSTMButton, gridBagConstraints);

        learningCardPanel.add(waitForSTMPanel, "waitForSTMPanel");

        transitionPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        transitionPanel.setName("transitionPanel"); // NOI18N
        transitionPanel.setLayout(new java.awt.GridBagLayout());

        transitoinIconLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/brain.gif"))); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        transitionPanel.add(transitoinIconLabel, gridBagConstraints);

        transitionExplanationLabel.setText(bundle.getString("Transition_Explanation")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.insets = new java.awt.Insets(20, 0, 0, 0);
        transitionPanel.add(transitionExplanationLabel, gridBagConstraints);

        transitionOKButton.setText(bundle.getString("OK")); // NOI18N
        transitionOKButton.setName("transitionOKButton"); // NOI18N
        transitionOKButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                transitionOKButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(20, 0, 0, 0);
        transitionPanel.add(transitionOKButton, gridBagConstraints);

        learningCardPanel.add(transitionPanel, "transitionPanel");

        typingErrorPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        typingErrorPanel.setLayout(new java.awt.GridBagLayout());

        infoLabel.setForeground(java.awt.Color.red);
        infoLabel.setText(bundle.getString("Mistyped_Answer")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 0, 5);
        typingErrorPanel.add(infoLabel, gridBagConstraints);

        typingErrorSplitPane.setResizeWeight(0.5);
        typingErrorSplitPane.setContinuousLayout(true);

        inputPanel.setLayout(new java.awt.GridBagLayout());

        inputLabel.setText(bundle.getString("Your_Input")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        inputPanel.add(inputLabel, gridBagConstraints);

        inputTextArea.setEditable(false);
        inputScrollPane.setViewportView(inputTextArea);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        inputPanel.add(inputScrollPane, gridBagConstraints);

        typingErrorSplitPane.setLeftComponent(inputPanel);

        reversePanel.setLayout(new java.awt.GridBagLayout());

        reverseLabel.setText(bundle.getString("Reverse_Side")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        reversePanel.add(reverseLabel, gridBagConstraints);

        reverseTextArea.setEditable(false);
        reverseScrollPane.setViewportView(reverseTextArea);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        reversePanel.add(reverseScrollPane, gridBagConstraints);

        typingErrorSplitPane.setRightComponent(reversePanel);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
        typingErrorPanel.add(typingErrorSplitPane, gridBagConstraints);

        editTypingErrorButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/edit.png"))); // NOI18N
        editTypingErrorButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        editTypingErrorButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editTypingErrorButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        typingErrorPanel.add(editTypingErrorButton, gridBagConstraints);

        moveBackButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/back.png"))); // NOI18N
        moveBackButton.setText(bundle.getString("Acknowledge_Error")); // NOI18N
        moveBackButton.setName("moveBackButton"); // NOI18N
        moveBackButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                moveBackButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.insets = new java.awt.Insets(5, 0, 5, 0);
        typingErrorPanel.add(moveBackButton, gridBagConstraints);

        ignoreErrorButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/forward.png"))); // NOI18N
        ignoreErrorButton.setText(bundle.getString("Ignore_Error")); // NOI18N
        ignoreErrorButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
        ignoreErrorButton.setName("ignoreErrorButton"); // NOI18N
        ignoreErrorButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                ignoreErrorButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        typingErrorPanel.add(ignoreErrorButton, gridBagConstraints);

        learningCardPanel.add(typingErrorPanel, "typingErrorPanel");

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        learningPanel.add(learningCardPanel, gridBagConstraints);

        learningStatusPanel.setLayout(new java.awt.CardLayout());

        timerPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        timerPanel.setLayout(new java.awt.GridBagLayout());

        pauseLearningToggleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/player_pause.png"))); // NOI18N
        pauseLearningToggleButton.setToolTipText(bundle.getString("Pause_Learning")); // NOI18N
        pauseLearningToggleButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        pauseLearningToggleButton.setName("pauseLearningToggleButton"); // NOI18N
        pauseLearningToggleButton.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                pauseLearningToggleButtonItemStateChanged(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 0);
        timerPanel.add(pauseLearningToggleButton, gridBagConstraints);

        cancelLearningButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/player_stop.png"))); // NOI18N
        cancelLearningButton.setToolTipText(bundle.getString("Cancel_Learning")); // NOI18N
        cancelLearningButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
        cancelLearningButton.setName("cancelLearningButton"); // NOI18N
        cancelLearningButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancelLearningButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 0);
        timerPanel.add(cancelLearningButton, gridBagConstraints);

        showTimerCheckBox.setFont(showTimerCheckBox.getFont().deriveFont(showTimerCheckBox.getFont().getStyle() & ~java.awt.Font.BOLD, showTimerCheckBox.getFont().getSize()-1));
        showTimerCheckBox.setText(bundle.getString("Show_Timer")); // NOI18N
        showTimerCheckBox.setName("showTimerCheckBox"); // NOI18N
        showTimerCheckBox.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                showTimerCheckBoxItemStateChanged(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 0);
        timerPanel.add(showTimerCheckBox, gridBagConstraints);

        timerCardPanel.setLayout(new java.awt.CardLayout());

        fullTimerPanel.setLayout(new java.awt.GridLayout(2, 0));

        timerGridPanel1.setLayout(new java.awt.GridLayout(1, 0, 5, 0));

        ustmTimerLabel.setFont(ustmTimerLabel.getFont().deriveFont(ustmTimerLabel.getFont().getStyle() & ~java.awt.Font.BOLD, ustmTimerLabel.getFont().getSize()-1));
        ustmTimerLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        ustmTimerLabel.setText(bundle.getString("Ultra_Shortterm_Memory")); // NOI18N
        timerGridPanel1.add(ustmTimerLabel);

        stmTimerLabel.setFont(stmTimerLabel.getFont().deriveFont(stmTimerLabel.getFont().getStyle() & ~java.awt.Font.BOLD, stmTimerLabel.getFont().getSize()-1));
        stmTimerLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        stmTimerLabel.setText(bundle.getString("Shortterm_Memory")); // NOI18N
        timerGridPanel1.add(stmTimerLabel);

        fullTimerPanel.add(timerGridPanel1);

        timerGridPanel2.setLayout(new java.awt.GridLayout(1, 0, 5, 0));

        ustmTimerProgressBar.setFont(ustmTimerProgressBar.getFont().deriveFont(ustmTimerProgressBar.getFont().getStyle() & ~java.awt.Font.BOLD, ustmTimerProgressBar.getFont().getSize()-1));
        ustmTimerProgressBar.setStringPainted(true);
        timerGridPanel2.add(ustmTimerProgressBar);

        stmTimerProgressBar.setFont(stmTimerProgressBar.getFont().deriveFont(stmTimerProgressBar.getFont().getStyle() & ~java.awt.Font.BOLD, stmTimerProgressBar.getFont().getSize()-1));
        stmTimerProgressBar.setStringPainted(true);
        timerGridPanel2.add(stmTimerProgressBar);

        fullTimerPanel.add(timerGridPanel2);

        timerCardPanel.add(fullTimerPanel, "fullTimerPanel");
        timerCardPanel.add(noTimerPanel, "noTimerPanel");

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        timerPanel.add(timerCardPanel, gridBagConstraints);

        learningStatusPanel.add(timerPanel, "timerPanel");

        cancelRepeatingPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        cancelRepeatingPanel.setLayout(new java.awt.GridBagLayout());

        cancelRepeatingButton.setText(bundle.getString("Cancel_Repeating")); // NOI18N
        cancelRepeatingButton.setName("cancelRepeatingButton"); // NOI18N
        cancelRepeatingButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancelRepeatingButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        cancelRepeatingPanel.add(cancelRepeatingButton, gridBagConstraints);

        learningStatusPanel.add(cancelRepeatingPanel, "cancelRepeatingPanel");

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 1.0;
        learningPanel.add(learningStatusPanel, gridBagConstraints);

        cardPanel.add(learningPanel, "learningPanel");

        splitPane.setRightComponent(cardPanel);

        getContentPane().add(splitPane, java.awt.BorderLayout.CENTER);

        fileMenu.setText(bundle.getString("JPauker.fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        newMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N, java.awt.event.InputEvent.CTRL_MASK));
        newMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/filenew.png"))); // NOI18N
        newMenuItem.setText(bundle.getString("JPauker.newMenuItem.text")); // NOI18N
        newMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(newMenuItem);

        openMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
        openMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/fileopen.png"))); // NOI18N
        openMenuItem.setText(bundle.getString("JPauker.openMenuItem.text")); // NOI18N
        openMenuItem.setName("openMenuItem"); // NOI18N
        openMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(openMenuItem);

        importMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/fileimport.png"))); // NOI18N
        importMenuItem.setText(bundle.getString("Text_Import_Menu")); // NOI18N
        importMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                importMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(importMenuItem);

        recentFilesMenu.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/bookmark.png"))); // NOI18N
        recentFilesMenu.setText(bundle.getString("Recent_Files")); // NOI18N
        recentFilesMenu.setName("recentFilesMenu"); // NOI18N
        recentFilesMenu.addMenuListener(new javax.swing.event.MenuListener() {
            public void menuCanceled(javax.swing.event.MenuEvent evt) {
            }
            public void menuDeselected(javax.swing.event.MenuEvent evt) {
            }
            public void menuSelected(javax.swing.event.MenuEvent evt) {
                recentFilesMenuMenuSelected(evt);
            }
        });
        fileMenu.add(recentFilesMenu);
        fileMenu.add(separator1);

        saveMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
        saveMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/filesave.png"))); // NOI18N
        saveMenuItem.setText(bundle.getString("JPauker.saveMenuItem.text")); // NOI18N
        saveMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(saveMenuItem);

        saveAsMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/filesaveas.png"))); // NOI18N
        saveAsMenuItem.setText(bundle.getString("JPauker.saveAsMenuItem.text")); // NOI18N
        saveAsMenuItem.setName("saveAsMenuItem"); // NOI18N
        saveAsMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveAsMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(saveAsMenuItem);
        fileMenu.add(separator4);

        resetMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/back.png"))); // NOI18N
        resetMenuItem.setText(bundle.getString("Reset_Lesson_Menu")); // NOI18N
        resetMenuItem.setName("resetMenuItem"); // NOI18N
        resetMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                resetMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(resetMenuItem);

        flipCardSidesMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/reload.png"))); // NOI18N
        flipCardSidesMenuItem.setText(bundle.getString("Flip_Card_Sides_Menu")); // NOI18N
        flipCardSidesMenuItem.setName("flipCardSidesMenuItem"); // NOI18N
        flipCardSidesMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                flipCardSidesMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(flipCardSidesMenuItem);
        fileMenu.add(separator2);

        exitMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_X, java.awt.event.InputEvent.CTRL_MASK));
        exitMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/exit.gif"))); // NOI18N
        exitMenuItem.setText(bundle.getString("JPauker.exitMenuItem.text")); // NOI18N
        exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exitMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(exitMenuItem);

        mainMenuBar.add(fileMenu);

        extraMenu.setText(bundle.getString("Extra")); // NOI18N
        extraMenu.setName("extraMenu"); // NOI18N

        addCardsMenuitem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/filenew.png"))); // NOI18N
        addCardsMenuitem.setText(bundle.getString("AddMenuItem")); // NOI18N
        addCardsMenuitem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addCardsMenuitemActionPerformed(evt);
            }
        });
        extraMenu.add(addCardsMenuitem);

        configureMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/configure.png"))); // NOI18N
        configureMenuItem.setText(bundle.getString("Configure_Pauker")); // NOI18N
        configureMenuItem.setName("configureMenuItem"); // NOI18N
        configureMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                configureMenuItemActionPerformed(evt);
            }
        });
        extraMenu.add(configureMenuItem);

        showToolBarMenuItem.setSelected(true);
        showToolBarMenuItem.setText(bundle.getString("Show_ToolBar")); // NOI18N
        showToolBarMenuItem.setName("showToolBarMenuItem"); // NOI18N
        showToolBarMenuItem.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                showToolBarMenuItemItemStateChanged(evt);
            }
        });
        extraMenu.add(showToolBarMenuItem);

        mainMenuBar.add(extraMenu);

        helpMenu.setText(bundle.getString("Help")); // NOI18N

        helpMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F1, 0));
        helpMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/help.png"))); // NOI18N
        helpMenuItem.setText(bundle.getString("Contents")); // NOI18N
        helpMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                helpMenuItemActionPerformed(evt);
            }
        });
        helpMenu.add(helpMenuItem);
        helpMenu.add(jSeparator4);

        aboutLessonMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/info.png"))); // NOI18N
        aboutLessonMenuItem.setText(bundle.getString("About_Lesson_MenuItem")); // NOI18N
        aboutLessonMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                aboutLessonMenuItemActionPerformed(evt);
            }
        });
        helpMenu.add(aboutLessonMenuItem);

        aboutProgramMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/info.png"))); // NOI18N
        aboutProgramMenuItem.setText(bundle.getString("AboutMenuItem")); // NOI18N
        aboutProgramMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                aboutProgramMenuItemActionPerformed(evt);
            }
        });
        helpMenu.add(aboutProgramMenuItem);

        donateMenuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pauker/icons/khelpcenter.png"))); // NOI18N
        donateMenuItem.setText(bundle.getString("Donate_Ellipsis")); // NOI18N
        donateMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                donateMenuItemActionPerformed(evt);
            }
        });
        helpMenu.add(donateMenuItem);

        mainMenuBar.add(helpMenu);

        setJMenuBar(mainMenuBar);
    }// </editor-fold>//GEN-END:initComponents
    private void showToolBarMenuItemItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_showToolBarMenuItemItemStateChanged
        toolBar.setVisible(showToolBarMenuItem.isSelected());
    }//GEN-LAST:event_showToolBarMenuItemItemStateChanged

    private void hideToolBarMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hideToolBarMenuItemActionPerformed
        showToolBarMenuItem.setSelected(false);
        String message = MessageFormat.format(
                STRINGS.getString("Info_Show_Toolbar"),
                STRINGS.getString("Extra"), STRINGS.getString("Show_ToolBar"));
        JOptionPane.showMessageDialog(
                this, message,
                STRINGS.getString("Information"),
                JOptionPane.INFORMATION_MESSAGE);
    }//GEN-LAST:event_hideToolBarMenuItemActionPerformed

    private void removeRepeatingButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeRepeatingButtonActionPerformed
        if (!canRemoveCard()) {
            return;
        }

        // remove card from summary, batch and search engine
        currentLesson.getSummaryBatch().removeCard(currentCard);
        removeCurrentCard();
        searchEngine.removeCard(currentCard);

        statisticPanel.setLesson(currentLesson);

        if ((Pauker.getLearningPhase() == Pauker.LearningPhase.REPEATING_USTM) &&
                (currentLesson.getUltraShortTermList().size() == 0) &&
                (currentLesson.getShortTermList().size() == 0)) {
            if (currentLesson.getUnlearnedBatch().getNumberOfCards() == 0) {
                stopLearning();
            } else {
                learnNewCards();
            }
        } else {
            repeatedCardMoved();
        }

        somethingHasChanged();
    }//GEN-LAST:event_removeRepeatingButtonActionPerformed

    private void removeCurrentCard() {
        // remove card from its batch
        switch (Pauker.getLearningPhase()) {
            case REPEATING_USTM:
                currentLesson.getUltraShortTermList().remove(currentCard);
                break;

            case REPEATING_STM:
                currentLesson.getShortTermList().remove(currentCard);
                break;

            case REPEATING_LTM:
                int longTermBatchNumber = currentCard.getLongTermBatchNumber();
                LongTermBatch longTermBatch =
                        currentLesson.getLongTermBatch(longTermBatchNumber);
                longTermBatch.removeCard(currentCard);
                break;

            default:
                throw new RuntimeException("unsupported learning phase \"" +
                        Pauker.getLearningPhase() +
                        "\" -> can't find batch of card!");
        }
    }

    private void removeUstmButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeUstmButtonActionPerformed
        if (!canRemoveCard()) {
            return;
        }

        // remove card from summary, "unlearned" batch and search engine
        currentLesson.getSummaryBatch().removeCard(currentCard);
        Batch unlearnedBatch = currentLesson.getUnlearnedBatch();
        unlearnedBatch.removeCard(currentCard);
        searchEngine.removeCard(currentCard);

        if ((unlearnedBatch.getNumberOfCards() > 0) ||
                (currentLesson.getUltraShortTermList().size() > 0)) {
            showNextUnlearnedCard();
        } else if (currentLesson.getShortTermList().size() > 0) {
            repeatSTMCards();
        } else {
            stopLearning();
        }

        // update statistics panel
        statisticPanel.setLesson(currentLesson);

        somethingHasChanged();
    }//GEN-LAST:event_removeUstmButtonActionPerformed

    private void stopLearning() {
        pauseLearningToggleButton.setSelected(false);
        Pauker.setLearningPhase(Pauker.LearningPhase.NOTHING);
        ustmTimer.stop();
        stmTimer.stop();
        resetGUI();
    }

    private void donateMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_donateMenuItemActionPerformed
        DonateDialog donateDialog = new DonateDialog(this);
        donateDialog.setVisible(true);
    }//GEN-LAST:event_donateMenuItemActionPerformed

    private void batchListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_batchListMouseClicked
        if (evt.getClickCount() == 2) {
            int selectedIndex = batchList.locationToIndex(evt.getPoint());
            if (selectedIndex != -1) {
                Card selectedCard = (Card) batchListModel.get(selectedIndex);
                EditCardDialog dialog = new EditCardDialog(this, selectedCard, searchEngine);
                if (dialog.okPressed()) {
                    cardChanged(selectedIndex);
                }
            }
        }
    }//GEN-LAST:event_batchListMouseClicked

    private void batchListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_batchListValueChanged
        if (evt.getValueIsAdjusting()) {
            return;
        }
        updateBatchListButtons();
    }//GEN-LAST:event_batchListValueChanged

    private void updateBatchListButtons() {
        // determine situation
        int cardsLeft = loadedBatch.getNumberOfCards();
        boolean hasSeveralCards = cardsLeft > 1;
        int[] selectedIndices = batchList.getSelectedIndices();
        boolean cardsSelected = selectedIndices.length > 0;

        // update buttons
        editCardButton.setEnabled(selectedIndices.length == 1);
        fontButton.setEnabled(cardsSelected);
        learningMethodButton.setEnabled(cardsSelected);
        upButton.setEnabled(cardsSelected && (selectedIndices[0] != 0));
        downButton.setEnabled(cardsSelected &&
                (selectedIndices[selectedIndices.length - 1] != batchListModel.getSize() - 1));
        sortButton.setEnabled(hasSeveralCards);
        randomizeButton.setEnabled(hasSeveralCards);
        instantRepeatButton.setEnabled(cardsSelected);
        forgetButton.setEnabled(cardsSelected && (loadedBatch != currentLesson.getUnlearnedBatch()));
        removeCardButton.setEnabled(cardsSelected);
        searchButton.setEnabled(cardsLeft > 0);
    }

    private void pauseLearningToggleButtonItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_pauseLearningToggleButtonItemStateChanged
        if (pauseLearningToggleButton.isSelected()) {
            ustmTimer.stop();
            stmTimer.stop();
            nextNewCardButton.setEnabled(false);
            repeatingYesButton.setEnabled(false);
            repeatingNoButton.setEnabled(false);
            showMeButton.setEnabled(false);
            typingOKButton.setEnabled(false);
            moveBackButton.setEnabled(false);
            ignoreErrorButton.setEnabled(false);
        } else {
            if (currentSTMTime < stmTime) {
                stmTimer.start();
            }
            if (currentUSTMTime < ustmTime) {
                ustmTimer.start();
            }
            nextNewCardButton.setEnabled(true);
            repeatingYesButton.setEnabled(true);
            repeatingNoButton.setEnabled(true);
            showMeButton.setEnabled(true);
            typingOKButton.setEnabled(true);
            moveBackButton.setEnabled(true);
            ignoreErrorButton.setEnabled(true);
        }
    }//GEN-LAST:event_pauseLearningToggleButtonItemStateChanged

    private void importMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importMenuItemActionPerformed
        ImportDialog dialog = new ImportDialog(this);
        dialog.setVisible(true);
    }//GEN-LAST:event_importMenuItemActionPerformed

    private void switchRepeatingLayoutButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_switchRepeatingLayoutButtonActionPerformed
        switchLayout(switchRepeatingLayoutButton, repeatingSplitPane,
                repeatingFrontSideTextArea, repeatingReverseSideTextArea);
    }//GEN-LAST:event_switchRepeatingLayoutButtonActionPerformed

    private void switchUSTMLayoutButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_switchUSTMLayoutButtonActionPerformed
        switchLayout(switchUSTMLayoutButton, ustmSplitPane,
                ustmFrontSideTextArea, ustmReverseSideTextArea);
    }//GEN-LAST:event_switchUSTMLayoutButtonActionPerformed

    private void editTypingErrorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editTypingErrorButtonActionPerformed
        EditCardDialog dialog = new EditCardDialog(this, currentCard, searchEngine);
        if (dialog.okPressed()) {
            JOptionPane.showMessageDialog(
                    this, STRINGS.getString("Typing_Error_Still_Shown"),
                    STRINGS.getString("Information"),
                    JOptionPane.INFORMATION_MESSAGE);
        }
    }//GEN-LAST:event_editTypingErrorButtonActionPerformed

    private void fontButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fontButtonActionPerformed

        // determine "average" values for fonts and colors of the selected cards

        HashMap<String, Integer> fontFamilyCounter =
                new HashMap<String, Integer>();
        int boldCounter = 0;
        int nonBoldCounter = 0;
        int italicCounter = 0;
        int nonItalicCounter = 0;
        HashMap<Color, Integer> foregroundCounter =
                new HashMap<Color, Integer>();
        HashMap<Color, Integer> backgroundCounter =
                new HashMap<Color, Integer>();
        float fontSizeSum = 0;
        int[] selectedIndices = batchList.getSelectedIndices();
        for (int selectedIndex : selectedIndices) {
            Card card = (Card) batchListModel.getElementAt(selectedIndex);
            CardSide frontSide = card.getFrontSide();
            CardSide reverseSide = card.getReverseSide();

            // add up font sizes
            fontSizeSum += card.getAverageFontSize();

            // count how often any font family name occurs
            increaseCounter(fontFamilyCounter, frontSide.getFontFamily());
            increaseCounter(fontFamilyCounter, reverseSide.getFontFamily());

            // count different font styles
            int frontSideFontStlye = frontSide.getFontStyle();
            if ((frontSideFontStlye & Font.BOLD) == 0) {
                nonBoldCounter++;
            } else {
                boldCounter++;
            }
            if ((frontSideFontStlye & Font.ITALIC) == 0) {
                nonItalicCounter++;
            } else {
                italicCounter++;
            }
            int reverseSideFontStlye = reverseSide.getFontStyle();
            if ((reverseSideFontStlye & Font.BOLD) == 0) {
                nonBoldCounter++;
            } else {
                boldCounter++;
            }
            if ((reverseSideFontStlye & Font.ITALIC) == 0) {
                nonItalicCounter++;
            } else {
                italicCounter++;
            }

            // count colors
            increaseCounter(
                    foregroundCounter, frontSide.getForegroundColor());
            increaseCounter(
                    foregroundCounter, reverseSide.getForegroundColor());
            increaseCounter(
                    backgroundCounter, frontSide.getBackgroundColor());
            increaseCounter(
                    backgroundCounter, reverseSide.getBackgroundColor());
        }

        String mostUsedFontFamily = getLargestKey(fontFamilyCounter);
        int averageFontSize = (int) (fontSizeSum / selectedIndices.length);
        int mostUsedFontStlye =
                (boldCounter > nonBoldCounter) ? Font.BOLD : Font.PLAIN;
        if (italicCounter > nonItalicCounter) {
            mostUsedFontStlye |= Font.ITALIC;
        }
        Font initialFont = new Font(
                mostUsedFontFamily, mostUsedFontStlye, averageFontSize);

        Color initialForegroud = getLargestKey(foregroundCounter);
        Color initialBackgroud = getLargestKey(backgroundCounter);


        // now that we finally found all the "average" values for fonts and
        // colors of the selected cards we open the dialog
        FontDialog dialog = new FontDialog(this, initialFont, initialForegroud,
                initialBackgroud, fontDialogSide);
        dialog.setVisible(true);

        if (dialog.okPressed()) {
            Font font = dialog.getTextAreaFont();
            fontDialogSide = dialog.getSide();
            Color foregroundColor = dialog.getForegroundColor();
            Color backgroundColor = dialog.getBackgroundColor();

            for (int selectedIndex : selectedIndices) {
                Card card = loadedBatch.getCard(selectedIndex);
                switch (fontDialogSide) {
                    case FRONT_SIDE:
                        CardSide frontSide = card.getFrontSide();
                        frontSide.setFont(font);
                        frontSide.setForegroundColor(foregroundColor);
                        frontSide.setBackgroundColor(backgroundColor);
                        break;

                    case REVERSE_SIDE:
                        CardSide reverseSide = card.getReverseSide();
                        reverseSide.setFont(font);
                        reverseSide.setForegroundColor(foregroundColor);
                        reverseSide.setBackgroundColor(backgroundColor);
                        break;

                    case BOTH_SIDES:
                        frontSide = card.getFrontSide();
                        frontSide.setFont(font);
                        frontSide.setForegroundColor(foregroundColor);
                        frontSide.setBackgroundColor(backgroundColor);
                        reverseSide = card.getReverseSide();
                        reverseSide.setFont(font);
                        reverseSide.setForegroundColor(foregroundColor);
                        reverseSide.setBackgroundColor(backgroundColor);
                        break;

                    default:
                        System.out.println("WARNING: PaukerFrame." +
                                "fontButtonActionPerformed() unknown side " +
                                fontDialogSide);
                }
                batchListModel.cardsChanged(selectedIndex, selectedIndex);
            }
            somethingHasChanged();
        }
    }//GEN-LAST:event_fontButtonActionPerformed

    private <T> void increaseCounter(Map<T, Integer> map, T key) {
        if (map.containsKey(key)) {
            Integer counter = map.get(key);
            Integer newCounter = Integer.valueOf(counter.intValue() + 1);
            map.put(key, newCounter);
        } else {
            map.put(key, Integer.valueOf(1));
        }
    }

    private <T> T getLargestKey(Map<T, Integer> map) {
        T maxKey = null;
        int maxInteger = 0;
        Set<T> keySet = map.keySet();
        for (T key : keySet) {
            int intValue = map.get(key).intValue();
            if (maxInteger < intValue) {
                maxKey = key;
                maxInteger = intValue;
            }
        }
        return maxKey;
    }

    private void ignoreErrorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ignoreErrorButtonActionPerformed
        pushCurrentCard();
    }//GEN-LAST:event_ignoreErrorButtonActionPerformed

    private void moveBackButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_moveBackButtonActionPerformed
        dropCurrentCard();
    }//GEN-LAST:event_moveBackButtonActionPerformed

    private void addCardsMenuitemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addCardsMenuitemActionPerformed
        showNewCardDialog();
    }//GEN-LAST:event_addCardsMenuitemActionPerformed

    private void learningMethodButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_learningMethodButtonMousePressed
        if (learningMethodButton.isEnabled()) {
            learningPopupMenu.show(learningMethodButton, evt.getX(), evt.getY());
        }
    }//GEN-LAST:event_learningMethodButtonMousePressed

    private void sortButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_sortButtonMousePressed
        if (sortButton.isEnabled()) {
            sortingPopupMenu.show(sortButton, evt.getX(), evt.getY());
        }
    }//GEN-LAST:event_sortButtonMousePressed

    private void instantRepeatButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_instantRepeatButtonActionPerformed

        int[] selectedIndices = batchList.getSelectedIndices();

        Object[] options = {
            STRINGS.getString("Repeat_Cards_Instantly"),
            STRINGS.getString("No")
        };

        questionLabel.setText(STRINGS.getString("Instant_Repeating_Question"));
        explanationLabel.setText(STRINGS.getString("Instant_Repeating_Explanation"));
        int result = JOptionPane.showOptionDialog(
                this, questionPanel,
                STRINGS.getString("Question"),
                JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
                null, options, options[0]);

        if (result != JOptionPane.YES_OPTION) {
            return;
        }

        currentLesson.instantRepeatCards(loadedBatch, selectedIndices);

        statisticPanel.setLesson(currentLesson);

        loadBatch(loadedBatch);

        // restore selection if summary batch was loaded
        if (loadedBatch == currentLesson.getSummaryBatch()) {
            System.out.println("summary batch loaded -> restore previous selection");
            for (int index : selectedIndices) {
                batchList.addSelectionInterval(index, index);
            }
        }

        scrollToCurrentSearchHit();

        learnNewCardsButton.setEnabled((currentLesson.getUnlearnedBatch()).getNumberOfCards() > 0);
        repeatCardsButton.setEnabled(true);

        somethingHasChanged();

    }//GEN-LAST:event_instantRepeatButtonActionPerformed

    private void typeMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_typeMenuItemActionPerformed
        setRepeatByTyping(true);
    }//GEN-LAST:event_typeMenuItemActionPerformed

    private void remeberMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_remeberMenuItemActionPerformed
        setRepeatByTyping(false);
    }//GEN-LAST:event_remeberMenuItemActionPerformed

    private void descendingRepeatMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_descendingRepeatMenuItemActionPerformed
        sortBatch(Card.Element.REPEATING_MODE, false);
    }//GEN-LAST:event_descendingRepeatMenuItemActionPerformed

    private void ascendingRepeatMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ascendingRepeatMenuItemActionPerformed
        sortBatch(Card.Element.REPEATING_MODE, true);
    }//GEN-LAST:event_ascendingRepeatMenuItemActionPerformed

    private void descendingExpiredMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_descendingExpiredMenuItemActionPerformed
        sortBatch(Card.Element.EXPIRED_DATE, false);
    }//GEN-LAST:event_descendingExpiredMenuItemActionPerformed

    private void ascendingExpiredMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ascendingExpiredMenuItemActionPerformed
        sortBatch(Card.Element.EXPIRED_DATE, true);
    }//GEN-LAST:event_ascendingExpiredMenuItemActionPerformed

    private void descendingLearnedMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_descendingLearnedMenuItemActionPerformed
        sortBatch(Card.Element.LEARNED_DATE, false);
    }//GEN-LAST:event_descendingLearnedMenuItemActionPerformed

    private void ascendingLearnedMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ascendingLearnedMenuItemActionPerformed
        sortBatch(Card.Element.LEARNED_DATE, true);
    }//GEN-LAST:event_ascendingLearnedMenuItemActionPerformed

    private void descendingBatchMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_descendingBatchMenuItemActionPerformed
        sortBatch(Card.Element.BATCH_NUMBER, false);
    }//GEN-LAST:event_descendingBatchMenuItemActionPerformed

    private void ascendingBatchMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ascendingBatchMenuItemActionPerformed
        sortBatch(Card.Element.BATCH_NUMBER, true);
    }//GEN-LAST:event_ascendingBatchMenuItemActionPerformed

    private void descendingBackMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_descendingBackMenuItemActionPerformed
        sortBatch(Card.Element.REVERSE_SIDE, false);
    }//GEN-LAST:event_descendingBackMenuItemActionPerformed

    private void descendingFrontMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_descendingFrontMenuItemActionPerformed
        sortBatch(Card.Element.FRONT_SIDE, false);
    }//GEN-LAST:event_descendingFrontMenuItemActionPerformed

    private void ascendingBackMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ascendingBackMenuItemActionPerformed
        sortBatch(Card.Element.REVERSE_SIDE, true);
    }//GEN-LAST:event_ascendingBackMenuItemActionPerformed

    private void ascendingFrontMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ascendingFrontMenuItemActionPerformed
        sortBatch(Card.Element.FRONT_SIDE, true);
    }//GEN-LAST:event_ascendingFrontMenuItemActionPerformed

    private void typingOKButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_typingOKButtonActionPerformed

        CardSide reverseSide = currentCard.getReverseSide();

        String reverseSideText = reverseSide.getText();
        String insertedText = repeatingInsertTextArea.getText();

        boolean correctInput;
        if (matchCase) {
            correctInput = insertedText.equals(reverseSideText);
        } else {
            correctInput = insertedText.equalsIgnoreCase(reverseSideText);
        }

        if (correctInput) {
            pushCurrentCard();

        } else {
            // make a Diff
            PathNodeDiff diff = new PathNodeDiff(reverseSideText, insertedText, matchCase);

            // highlight both sides
            Font highLightFont = reverseSide.getFont();
            highlightSide(diff.getStringAScript(), reverseSide.getText(),
                    highLightFont, reverseTextArea, Color.green);
            highlightSide(diff.getStringBScript(), insertedText,
                    highLightFont, inputTextArea, Color.red);

            updateSplitPane(typingErrorSplitPane, inputTextArea, reverseTextArea);

            showPanel(learningCardPanel, "typingErrorPanel");
            getRootPane().setDefaultButton(null);
            moveBackButton.requestFocusInWindow();
        }
    }//GEN-LAST:event_typingOKButtonActionPerformed

    private void highlightSide(List<Integer> script, String text, Font font,
            JTextArea textArea, Color color) {
        // special handling of newline characters
        StringBuilder stringBuilder = new StringBuilder(text);
        int insertions = 0;
        for (Integer integer : script) {
            int index = integer.intValue();
            if (text.charAt(index) == '\n') {
                // insert a special "return" unicode character
                stringBuilder.insert(index + insertions++, "\u21B5");
            }
        }
        textArea.setText(stringBuilder.toString());
        textArea.setFont(font);
        Highlighter.HighlightPainter highlightPainter =
                new DefaultHighlighter.DefaultHighlightPainter(color);
        Highlighter highlighter = textArea.getHighlighter();
        insertions = 0;
        try {
            for (Integer integer : script) {
                int index = integer.intValue();
                if (text.charAt(index) == '\n') {
                    // also highlight inserted special "return" unicode
                    // character
                    highlighter.addHighlight(index + insertions,
                            index + insertions + 2, highlightPainter);
                    insertions++;
                } else {
                    highlighter.addHighlight(index + insertions,
                            index + insertions + 1, highlightPainter);
                }
            }
        } catch (BadLocationException badLocationException) {
            logger.log(Level.SEVERE, null, badLocationException);
        }
    }

    private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed
        if (searchDialog == null) {
            searchDialog = new SearchDialog(this, batchPanel);
        }
        searchDialog.setVisible(true);
    }//GEN-LAST:event_searchButtonActionPerformed

    private void formWindowOpened(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowOpened
        // load the summary batch when opening the window
        loadedBatch = currentLesson.getSummaryBatch();
    }//GEN-LAST:event_formWindowOpened

    private void editWhileRepeatingButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editWhileRepeatingButtonActionPerformed
        EditCardDialog dialog = new EditCardDialog(this, currentCard, searchEngine);

        if (dialog.okPressed()) {
            fillTextComponentWithCardSide(currentCard.getFrontSide(),
                    repeatingFrontSideTextArea, false);
            fillTextComponentWithCardSide(currentCard.getReverseSide(),
                    repeatingReverseSideTextArea, false);
        }
    }//GEN-LAST:event_editWhileRepeatingButtonActionPerformed

    private void editWhileMemorizingButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editWhileMemorizingButtonActionPerformed
        EditCardDialog dialog = new EditCardDialog(this, currentCard, searchEngine);

        if (dialog.okPressed()) {
            fillTextComponentWithCardSide(currentCard.getFrontSide(),
                    ustmFrontSideTextArea, false);
            fillTextComponentWithCardSide(currentCard.getReverseSide(),
                    ustmReverseSideTextArea, false);
        }
    }//GEN-LAST:event_editWhileMemorizingButtonActionPerformed

    private void helpMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_helpMenuItemActionPerformed
        helpbroker.setCurrentID("Pauker");
        helpbroker.setSize(new Dimension(1200, 800));
        helpbroker.setDisplayed(true);
    }//GEN-LAST:event_helpMenuItemActionPerformed

    private void forgetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_forgetButtonActionPerformed

        int[] selectedIndices = batchList.getSelectedIndices();

        Object[] options = {null, STRINGS.getString("No")};

        String warningMessage = null;
        if (selectedIndices.length > 1) {
            warningMessage = STRINGS.getString("Move_Cards_Back_Question");
            options[0] = STRINGS.getString("Move_Cards_Back");
        } else {
            warningMessage = STRINGS.getString("Move_Card_Back_Question");
            options[0] = STRINGS.getString("Move_Card_Back");
        }

        questionLabel.setText(warningMessage);
        explanationLabel.setText(STRINGS.getString("Move_Cards_Back_Explanation"));
        int result = JOptionPane.showOptionDialog(
                this, questionPanel, STRINGS.getString("Question"),
                JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
                null, options, options[0]);

        if (result != JOptionPane.YES_OPTION) {
            return;
        }

        currentLesson.forgetCards(loadedBatch, selectedIndices);

        statisticPanel.setLesson(currentLesson);

        loadBatch(loadedBatch);

        // restore selection if summary batch was loaded
        if (loadedBatch == currentLesson.getSummaryBatch()) {
            System.out.println("summary batch loaded -> restore previous selection");
            for (int index : selectedIndices) {
                batchList.addSelectionInterval(index, index);
            }
        }

        scrollToCurrentSearchHit();

        learnNewCardsButton.setEnabled(true);
        repeatCardsButton.setEnabled(currentLesson.getNumberOfExpiredCards() > 0);

        somethingHasChanged();
    }//GEN-LAST:event_forgetButtonActionPerformed

    private void upButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_upButtonActionPerformed
        moveCards(-1);
    }//GEN-LAST:event_upButtonActionPerformed

    private void downButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downButtonActionPerformed
        moveCards(1);
    }//GEN-LAST:event_downButtonActionPerformed

    private void transitionOKButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_transitionOKButtonActionPerformed
        showPanel(learningCardPanel, "repeatingPanel");
        Card firstStmCard = currentLesson.getShortTermList().get(0);
        repeatCard(firstStmCard);
    }//GEN-LAST:event_transitionOKButtonActionPerformed

    private void configureMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_configureMenuItemActionPerformed
        SettingsDialog settingsDialog = new SettingsDialog(this);
        settingsDialog.setVisible(true);
        if (settingsDialog.okPressed()) {
            repeatingStrategy = settingsDialog.getRepeatingStrategy();
            putBackStrategy = settingsDialog.getPutBackStrategy();

            ustmTime = settingsDialog.getUSTMTime();
            stmTime = settingsDialog.getSTMTime();

            matchCase = settingsDialog.isMatchCaseSelected();

            int numberOfCards = loadedBatch.getNumberOfCards();
            batchListModel.cardsChanged(0, numberOfCards - 1);

            lineWrapping = settingsDialog.isLineWrappingSelected();
            setLineWrap(lineWrapping);

            searchLimit = settingsDialog.getSearchLimit();
            searchEngine.setSearchLimit(searchLimit);

            playRingTone = settingsDialog.isPlayRingToneSelected();
        }
    }//GEN-LAST:event_configureMenuItemActionPerformed

    private void showTimerCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_showTimerCheckBoxItemStateChanged
        if (showTimerCheckBox.isSelected()) {
            showPanel(timerCardPanel, "fullTimerPanel");
        } else {
            showPanel(timerCardPanel, "noTimerPanel");
        }
    }//GEN-LAST:event_showTimerCheckBoxItemStateChanged

    private void randomizeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_randomizeButtonActionPerformed
        // remember selection before randomization
        int[] selectedIndices = batchList.getSelectedIndices();

        // actual randomization
        SummaryBatch summaryBatch = currentLesson.getSummaryBatch();
        if (loadedBatch == summaryBatch) {
            // special handling when randomizing the summary batch:
            // randomize also the unlearned and all long term batches
            int[] noSelection = new int[0];
            currentLesson.getUnlearnedBatch().shuffle(noSelection);
            for (LongTermBatch longTermBatch : currentLesson.getLongTermBatches()) {
                longTermBatch.shuffle(noSelection);
            }
        }
        int[] newSelectedIndices = loadedBatch.shuffle(selectedIndices);
        batchListModel.setBatch(loadedBatch);
        batchListModel.cardsChanged(0, loadedBatch.getNumberOfCards() - 1);

        // reset selection
        batchList.clearSelection();
        if (newSelectedIndices != null) {
            for (int index : newSelectedIndices) {
                batchList.addSelectionInterval(index, index);
            }
        }

        // scroll to search hit or selection
        SearchHit currentSearchHit = loadedBatch.getCurrentSearchHit();
        if (currentSearchHit == null) {
            // scroll to selection
            if ((newSelectedIndices != null) &&
                    (newSelectedIndices.length != 0)) {
                Arrays.sort(newSelectedIndices);
                int firstIndex = newSelectedIndices[0];
                batchList.ensureIndexIsVisible(firstIndex);
            }
        } else {
            scrollToCurrentSearchHit();
        }

        somethingHasChanged();
    }//GEN-LAST:event_randomizeButtonActionPerformed

    private void flipCardSidesMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_flipCardSidesMenuItemActionPerformed
        if (currentLesson.getNumberOfCards() == 0) {

            JOptionPane.showMessageDialog(
                    this, STRINGS.getString("No_Cards_To_Flip_Hint"),
                    STRINGS.getString("Information"),
                    JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        Object[] options = {
            STRINGS.getString("Flip_Card_Sides"),
            STRINGS.getString("Cancel")
        };

        questionLabel.setText(STRINGS.getString("Flip_Cards_Question"));
        explanationLabel.setText(STRINGS.getString("Flip_Cards_Explanation"));
        int result = JOptionPane.showOptionDialog(
                this, questionPanel,
                STRINGS.getString("Warning"),
                JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
                null, options, options[0]);

        if (result != 0) {
            return;
        }

        currentLesson.flip();

        statisticPanel.setLesson(currentLesson);
        statisticPanel.clearSelection();
        showPanel(lessonPanel, "aboutPanel");

        learnNewCardsButton.setEnabled((currentLesson.getUnlearnedBatch()).getNumberOfCards() > 0);
        repeatCardsButton.setEnabled(currentLesson.getNumberOfExpiredCards() > 0);

        // must update the search engine
        // (otherwise searching for similar cards works on the wrong card side)
        searchEngine.init();
        searchEngine.index(currentLesson);

        somethingHasChanged();
    }//GEN-LAST:event_flipCardSidesMenuItemActionPerformed

    private void aboutLessonMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_aboutLessonMenuItemActionPerformed
        showPanel(lessonPanel, "aboutPanel");
    }//GEN-LAST:event_aboutLessonMenuItemActionPerformed

    private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveButtonActionPerformed
        saveFile(currentFileName, false);
    }//GEN-LAST:event_saveButtonActionPerformed

    private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed
        openAction();
    }//GEN-LAST:event_openButtonActionPerformed

    private void newButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newButtonActionPerformed
        newAction();
    }//GEN-LAST:event_newButtonActionPerformed

    private void repeatSTMButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_repeatSTMButtonActionPerformed
        repeatSTMCards();
    }//GEN-LAST:event_repeatSTMButtonActionPerformed

    private void repeatUSTMButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_repeatUSTMButtonActionPerformed
        repeatUSTMCards();
    }//GEN-LAST:event_repeatUSTMButtonActionPerformed

    private void cancelRepeatingButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelRepeatingButtonActionPerformed
        resetGUI();
    }//GEN-LAST:event_cancelRepeatingButtonActionPerformed

    private void resetMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetMenuItemActionPerformed
        if (currentLesson.getNumberOfCards() == 0) {
            JOptionPane.showMessageDialog(
                    this, STRINGS.getString("No_Cards_To_Reset_Hint"),
                    STRINGS.getString("Information"),
                    JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        if (currentLesson.getNumberOfLongTermBatches() == 0) {
            JOptionPane.showMessageDialog(
                    this, STRINGS.getString("No_High_Cards_To_Reset_Hint"),
                    STRINGS.getString("Information"),
                    JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        Object[] options = {
            STRINGS.getString("Reset_Lesson"),
            STRINGS.getString("Cancel")
        };
        questionLabel.setText(STRINGS.getString("Reset_Lesson_Question"));
        explanationLabel.setText(STRINGS.getString("Reset_Lesson_Explanation"));
        int result = JOptionPane.showOptionDialog(
                this, questionPanel,
                STRINGS.getString("Warning"),
                JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
                null, options, options[0]);

        if (result != JOptionPane.YES_OPTION) {
            return;
        }

        currentLesson.reset();
        statisticPanel.setLesson(currentLesson);
        statisticPanel.selectSummary();
        loadBatch(currentLesson.getSummaryBatch());

        learnNewCardsButton.setEnabled((currentLesson.getUnlearnedBatch()).getNumberOfCards() > 0);
        repeatCardsButton.setEnabled(false);

        somethingHasChanged();
    }//GEN-LAST:event_resetMenuItemActionPerformed

    private void repeatingNoButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_repeatingNoButtonActionPerformed
        dropCurrentCard();
    }//GEN-LAST:event_repeatingNoButtonActionPerformed

    private void repeatingYesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_repeatingYesButtonActionPerformed
        pushCurrentCard();
    }//GEN-LAST:event_repeatingYesButtonActionPerformed

    private void showMeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showMeButtonActionPerformed
        showPanel(repeatingCardPanel, "repeatingShowPanel");
        showPanel(repeatingButtonCardPanel, "questionButtonPanel");
        // setting default on repeatingYesButton
        getRootPane().setDefaultButton(null);
        repeatingYesButton.requestFocusInWindow();
    }//GEN-LAST:event_showMeButtonActionPerformed

    private void nextNewCardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextNewCardButtonActionPerformed
        currentLesson.getUltraShortTermList().add(currentCard);
        currentLesson.getUnlearnedBatch().removeCard(currentCard);
        statisticPanel.setLesson(currentLesson);

        if (currentUSTMTime == ustmTime) {
            repeatUSTMCards();
            return;
        }

        showNextUnlearnedCard();
    }//GEN-LAST:event_nextNewCardButtonActionPerformed

    private void cancelLearningButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelLearningButtonActionPerformed
        if (currentLesson.getUltraShortTermList().size() + currentLesson.getShortTermList().size() > 0) {
            Object[] options = {
                STRINGS.getString("Cancel_Learning"),
                STRINGS.getString("Continue_Learning")
            };

            questionLabel.setText(STRINGS.getString("Cancel_Learning_Question"));
            explanationLabel.setText(STRINGS.getString("Cancel_Learning_Explanation"));
            int result = JOptionPane.showOptionDialog(
                    this, questionPanel,
                    STRINGS.getString("Warning"),
                    JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
                    null, options, options[0]);

            if (result != JOptionPane.YES_OPTION) {
                return;
            }
        }

        pauseLearningToggleButton.setSelected(false);

        Pauker.setLearningPhase(Pauker.LearningPhase.NOTHING);

        ustmTimer.stop();
        stmTimer.stop();

        List<Card> shortTermList = currentLesson.getShortTermList();
        for (int i = shortTermList.size() - 1; i >= 0; i--) {
            putBack(shortTermList.remove(i));
        }
        List<Card> ultraShortTermList = currentLesson.getUltraShortTermList();
        for (int i = ultraShortTermList.size() - 1; i >= 0; i--) {
            putBack(ultraShortTermList.remove(i));
        }

        resetGUI();
    }//GEN-LAST:event_cancelLearningButtonActionPerformed

    private void recentFilesMenuMenuSelected(javax.swing.event.MenuEvent evt) {//GEN-FIRST:event_recentFilesMenuMenuSelected
        if (recentFilesHaveChanged) {
            // remove old recent file entries
            recentFilesMenu.removeAll();

            // add recent file entries
            for (String recentFile : recentFiles) {
                JMenuItem newRecentFileMenuItem = new JMenuItem(recentFile);
                newRecentFileMenuItem.addActionListener(new java.awt.event.ActionListener() {

                    public void actionPerformed(java.awt.event.ActionEvent event) {
                        openRecentFile(event);
                    }
                });
                recentFilesMenu.add(newRecentFileMenuItem);
            }
            recentFilesHaveChanged = false;
        }
    }//GEN-LAST:event_recentFilesMenuMenuSelected

    private void repeatCardsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_repeatCardsButtonActionPerformed
        Pauker.setLearningPhase(Pauker.LearningPhase.REPEATING_LTM);

        // disable menu
        // fixes BUG 942046 - Special chars, menu shortcut clash in Mac OS X
        fileMenu.setEnabled(false);
        addCardsMenuitem.setEnabled(false);
        configureMenuItem.setEnabled(false);
        aboutLessonMenuItem.setEnabled(false);
        newButton.setEnabled(false);
        openButton.setEnabled(false);
        saveButton.setEnabled(false);

        // showing the correct panels
        showPanel(cardPanel, "learningPanel");
        showPanel(learningCardPanel, "repeatingPanel");
        showPanel(learningStatusPanel, "cancelRepeatingPanel");
        statisticPanel.setMouseSensitive(false);
        repeatExpiredCard();
    }//GEN-LAST:event_repeatCardsButtonActionPerformed

    private void learnNewCardsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_learnNewCardsButtonActionPerformed
        ustmTimerProgressBar.setValue(0);
        ustmTimerProgressBar.setString("0 / " + ustmTime + " " + STRINGS.getString("Seconds"));

        stmTimeString = getMinSecString(stmTime);
        stmTimerProgressBar.setValue(0);
        stmTimerProgressBar.setString("0:00 / " + stmTimeString + " " + STRINGS.getString("Minutes"));

        fileMenu.setEnabled(false);
        addCardsMenuitem.setEnabled(false);
        configureMenuItem.setEnabled(false);
        aboutLessonMenuItem.setEnabled(false);
        newButton.setEnabled(false);
        openButton.setEnabled(false);
        saveButton.setEnabled(false);

        Pauker.setLearningPhase(Pauker.LearningPhase.FILLING_USTM);

        statisticPanel.setMouseSensitive(false);

        // showing the right panels
        showPanel(cardPanel, "learningPanel");
        showPanel(learningStatusPanel, "timerPanel");

        // start stm timer
        currentSTMTime = 0;
        stmTimer.start();

        // lets go!
        learnNewCards();
    }//GEN-LAST:event_learnNewCardsButtonActionPerformed

    private void removeCardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeCardButtonActionPerformed

        int[] selectedIndices = batchList.getSelectedIndices();
        String questionString = null;
        Object[] options = {
            null,
            STRINGS.getString("Cancel")
        };

        if (selectedIndices.length == 1) {
            questionString = STRINGS.getString("Confirm_Card_Removal");
            options[0] = STRINGS.getString("Remove_Card");
        } else {
            questionString = STRINGS.getString("Confirm_Cards_Removal");
            options[0] = STRINGS.getString("Remove_Cards");
        }

        int result = JOptionPane.showOptionDialog(
                this, questionString, STRINGS.getString("Question"),
                JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
                null, options, options[0]);

        if (result != JOptionPane.YES_OPTION) {
            return;
        }

        // do the right thing when removing the cards
        SummaryBatch summaryBatch = currentLesson.getSummaryBatch();
        if (loadedBatch == summaryBatch) {
            // just remove the card from the summary
            // (the summary batch then takes care itself to remove the card
            // from the correct batch...)
            for (int i = selectedIndices.length - 1; i >= 0; i--) {
                Card card = summaryBatch.removeCard(selectedIndices[i]);
                searchEngine.removeCard(card);
            }
        } else {
            // longterm batches no not know about the summary batch
            // so we have to remove the card from both the batch
            // (maybe I have to change that...)
            for (int i = selectedIndices.length - 1; i >= 0; i--) {
                Card card = loadedBatch.removeCard(selectedIndices[i]);
                searchEngine.removeCard(card);
                summaryBatch.removeCard(card);
            }
        }

        // update batch list
        batchListModel.setBatch(loadedBatch);
        batchList.clearSelection();

        currentLesson.trim();
        statisticPanel.setLesson(currentLesson);

        int cardsLeft = loadedBatch.getNumberOfCards();

        editCardButton.setEnabled(false);
        upButton.setEnabled(false);
        downButton.setEnabled(false);
        boolean hasSeveralCards = cardsLeft > 1;
        sortButton.setEnabled(hasSeveralCards);
        randomizeButton.setEnabled(hasSeveralCards);
        searchButton.setEnabled(cardsLeft > 0);
        forgetButton.setEnabled(false);
        instantRepeatButton.setEnabled(false);
        removeCardButton.setEnabled(false);

        learnNewCardsButton.setEnabled((currentLesson.getUnlearnedBatch()).getNumberOfCards() > 0);

        somethingHasChanged();

    }//GEN-LAST:event_removeCardButtonActionPerformed

    private void editCardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editCardButtonActionPerformed
        int selectedIndex = batchList.getSelectedIndex();
        Card selectedCard = (Card) batchListModel.get(selectedIndex);
        EditCardDialog dialog = new EditCardDialog(this, selectedCard, searchEngine);
        if (dialog.okPressed()) {
            cardChanged(selectedIndex);
        }
    }//GEN-LAST:event_editCardButtonActionPerformed

    private void addCardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addCardButtonActionPerformed
        showNewCardDialog();
    }//GEN-LAST:event_addCardButtonActionPerformed

    private void aboutProgramMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_aboutProgramMenuItemActionPerformed
        AboutDialog aboutDialog = new AboutDialog(this);
        aboutDialog.setVisible(true);
    }//GEN-LAST:event_aboutProgramMenuItemActionPerformed

    private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMenuItemActionPerformed
        openAction();
    }//GEN-LAST:event_openMenuItemActionPerformed

    private void newMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newMenuItemActionPerformed
        if (Pauker.getLearningPhase() == Pauker.LearningPhase.NOTHING) {
            newAction();
        }
    }//GEN-LAST:event_newMenuItemActionPerformed

    private void saveAsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveAsMenuItemActionPerformed
        saveFileAs();
    }//GEN-LAST:event_saveAsMenuItemActionPerformed

    private void saveMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveMenuItemActionPerformed
        saveFile(currentFileName, false);
    }//GEN-LAST:event_saveMenuItemActionPerformed

    private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed
        exitProgram();
    }//GEN-LAST:event_exitMenuItemActionPerformed

    /** Exit the Application */
03493     private void exitForm(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_exitForm
        if (!modalDialogVisible) {
            exitProgram();
        }
    }//GEN-LAST:event_exitForm

    private boolean canRemoveCard() {
        Object[] options = {
            STRINGS.getString("Remove_Card"),
            STRINGS.getString("Cancel")
        };

        String questionString = STRINGS.getString("Confirm_Card_Removal");
        int result = JOptionPane.showOptionDialog(
                this, questionString, STRINGS.getString("Question"),
                JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
                null, options, options[0]);

        return result == JOptionPane.YES_OPTION;
    }

    private void showNextUnlearnedCard() {
        Batch unlearnedBatch = currentLesson.getUnlearnedBatch();
        if (unlearnedBatch.getNumberOfCards() > 0) {
            // flip to next new card
            currentCard = unlearnedBatch.getCard(0);
            fillTextComponentWithCardSide(currentCard.getFrontSide(),
                    ustmFrontSideTextArea, true);
            fillTextComponentWithCardSide(currentCard.getReverseSide(),
                    ustmReverseSideTextArea, true);
            if (unlearnedBatch.getNumberOfCards() == 1) {
                // we show the last card
                nextNewCardButton.setText(STRINGS.getString("Repeat"));
            }

            updateSplitPane(ustmSplitPane, ustmFrontSideTextArea, ustmReverseSideTextArea);

        } else {
            showPanel(learningCardPanel, "waitForUSTMPanel");
            getRootPane().setDefaultButton(null);
            repeatUSTMButton.requestFocusInWindow();
            Pauker.setLearningPhase(Pauker.LearningPhase.WAITING_FOR_USTM);
        }
    }

    private void exitProgram() {

        switch (Pauker.getLearningPhase()) {
            case REPEATING_USTM:
            case WAITING_FOR_USTM:
            case REPEATING_STM:
            case WAITING_FOR_STM:
                modalDialogVisible = true;
                JOptionPane.showMessageDialog(
                        this, STRINGS.getString("Exit_Warning_Message"),
                        STRINGS.getString("Warning"),
                        JOptionPane.WARNING_MESSAGE);
                modalDialogVisible = false;
                return;
        }

        if (!unsavedChangesOK()) {
            return;
        }

        BorderLayout borderLayout = (BorderLayout) getContentPane().getLayout();
        Object toolBarConstraints = borderLayout.getConstraints(toolBar);

        // save preferences
        Preferences preferences =
                Preferences.userRoot().node(preferencesPathName);
        for (int i = 0; i < recentFiles.size(); i++) {
            String recentFile = recentFiles.get(i);
            preferences.put("RECENT_FILE_" + i, recentFile);
        }
        for (int i = recentFiles.size(); i < MAX_RECENT_FILES; i++) {
            preferences.remove("RECENT_FILE_" + i);
        }
        preferences.put("LAST_DIRECTORY", lastAccessedDirectory);
        preferences.putBoolean("SHOW_TIMER", showTimerCheckBox.isSelected());
        preferences.putInt("REPEATING_STRATEGY", repeatingStrategy.ordinal());
        preferences.putInt("PUTBACK_STRATEGY", putBackStrategy.ordinal());
        preferences.putInt("USTM_TIME", ustmTime);
        preferences.putInt("STM_TIME", stmTime);
        preferences.putBoolean("MATCH_CASE", matchCase);
        preferences.putBoolean("LINE_WRAPPING", lineWrapping);
        preferences.putInt("SPLIT_ORIENTATION", splitOrientation);
        preferences.putInt("SEARCH_LIMIT", searchLimit);
        preferences.putBoolean("PLAY_RINGTONE", playRingTone);
        preferences.putInt("MAIN_DIVIDER_LOCATION",
                splitPane.getDividerLocation());
        if (toolBarConstraints == null) {
            preferences.remove("TOOLBAR_CONSTRAINTS");
        } else {
            preferences.put("TOOLBAR_CONSTRAINTS",
                    toolBarConstraints.toString());
        }
        preferences.putBoolean("TOOLBAR_VISIBLE", toolBar.isVisible());
        preferences.putInt("FONT_DIALOG_SIDE", fontDialogSide.ordinal());

        if (newCardDialog != null) {
            EditCardPanel editCardPanel = newCardDialog.getEditCardPanel();
            JTextComponent textComponent =
                    editCardPanel.getFrontSideTextComponent();
            Font font = textComponent.getFont();
            preferences.put("FRONTSIDE_FONT_FAMILY", font.getFamily());
            preferences.putInt("FRONTSIDE_FONT_STYLE", font.getStyle());
            preferences.putInt("FRONTSIDE_FONT_SIZE", font.getSize());
            preferences.putInt("FRONTSIDE_FOREGROUND",
                    textComponent.getForeground().getRGB());
            preferences.putInt("FRONTSIDE_BACKGROUND",
                    textComponent.getBackground().getRGB());
            textComponent = editCardPanel.getReverseSideTextComponent();
            font = textComponent.getFont();
            preferences.put("REVERSESIDE_FONT_FAMILY", font.getFamily());
            preferences.putInt("REVERSESIDE_FONT_STYLE", font.getStyle());
            preferences.putInt("REVERSESIDE_FONT_SIZE", font.getSize());
            preferences.putInt("REVERSESIDE_FOREGROUND",
                    textComponent.getForeground().getRGB());
            preferences.putInt("REVERSESIDE_BACKGROUND",
                    textComponent.getBackground().getRGB());
            preferences.putBoolean("REPEAT_BY_TYPING",
                    editCardPanel.isRepeatByTyping());
            preferences.putBoolean("KEEP_NEW_CARD_WINDOW_OPEN",
                    keepNewCardDialogOpen);
        }
        preferences.putInt("OPEN_FILE_DIALOG_WIDTH",
                openFileDialog.getWidth());
        preferences.putInt("OPEN_FILE_DIALOG_HEIGTH",
                openFileDialog.getHeight());

        System.exit(0);
    }

    /**
     * @param args the command line arguments
     */
03630     public static void main(final String args[]) {

//        Properties properties = System.getProperties();
//        Enumeration propertyNames = properties.propertyNames();
//        while (propertyNames.hasMoreElements()) {
//            String key = (String) propertyNames.nextElement();
//            String property = properties.getProperty(key);
//            System.out.println(key + ':' + property);
//        }

        // check java version
        String javaVendor = System.getProperty("java.vendor");
        String javaVersion = System.getProperty("java.version");
        String[] tokens = javaVersion.split("\\.");
        int majorVersion = Integer.parseInt(tokens[0]);
        int minorVersion = Integer.parseInt(tokens[1]);
        if (majorVersion <= 1 && minorVersion <= 4) {
            logger.severe(
                    "***************************************************\n" +
                    STRINGS.getString("Error_Java_Version") + "\n" +
                    "***************************************************");
            System.exit(-1);
        }

        // gather language info
        String userLanguage = System.getProperty("user.language");
        String userCountry = System.getProperty("user.country");

        // check heap size
        Runtime runtime = Runtime.getRuntime();
        long maxMemory = runtime.maxMemory();

        // OS specific handling
        String osName = System.getProperty("os.name");

        // log all collected info
        NumberFormat format = NumberFormat.getIntegerInstance();
        logger.info("\n " +
                STRINGS.getString("Operating_System") +
                ": \"" + osName + "\"\n " +
                STRINGS.getString("Java_Vendor") +
                ": \"" + javaVendor + "\"\n " +
                STRINGS.getString("Java_Version") +
                ": \"" + javaVersion + "\"\n " +
                STRINGS.getString("User_Language") +
                ": \"" + userLanguage + "\"\n " +
                STRINGS.getString("User_Country") +
                ": \"" + userCountry + "\"\n " +
                STRINGS.getString("Maximum_Memory") +
                ": " + format.format(maxMemory) + " byte\n");

        // show warning when heap is too small
        if (maxMemory < 100000000) {
            logger.warning(STRINGS.getString("Warning_Small_Heap"));
        }

        // special handling for Mac OS X
        if ("Mac OS X".equals(osName)) {
            logger.info("using Mac OS X screen menu bar...");
            System.setProperty("apple.laf.useScreenMenuBar", "true");
        }

        // WORKAROUND:
        // The the Java Runtime provides localization only for some languages.
        // So we provide a way here to localize the missing languages...
        String language = Locale.getDefault().getLanguage();
        if ("nl".equals(language) || "eo".equals(language) ||
                "pl".equals(language)) {
            translateUI("FileChooser.detailsViewButtonToolTipText");
            translateUI("FileChooser.fileNameLabelText");
            translateUI("FileChooser.filesOfTypeLabelText");
            translateUI("FileChooser.homeFolderToolTipText");
            translateUI("FileChooser.listViewButtonToolTipText");
            translateUI("FileChooser.lookInLabelText");
            translateUI("FileChooser.newFolderToolTipText");
            translateUI("FileChooser.upFolderToolTipText");
        }

        // tell the UIManager to use the platform look & feel
//        try {
//            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
//        } catch (Exception e) {
//        // ignored...
//        }

        // start up
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                PaukerFrame paukerFrame = new PaukerFrame();
                paukerFrame.setVisible(true);
                if (args.length > 0) {
                    String path = args[0];
                    // support for Java Web Start arguments
                    if (args[0].equals("-open") && args.length > 1) {
                        path = args[1];
                    }
                    File file = new File(path);
                    paukerFrame.openFiles(new File[]{file}, null, false);
                }
            }
        });
    }

    private static void translateUI(String key) {
        UIManager.put(key, STRINGS.getString(key));
    }

    private void textChanged(DocumentEvent documentEvent) {
        Document eventSource = documentEvent.getDocument();
        if (eventSource == aboutDocument) {
            currentLesson.setDescription(aboutTextArea.getText());
            if (!settingAboutText) {
                somethingHasChanged();
            }
        }
    }

    private void showPanel(JPanel panel, String card) {
        CardLayout layoutManager = (CardLayout) panel.getLayout();
        layoutManager.show(panel, card);
    }

    private void switchLayout(JButton button, JSplitPane splitPane,
            JTextArea frontSideTextArea, JTextArea reverseSideTextArea) {
        if (splitOrientation == JSplitPane.HORIZONTAL_SPLIT) {
            splitOrientation = JSplitPane.VERTICAL_SPLIT;
            button.setIcon(new ImageIcon(getClass().getResource("/pauker/icons/view_left_right_16.png")));
            button.setToolTipText(PaukerFrame.STRINGS.getString("Cardsides_Left_Right"));
        } else {
            splitOrientation = JSplitPane.HORIZONTAL_SPLIT;
            button.setIcon(new ImageIcon(getClass().getResource("/pauker/icons/view_top_bottom_16.png")));
            button.setToolTipText(PaukerFrame.STRINGS.getString("Cardsides_Top_Down"));
        }
        updateSplitPane(splitPane, frontSideTextArea, reverseSideTextArea);
    }

    private void setRepeatByTyping(boolean repeatByTyping) {
        for (int index : batchList.getSelectedIndices()) {
            Card card = loadedBatch.getCard(index);
            card.setRepeatByTyping(repeatByTyping);
            batchListModel.cardsChanged(index, index);
        }
        somethingHasChanged();
    }

    private void sortBatch(Card.Element element, boolean ascending) {
        // !!! must store selectedIndices before sorting the batch !!!
        int[] selectedIndices = batchList.getSelectedIndices();

        int[] newIndices = loadedBatch.sortCards(element, ascending);
        batchListModel.setBatch(loadedBatch);
        batchListModel.cardsChanged(0, loadedBatch.getNumberOfCards() - 1);

        // restore card selection
        batchList.clearSelection();
        for (int i : selectedIndices) {
            int index = newIndices[i];
            batchList.addSelectionInterval(index, index);
        }

        // scroll to first selected card
        if (selectedIndices.length > 0) {
            batchList.ensureIndexIsVisible(newIndices[selectedIndices[0]]);
        }

        somethingHasChanged();
    }

    private void moveCards(int offset) {
        // !!! must store selectedIndices before moving the cards !!!
        int[] selectedIndices = batchList.getSelectedIndices();

        loadedBatch.moveCards(selectedIndices, offset);
        batchListModel.setBatch(loadedBatch);

        int firstIndex = selectedIndices[0];
        int lastIndex = selectedIndices[selectedIndices.length - 1];
        int movedFirstIndex = firstIndex + offset;
        int movedLastIndex = lastIndex + offset;

        // reset cell sizes
        if (offset > 0) {
            batchListModel.cardsChanged(firstIndex, movedLastIndex);
        } else {
            batchListModel.cardsChanged(movedFirstIndex, lastIndex);
        }

        // reset selection
        batchList.clearSelection();
        for (int i : selectedIndices) {
            int index = i + offset;
            batchList.addSelectionInterval(index, index);
        }
        // scroll
        Rectangle rectangle = batchList.getCellBounds(movedFirstIndex, movedLastIndex);
        batchList.scrollRectToVisible(rectangle);

        somethingHasChanged();
    }

    private void setLineWrap(boolean lineWrap) {
        ustmFrontSideTextArea.setLineWrap(lineWrap);
        ustmReverseSideTextArea.setLineWrap(lineWrap);
        repeatingFrontSideTextArea.setLineWrap(lineWrap);
        repeatingReverseSideTextArea.setLineWrap(lineWrap);
        repeatingInsertTextArea.setLineWrap(lineWrap);
        // update both the list & the renderer
        batchList.setLineWrapping(lineWrap);
        batchListCellRenderer.setLineWrap(lineWrap);
    }

    private void resetGUI() {
        // reset some internals first
        Pauker.setLearningPhase(Pauker.LearningPhase.NOTHING);
        currentLesson.trim();

        // now reset GUI top down
        setTitle(currentTitle);
        getRootPane().setDefaultButton(null);

        statisticPanel.setLesson(currentLesson);
        statisticPanel.clearSelection();
        statisticPanel.setMouseSensitive(true);

        fileMenu.setEnabled(true);
        addCardsMenuitem.setEnabled(true);
        configureMenuItem.setEnabled(true);
        aboutLessonMenuItem.setEnabled(true);
        newButton.setEnabled(true);
        openButton.setEnabled(true);
        saveButton.setEnabled(somethingChanged);
        saveMenuItem.setEnabled(somethingChanged);

        learnNewCardsButton.setEnabled((currentLesson.getUnlearnedBatch()).getNumberOfCards() > 0);
        repeatCardsButton.setEnabled(currentLesson.getNumberOfExpiredCards() > 0);

        showPanel(cardPanel, "overviewPanel");
        showPanel(lessonPanel, "aboutPanel");
    }

    private void repeatCard(Card card) {
        currentCard = card;

        // set focus in statisticTable
        switch (Pauker.getLearningPhase()) {
            case REPEATING_USTM:
                statisticPanel.selectUltraShortTermBatch();
                break;
            case REPEATING_STM:
                statisticPanel.selectShortTermBatch();
                break;
            case REPEATING_LTM:
                int longTermBatchNumber = card.getLongTermBatchNumber();
                statisticPanel.selectLongTermBatch(longTermBatchNumber);
                break;
            default:
                throw new RuntimeException("unsupported learning phase \"" +
                        Pauker.getLearningPhase() +
                        "\" -> could not set selection in statistics!");
        }

        fillTextComponentWithCardSide(currentCard.getFrontSide(),
                repeatingFrontSideTextArea, true);
        CardSide reverseSide = currentCard.getReverseSide();

        // show relevant panel
        showPanel(learningCardPanel, "repeatingPanel");
        getRootPane().setDefaultButton(null);

        // !!! for updateSplitPane() to work correctly we always have to fill the
        // text into the repeatingReverseSideTextArea, even when we are repeating
        // by typing !!!
        fillTextComponentWithCardSide(
                reverseSide, repeatingReverseSideTextArea, true);

        if (currentCard.isRepeatedByTyping()) {
            showPanel(repeatingCardPanel, "repeatingInsertPanel");
            showPanel(repeatingButtonCardPanel, "typingOKPanel");
            // set only font and orientation on repeatingInsertTextArea so that we
            // do not give away to much information about the card to repeat
            setFontAndOrientation(reverseSide, repeatingInsertTextArea);
            repeatingInsertTextArea.setText("");
            repeatingInsertTextArea.requestFocusInWindow();
            repeatingInsertTextArea.setForeground(Color.BLACK);
            getRootPane().setDefaultButton(typingOKButton);
        } else {
            showPanel(repeatingCardPanel, "repeatingAskPanel");
            showPanel(repeatingButtonCardPanel, "showMeButtonPanel");
            showMeButton.requestFocusInWindow();
        }

        updateSplitPane(repeatingSplitPane, repeatingFrontSideTextArea,
                repeatingReverseSideTextArea);
    }

    // the user did not know the current card when repeating and wants to move
    // it back to the "unlearned" batch
    private void dropCurrentCard() {
        // move current card back to unlearned batch
        putBack(currentCard);
        removeCurrentCard();
        statisticPanel.setLesson(currentLesson);

        if (Pauker.getLearningPhase() == Pauker.LearningPhase.REPEATING_LTM) {
            somethingHasChanged();
        }

        repeatedCardMoved();
    }

    private void putBack(Card card) {
        // move card back to unlearned batch
        Batch unlearnedBatch = currentLesson.getUnlearnedBatch();
        switch (putBackStrategy) {
            case ON_TOP:
                unlearnedBatch.addCard(0, card);
                break;
            case AT_BOTTOM:
                unlearnedBatch.addCard(card);
                break;
            case ANYWHERE:
                int randomIndex = nextRandom(unlearnedBatch.getNumberOfCards());
                unlearnedBatch.addCard(randomIndex, card);
        }
    }

    private void openRecentFile(ActionEvent actionEvent) {
        if (!unsavedChangesOK()) {
            return;
        }

        JMenuItem menuItem = (JMenuItem) actionEvent.getSource();
        String path = menuItem.getText();
        File file = new File(path);
        openFiles(new File[]{file}, null, false);
    }

    private boolean unsavedChangesOK() {
        if (!somethingChanged) {
            return true;
        }

        Object[] options = {
            STRINGS.getString("Save"),
            STRINGS.getString("DontSave"),
            STRINGS.getString("Cancel")
        };

        modalDialogVisible = true;

        questionLabel.setText(STRINGS.getString("Unsaved_Changes_Question"));
        explanationLabel.setText(STRINGS.getString("Unsaved_Changes_Explanation"));
        int result = JOptionPane.showOptionDialog(
                this, questionPanel,
                STRINGS.getString("Question"),
                JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
                null, options, options[0]);

        modalDialogVisible = false;

        switch (result) {
            case 0:
                if (!saveFile(currentFileName, false)) {
                    return false;
                }
                return true;
            case 1:
                return true;
            default:
                return false;
        }

    }

    private void repeatExpiredCard() {
        switch (repeatingStrategy) {
            case OLDEST_FIRST:
                for (int i = currentLesson.getNumberOfLongTermBatches() - 1;
                        i >= 0; i--) {
                    if (expiredCardRepeated(i/*longTermBatchIndex*/)) {
                        return;
                    }
                }
                break;

            case NEWEST_FIRST:
                for (int i = 0, numberOfBatches =
                        currentLesson.getNumberOfLongTermBatches();
                        i < numberOfBatches; i++) {
                    if (expiredCardRepeated(i/*longTermBatchIndex*/)) {
                        return;
                    }
                }
                break;

            case RANDOM_ORDER:
                Card expiredCard = currentLesson.getRandomExpiredCard();
                if (expiredCard != null) {
                    repeatCard(expiredCard);
                    return;
                }
        }

        resetGUI();
    }

    private boolean expiredCardRepeated(int longTermBatchIndex) {
        LongTermBatch longTermBatch = currentLesson.getLongTermBatch(longTermBatchIndex);
        if (longTermBatch.getNumberOfExpiredCards() > 0) {
            Card expiredCard = longTermBatch.getOldestExpiredCard();
            repeatCard(expiredCard);
            return true;
        }
        return false;
    }

    private void learnNewCards() {
        statisticPanel.selectUnlearnedBatch();

        Batch unlearnedBatch = currentLesson.getUnlearnedBatch();
        if (unlearnedBatch.getNumberOfCards() == 1) {
            // we show the last card
            nextNewCardButton.setText(STRINGS.getString("Repeat"));
        } else {
            nextNewCardButton.setText(STRINGS.getString("Next_Card"));
        }

        currentCard = unlearnedBatch.getCard(0);

        fillTextComponentWithCardSide(currentCard.getFrontSide(),
                ustmFrontSideTextArea, true);
        fillTextComponentWithCardSide(currentCard.getReverseSide(),
                ustmReverseSideTextArea, true);

        // update card split button & splitpane
        if (splitOrientation == JSplitPane.HORIZONTAL_SPLIT) {
            switchUSTMLayoutButton.setIcon(new ImageIcon(
                    getClass().getResource("/pauker/icons/view_top_bottom_16.png")));
            switchUSTMLayoutButton.setToolTipText(
                    PaukerFrame.STRINGS.getString("Cardsides_Top_Down"));
        } else {
            switchUSTMLayoutButton.setIcon(new ImageIcon(
                    getClass().getResource("/pauker/icons/view_left_right_16.png")));
            switchUSTMLayoutButton.setToolTipText(
                    PaukerFrame.STRINGS.getString("Cardsides_Left_Right"));
        }
        updateSplitPane(ustmSplitPane, ustmFrontSideTextArea, ustmReverseSideTextArea);

        // flip card layouts
        showPanel(learningCardPanel, "USTMLearningPanel");

        // setting default on nextNewCardButton
        getRootPane().setDefaultButton(null);
        nextNewCardButton.requestFocusInWindow();

        // start ustm timer
        currentUSTMTime = 0;
        ustmTimer.start();
    }

    private void updateSplitPane(JSplitPane splitPane,
            JTextArea frontSideTextArea, JTextArea reverseSideTextArea) {

        // update orientation
        if (splitPane.getOrientation() != splitOrientation) {
            if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
                splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
            } else {
                splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
            }
        }

        // update number of rows
        int lines = frontSideTextArea.getLineCount();
        frontSideTextArea.setRows(lines == 0 ? 1 : lines);
        lines = reverseSideTextArea.getLineCount();
        reverseSideTextArea.setRows(lines == 0 ? 1 : lines);

        // update split position
        splitPane.resetToPreferredSizes();
    }

    private void repeatUSTMCards() {
        Pauker.setLearningPhase(Pauker.LearningPhase.REPEATING_USTM);

        // stop timer
        ustmTimer.stop();
        ustmTimerProgressBar.setValue(0);
        ustmTimerProgressBar.setString("");

        // update layout switch button
        if (splitOrientation == JSplitPane.HORIZONTAL_SPLIT) {
            switchRepeatingLayoutButton.setIcon(new ImageIcon(
                    getClass().getResource("/pauker/icons/view_top_bottom_16.png")));
            switchRepeatingLayoutButton.setToolTipText(
                    PaukerFrame.STRINGS.getString("Cardsides_Top_Down"));
        } else {
            switchRepeatingLayoutButton.setIcon(new ImageIcon(
                    getClass().getResource("/pauker/icons/view_left_right_16.png")));
            switchRepeatingLayoutButton.setToolTipText(
                    PaukerFrame.STRINGS.getString("Cardsides_Left_Right"));
        }

        Card firstUstmCard = currentLesson.getUltraShortTermList().get(0);
        repeatCard(firstUstmCard);
    }

    private void repeatSTMCards() {
        Pauker.setLearningPhase(Pauker.LearningPhase.REPEATING_STM);

        // stop timers
        ustmTimer.stop();
        ustmTimerProgressBar.setValue(0);
        ustmTimerProgressBar.setString("");
        stmTimer.stop();
        stmTimerProgressBar.setValue(0);
        stmTimerProgressBar.setString("");

        setTitle(currentTitle);

        showPanel(learningCardPanel, "transitionPanel");
        getRootPane().setDefaultButton(null);
        transitionOKButton.requestFocusInWindow();
    }

    private void cardChanged(int selectedIndex) {
        loadedBatch.repeatSearch();
        batchListModel.cardsChanged(selectedIndex, selectedIndex);
        // scroll edited card to visible area
        // (because the user may have changed its size)
        batchList.ensureIndexIsVisible(selectedIndex);
        somethingHasChanged();
    }

    /**
     * while repeating cards the user acknowledged that the card was remembered
     * correctly, we have to move the current card one batch further
     */
04169     private void pushCurrentCard() {
        switch (Pauker.getLearningPhase()) {
            case REPEATING_USTM:
                currentLesson.getUltraShortTermList().remove(currentCard);
                currentLesson.getShortTermList().add(currentCard);
                break;

            case REPEATING_STM:
                currentLesson.getShortTermList().remove(currentCard);
                if (currentLesson.getNumberOfLongTermBatches() == 0) {
                    currentLesson.addLongTermBatch();
                }
                LongTermBatch longTermBatch = currentLesson.getLongTermBatch(0);
                longTermBatch.addCard(currentCard);
                currentCard.setLearned(true);
                break;

            case REPEATING_LTM:
                // remove card from current long term memory batch
                int longTermBatchNumber = currentCard.getLongTermBatchNumber();
                int nextLongTermBatchNumber = longTermBatchNumber + 1;
                longTermBatch =
                        currentLesson.getLongTermBatch(longTermBatchNumber);
                longTermBatch.removeCard(currentCard);
                // add card to next long term batch
                if (currentLesson.getNumberOfLongTermBatches() ==
                        nextLongTermBatchNumber) {
                    currentLesson.addLongTermBatch();
                }
                LongTermBatch nextLongTermBatch =
                        currentLesson.getLongTermBatch(nextLongTermBatchNumber);
                nextLongTermBatch.addCard(currentCard);
                currentCard.updateLernedTimeStamp();
                break;

            default:
                throw new RuntimeException("unsupported learning phase \"" +
                        Pauker.getLearningPhase() +
                        "\" -> can't find batch of card!");
        }

        // update statistics
        statisticPanel.setLesson(currentLesson);

        if (Pauker.getLearningPhase() != Pauker.LearningPhase.REPEATING_USTM) {
            somethingHasChanged();
        }

        repeatedCardMoved();
    }

    private void repeatedCardMoved() {
        switch (Pauker.getLearningPhase()) {
            case REPEATING_USTM:
                List<Card> ustmList = currentLesson.getUltraShortTermList();
                if (ustmList.isEmpty()) {
                    if (currentSTMTime == stmTime) {
                        List<Card> stmList = currentLesson.getShortTermList();
                        if (stmList.isEmpty()) {
                            // we are done for now
                            Pauker.setLearningPhase(Pauker.LearningPhase.NOTHING);
                            resetGUI();
                        } else {
                            repeatSTMCards();
                        }
                    } else if (currentLesson.getUnlearnedBatch().getNumberOfCards() == 0) {
                        showPanel(learningCardPanel, "waitForSTMPanel");
                        getRootPane().setDefaultButton(null);
                        repeatSTMButton.requestFocusInWindow();
                        Pauker.setLearningPhase(Pauker.LearningPhase.WAITING_FOR_STM);
                    } else {
                        learnNewCards();
                    }
                } else {
                    Card firstUstmCard = ustmList.get(0);
                    repeatCard(firstUstmCard);
                }
                break;

            case REPEATING_STM:
                List<Card> stmList = currentLesson.getShortTermList();
                if (stmList.isEmpty()) {
                    // we are done for now
                    Pauker.setLearningPhase(Pauker.LearningPhase.NOTHING);
                    resetGUI();
                } else {
                    Card firstStmCard = stmList.get(0);
                    repeatCard(firstStmCard);
                }
                break;

            case REPEATING_LTM:
                repeatExpiredCard();
        }
    }

    private void openAction() {
        if (!unsavedChangesOK()) {
            return;
        }

        if (lastAccessedDirectory != null) {
            openFileDialog.setCurrentDirectory(new File(lastAccessedDirectory));
        }
        openFileDialog.reset();
        openFileDialog.showOpenDialog(this);
    }

    /**
     * Opens the selected files.
     * @param files the selected files
     * @param encoding the encoding of the files
     * @param merging if the files should be merged
     * @return true, if the files could be opened
     */
04284     public boolean openFiles(File[] files, String encoding, boolean merging) {

        String path = null;
        try {
            if (merging) {
                // try opening all lessons before actually merging them
                Lesson[] newLessons = new Lesson[files.length];
                for (int i = 0; i < files.length; i++) {
                    path = files[i].getPath();
                    newLessons[i] = Pauker.openLesson(path, encoding);
                }
                System.out.println("all lessons opened");

                // merge all lessons into the current one
                for (int i = 0; i < newLessons.length; i++) {
                    Lesson newLesson = newLessons[i];
                    if (newLesson.getNumberOfCards() == 0) {
                        System.out.println(files[i] + " contains no cards!");
                    } else {
                        somethingHasChanged();
                        currentLesson.merge(newLesson);
                    }
                }
                System.out.println("all lessons merged");

            } else {
                // open single file
                path = files[0].getPath();
                Lesson newLesson = Pauker.openLesson(path, encoding);

                int lastSeparatorIndex = path.lastIndexOf(File.separatorChar);
                /* Only remember complete directory names.
                 * (We can have relative path names when coming from the command line.
                 *  Then we must not remember anything here...)
                 */
                if (lastSeparatorIndex != -1) {
                    lastAccessedDirectory = path.substring(0, lastSeparatorIndex);
                }
                currentLesson = newLesson;
                currentFileName = path;
                addToRecentFiles(currentFileName);
                somethingChanged = false;
                currentTitle = path.substring(lastSeparatorIndex + 1) + " (" + titleString + ")";
                setTitle(currentTitle);
                saveButton.setEnabled(false);
                saveMenuItem.setEnabled(false);
            }

        } catch (Exception ex) {

            logger.log(Level.SEVERE, "could not open files", ex);

            String errorMessage = MessageFormat.format(
                    STRINGS.getString("Error_Opening_File"), path);
            JOptionPane.showMessageDialog(this, errorMessage,
                    STRINGS.getString("Error"), JOptionPane.ERROR_MESSAGE);

            recentFiles.remove(path);
            recentFilesHaveChanged = true;

            return false;
        }

        // refresh expiration
        currentLesson.refreshExpiration();

        // reset gui
        statisticPanel.setLesson(currentLesson);

        learnNewCardsButton.setEnabled((currentLesson.getUnlearnedBatch()).getNumberOfCards() > 0);
        repeatCardsButton.setEnabled(currentLesson.getNumberOfExpiredCards() > 0);

        settingAboutText = true;
        aboutTextArea.setText(currentLesson.getDescription());
        aboutTextArea.setCaretPosition(0);
        settingAboutText = false;
        showPanel(lessonPanel, "aboutPanel");

        /*
        // limit preferred height of batch list (it is much too high)
        batchListPanel.setPreferredSize(null);
        batchListPanel.doLayout();
        Dimension preferredSize = batchListPanel.getPreferredSize();
        preferredSize.width += 20; // prevent initial horizontal scrollbar
        preferredSize.height = 50;
        batchListPanel.setPreferredSize(preferredSize);
         */

        // TODO: some people like it, some not...
        statisticPanel.setPreferredSize(null);
        Dimension preferredStatisticSize = statisticPanel.getPreferredSize();
        Dimension newSize = new Dimension(preferredStatisticSize);
        newSize.height = 220;
        statisticPanel.setPreferredSize(newSize);

        // the following lines of code are a version of pack() that never
        // shrinks the window
        Dimension currentSize = getSize();
        Dimension preferredSize = getPreferredSize();
        setSize(Math.max(currentSize.width, preferredSize.width),
                Math.max(currentSize.height, preferredSize.height));

        // TODO: background thread?
        searchEngine.init();
        searchEngine.index(currentLesson);

        return true;
    }

    private void addToRecentFiles(String path) {
        // look if entry already exists in list
        boolean entryExists = false;
        int existingIndex = 0;
        for (int i = 0; i < recentFiles.size(); i++) {
            if (path.equals(recentFiles.get(i))) {
                entryExists = true;
                existingIndex = i;
                break;
            }
        }

        if (entryExists) {
            // move to top
            recentFiles.add(0, recentFiles.remove(existingIndex));
        } else {
            // add entry
            recentFiles.add(0, path);
            int size = recentFiles.size();
            if (size > MAX_RECENT_FILES) {
                recentFiles.remove(size - 1);
            }
        }

        recentFilesHaveChanged = true;
    }

    private void newAction() {
        if (!unsavedChangesOK()) {
            return;
        }

        currentLesson = new Lesson();
        currentFileName = null;
        statisticPanel.setLesson(currentLesson);

        settingAboutText = true;
        aboutTextArea.setText(currentLesson.getDescription());
        aboutTextArea.setCaretPosition(0);
        settingAboutText = false;
        showPanel(lessonPanel, "aboutPanel");

        learnNewCardsButton.setEnabled(false);
        repeatCardsButton.setEnabled(false);

        currentTitle = titleString;
        setTitle(currentTitle);

        somethingChanged = false;
        saveButton.setEnabled(false);
        saveMenuItem.setEnabled(false);

        searchEngine.init();
    }

    private boolean saveFile(String fileName, boolean checkOverwrite) {
        if (fileName == null) {
            return saveFileAs();
        }

        // what file format was chosen?
        FileFilter fileFilter = saveFileChooser.getFileFilter();
        try {
            if (fileFilter == csvFileFilter) {
                // export as CSV
                if (!fileName.toLowerCase().endsWith(".csv")) {
                    fileName += ".csv";
                }
                if (checkOverwrite && !overWritingOK(fileName)) {
                    return false;
                }
                String csvData = Pauker.lessonToCSV(currentLesson);
                FileOutputStream fileOutputStream = null;
                try {
                    fileOutputStream = new FileOutputStream(fileName);
                    fileOutputStream.write(csvData.getBytes("UTF-8"));
                    fileOutputStream.flush();
                } finally {
                    if (fileOutputStream != null) {
                        fileOutputStream.close();
                    }
                }
                int lastSeparatorIndex =
                        fileName.lastIndexOf(File.separatorChar);
                if (lastSeparatorIndex != -1) {
                    lastAccessedDirectory =
                            fileName.substring(0, lastSeparatorIndex);
                }

                return true;

            } else {
                // save as normal Pauker lesson
                if (!fileName.endsWith(".pau.gz") &&
                        !fileName.endsWith(".xml.gz")) {
                    if (fileName.endsWith(".pkr")) {
                        fileName = fileName.substring(0, fileName.length() - 4);
                    } else if (fileName.endsWith(".pau")) {
                        fileName = fileName.substring(0, fileName.length() - 4);
                    }
                    fileName += ".pau.gz";
                }
                if (checkOverwrite && !overWritingOK(fileName)) {
                    return false;
                }
                FileOutputStream fileOutputStream = null;
                GZIPOutputStream gzipOutputStream = null;
                try {
                    String xmlData = Pauker.lessonToXML(currentLesson);
                    fileOutputStream = new FileOutputStream(fileName);
                    gzipOutputStream = new GZIPOutputStream(fileOutputStream);
                    gzipOutputStream.write(xmlData.getBytes("UTF-8"));
                    gzipOutputStream.finish();
                    gzipOutputStream.flush();
                    fileOutputStream.flush();
                } catch (OutOfMemoryError oom) {
                    logger.log(Level.SEVERE, "could not save file", oom);
                    String errorMessage = STRINGS.getString("Error_OOM");

                    // check, how Pauker was started
                    boolean showCommandLineHint = false;
                    if (System.getProperty("javawebstart.version") == null) {
                        String javaClassPath =
                                System.getProperty("java.class.path");
                        if (javaClassPath.contains("temp0.jar")) {
                            logger.info("Pauker was started via JSmooth");
                        } else {
                            logger.info("Pauker was started via \"java -jar\"");
                            showCommandLineHint = true;
                        }
                    } else {
                        logger.info("Pauker was started via Java Web Start");
                    }

                    // add a hint depending on how Pauker was started
                    if (showCommandLineHint) {
                        errorMessage += '\n' +
                                STRINGS.getString("Hint_Heap_Command_Line");
                    } else {
                        errorMessage += '\n' +
                                STRINGS.getString("Hint_Heap_Developer");
                    }


                    JOptionPane.showMessageDialog(
                            this, errorMessage,
                            STRINGS.getString("Error"),
                            JOptionPane.ERROR_MESSAGE);

                    return false;

                } finally {
                    if (gzipOutputStream != null) {
                        try {
                            gzipOutputStream.close();
                        } finally {
                            if (fileOutputStream != null) {
                                fileOutputStream.close();
                            }
                        }
                    }
                }

                currentFileName = fileName;
                addToRecentFiles(currentFileName);

                int lastSeparatorIndex = currentFileName.lastIndexOf(File.separatorChar);
                if (lastSeparatorIndex != -1) {
                    lastAccessedDirectory = fileName.substring(0, lastSeparatorIndex);
                }

                currentTitle = currentFileName.substring(lastSeparatorIndex + 1) + " (" + titleString + ")";
                setTitle(currentTitle);
                somethingChanged = false;
                saveButton.setEnabled(false);
                saveMenuItem.setEnabled(false);

                return true;
            }
        } catch (IOException ex) {
            showThrowable(ex);
        } catch (ParserConfigurationException ex) {
            showThrowable(ex);
        } catch (TransformerException ex) {
            showThrowable(ex);
        }

        return false;
    }

    private void showThrowable(Throwable throwable) {
        logger.log(Level.SEVERE, null, throwable);
        JOptionPane.showMessageDialog(
                this, throwable,
                STRINGS.getString("Error"),
                JOptionPane.ERROR_MESSAGE);
    }

    private boolean overWritingOK(String fileName) {
        File testFile = new File(fileName);
        if (testFile.exists()) {
            Object[] options = {
                STRINGS.getString("Overwrite"),
                STRINGS.getString("Cancel")
            };
            String warningMessage = MessageFormat.format(
                    STRINGS.getString("File_Exists_Explanation"),
                    testFile.getName());

            questionLabel.setText(STRINGS.getString("File_Exists_Question"));
            explanationLabel.setText(warningMessage);
            int result = JOptionPane.showOptionDialog(
                    this, questionPanel,
                    STRINGS.getString("Warning"),
                    JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
                    null, options, options[0]);

            if (result != 0) {
                return false;
            }
        }

        return true;
    }

    private boolean saveFileAs() {
        if (lastAccessedDirectory != null) {
            saveFileChooser.setCurrentDirectory(new File(lastAccessedDirectory));
            saveFileChooser.setSelectedFile(null);
        }
        saveFileChooser.setFileFilter(xmlFileFilter);

        int returnValue = saveFileChooser.showSaveDialog(this);

        if (returnValue == JFileChooser.APPROVE_OPTION) {
            return saveFile(saveFileChooser.getSelectedFile().getPath(), true);
        }

        return false;
    }

    private void showNewCardDialog() {
        if (((loadedBatch == currentLesson.getSummaryBatch()) ||
                (loadedBatch == currentLesson.getUnlearnedBatch())) &&
                (batchListModel.getSize() > 100)) {
            // The summary or unlearned batch is showing and it contains a lot
            // of cards.
            // It is a good idea to switch away from this batch, or adding new
            // cards will consume too much list re-rendering time.
            showPanel(lessonPanel, "aboutPanel");
        }

        if (newCardDialog == null) {
            newCardDialog = new NewCardDialog(
                    this, searchEngine, keepNewCardDialogOpen);
            // apply stored settings
            EditCardPanel editCardPanel = newCardDialog.getEditCardPanel();
            JTextComponent textComponent =
                    editCardPanel.getFrontSideTextComponent();
            textComponent.setFont(frontSideFont);
            textComponent.setForeground(frontSideForeground);
            textComponent.setBackground(frontSideBackground);
            textComponent = editCardPanel.getReverseSideTextComponent();
            textComponent.setFont(reverseSideFont);
            textComponent.setForeground(reverseSideForeground);
            textComponent.setBackground(reverseSideBackground);
            editCardPanel.setRepeatByTyping(repeatByTyping);
        } else {
            newCardDialog.reset();
            newCardDialog.setOrientation(splitOrientation);
        }
        newCardDialog.setVisible(true);
        keepNewCardDialogOpen = newCardDialog.isKeepOpenSelected();
    }

    public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
        String propertyName = propertyChangeEvent.getPropertyName();
        if ("focusOwner".equals(propertyName)) {
            Object newFocusOwner = propertyChangeEvent.getNewValue();
            if (newFocusOwner instanceof JButton) {
                JButton button = (JButton) newFocusOwner;
                JRootPane buttonRootPane = button.getRootPane();
                if (buttonRootPane != null) {
                    buttonRootPane.setDefaultButton(button);
                }
            }
        }
    }

    private class MyFocusTraversalPolicy extends LayoutFocusTraversalPolicy {

        @Override
        public Component getComponentAfter(Container container, Component component) {
            if (component.equals(repeatingYesButton)) {
                return repeatingNoButton;
            } else if (component.equals(repeatingNoButton)) {
                return repeatingYesButton;
            } else if (component.equals(moveBackButton)) {
                return ignoreErrorButton;
            } else if (component.equals(ignoreErrorButton)) {
                return moveBackButton;
            }
            return super.getComponentAfter(container, component);
        }

        @Override
        public Component getComponentBefore(Container container, Component component) {
            if (component.equals(repeatingYesButton)) {
                return repeatingNoButton;
            } else if (component.equals(repeatingNoButton)) {
                return repeatingYesButton;
            } else if (component.equals(moveBackButton)) {
                return ignoreErrorButton;
            } else if (component.equals(ignoreErrorButton)) {
                return moveBackButton;
            }
            return super.getComponentBefore(container, component);
        }
    }

    /**
     * returns true, if the case is checked when repeating by typing, false
     * otherwise
     * @return true, if the case is checked when repeating by typing, false
     * otherwise
     */
04719     public boolean isMatchCase() {
        return matchCase;
    }

    /**
     * returns true, if a ringtone should be played when the timer goes off,
     * false otherwise
     * @return true, if a ringtone should be played when the timer goes off,
     * false otherwise
     */
04729     public boolean isPlayRingTone() {
        return playRingTone;
    }

    /**
     * returns the putback strategy
     * @return the putback strategy
     */
04737     public Pauker.PutbackStrategy getPutBackStrategy() {
        return putBackStrategy;
    }

    /**
     * returns the repeating strategy
     * @return the repeating strategy
     */
04745     public Pauker.RepeatingStrategy getRepeatingStrategy() {
        return repeatingStrategy;
    }

    /**
     * returns the search limit (the number of characters a word must have to be
     * included in the search for similar cards)
     * @return the search limit (the number of characters a word must have to be
     * included in the search for similar cards)
     */
04755     public int getSearchLimit() {
        return searchLimit;
    }

    /**
     * returns the configured time for the short-term memory
     * @return the configured time for the short-term memory
     */
04763     public int getStmTime() {
        return stmTime;
    }

    /**
     * returns the configured time for the ultra-short-term memory
     * @return the configured time for the ultra-short-term memory
     */
04771     public int getUstmTime() {
        return ustmTime;
    }

    /**
     * returns the XML file filter
     * @return the XML file filter
     */
04779     public FileFilter getXmlFileFilter() {
        return xmlFileFilter;
    }

    private int nextRandom(int exclusiveMaxValue) {
        // this is important if we put back cards to an empty unlearned batch
        if (exclusiveMaxValue == 0) {
            return 0;
        }

        // lazy creation of random source
        if (random == null) {
            random = new Random();
        }

        return random.nextInt(exclusiveMaxValue);
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel USTMLearningPanel;
    private javax.swing.JMenuItem aboutLessonMenuItem;
    private javax.swing.JPanel aboutPanel;
    private javax.swing.JMenuItem aboutProgramMenuItem;
    private javax.swing.JScrollPane aboutScrollPane;
    private javax.swing.JTextArea aboutTextArea;
    private javax.swing.JButton addCardButton;
    private javax.swing.JMenuItem addCardsMenuitem;
    private javax.swing.JMenuItem ascendingBackMenuItem;
    private javax.swing.JMenuItem ascendingBatchMenuItem;
    private javax.swing.JMenuItem ascendingExpiredMenuItem;
    private javax.swing.JMenuItem ascendingFrontMenuItem;
    private javax.swing.JMenuItem ascendingLearnedMenuItem;
    private javax.swing.JMenu ascendingMenu;
    private javax.swing.JMenuItem ascendingRepeatMenuItem;
    private pauker.program.gui.swing.UpdateLayoutList batchList;
    private javax.swing.JPanel batchListPanel;
    private javax.swing.JScrollPane batchListScrollPane;
    private javax.swing.JPanel batchPanel;
    private javax.swing.JPanel buttonPanel;
    private javax.swing.JButton cancelLearningButton;
    private javax.swing.JButton cancelRepeatingButton;
    private javax.swing.JPanel cancelRepeatingPanel;
    private javax.swing.JPanel cardPanel;
    private javax.swing.JPanel cardsButtonPanel;
    private javax.swing.JMenuItem configureMenuItem;
    private javax.swing.JMenuItem descendingBackMenuItem;
    private javax.swing.JMenuItem descendingBatchMenuItem;
    private javax.swing.JMenuItem descendingExpiredMenuItem;
    private javax.swing.JMenuItem descendingFrontMenuItem;
    private javax.swing.JMenuItem descendingLearnedMenuItem;
    private javax.swing.JMenu descendingMenu;
    private javax.swing.JMenuItem descendingRepeatMenuItem;
    private javax.swing.JLabel didYouKnowLabel;
    private javax.swing.JMenuItem donateMenuItem;
    private javax.swing.JButton downButton;
    private javax.swing.JButton editCardButton;
    private javax.swing.JButton editTypingErrorButton;
    private javax.swing.JButton editWhileMemorizingButton;
    private javax.swing.JButton editWhileRepeatingButton;
    private javax.swing.JMenuItem exitMenuItem;
    private javax.swing.JLabel explanationLabel;
    private javax.swing.JMenu extraMenu;
    private javax.swing.JMenu fileMenu;
    private javax.swing.JMenuItem flipCardSidesMenuItem;
    private javax.swing.JButton fontButton;
    private javax.swing.JButton forgetButton;
    private javax.swing.JPanel fullTimerPanel;
    private javax.swing.JMenu helpMenu;
    private javax.swing.JMenuItem helpMenuItem;
    private javax.swing.JMenuItem hideToolBarMenuItem;
    private javax.swing.JButton ignoreErrorButton;
    private javax.swing.JMenuItem importMenuItem;
    private javax.swing.JLabel infoLabel;
    private javax.swing.JLabel inputLabel;
    private javax.swing.JPanel inputPanel;
    private javax.swing.JScrollPane inputScrollPane;
    private javax.swing.JTextArea inputTextArea;
    private javax.swing.JLabel insertReverseSideLabel;
    private javax.swing.JButton instantRepeatButton;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JSeparator jSeparator2;
    private javax.swing.JSeparator jSeparator3;
    private javax.swing.JSeparator jSeparator4;
    private javax.swing.JSeparator jSeparator5;
    private javax.swing.JButton learnNewCardsButton;
    private javax.swing.JPanel learningCardPanel;
    private javax.swing.JLabel learningLabel;
    private javax.swing.JPanel learningMenuHeaderPanel;
    private javax.swing.JButton learningMethodButton;
    private javax.swing.JPanel learningPanel;
    private javax.swing.JPopupMenu learningPopupMenu;
    private javax.swing.JPanel learningStatusPanel;
    private javax.swing.JPanel lessonPanel;
    private javax.swing.JMenuBar mainMenuBar;
    private javax.swing.JButton moveBackButton;
    private javax.swing.JButton newButton;
    private javax.swing.JMenuItem newMenuItem;
    private javax.swing.JButton nextNewCardButton;
    private javax.swing.JPanel noTimerPanel;
    private javax.swing.JButton openButton;
    private javax.swing.JMenuItem openMenuItem;
    private javax.swing.JPanel overviewPanel;
    private javax.swing.JToggleButton pauseLearningToggleButton;
    private javax.swing.JPanel questionButtonPanel;
    private javax.swing.JLabel questionLabel;
    private javax.swing.JPanel questionPanel;
    private javax.swing.JButton randomizeButton;
    private javax.swing.JMenu recentFilesMenu;
    private javax.swing.JMenuItem remeberMenuItem;
    private javax.swing.JButton removeCardButton;
    private javax.swing.JButton removeRepeatingButton;
    private javax.swing.JButton removeUstmButton;
    private javax.swing.JButton repeatCardsButton;
    private javax.swing.JButton repeatSTMButton;
    private javax.swing.JButton repeatUSTMButton;
    private javax.swing.JPanel repeatingAskPanel;
    private javax.swing.JPanel repeatingButtonCardPanel;
    private javax.swing.JLabel repeatingCardFrontSideLabel;
    private javax.swing.JPanel repeatingCardPanel;
    private javax.swing.JLabel repeatingCardReverseSideLabel;
    private javax.swing.JPanel repeatingFrontSidePanel;
    private javax.swing.JScrollPane repeatingFrontSideScrollPane;
    private javax.swing.JTextArea repeatingFrontSideTextArea;
    private javax.swing.JLabel repeatingHintLabel;
    private javax.swing.JPanel repeatingInsertPanel;
    private javax.swing.JScrollPane repeatingInsertScrollPane;
    private javax.swing.JTextArea repeatingInsertTextArea;
    private javax.swing.JButton repeatingNoButton;
    private javax.swing.JPanel repeatingPanel;
    private javax.swing.JPanel repeatingReverseSidePanel;
    private javax.swing.JScrollPane repeatingReverseSideScrollPane;
    private javax.swing.JTextArea repeatingReverseSideTextArea;
    private javax.swing.JPanel repeatingShowPanel;
    private javax.swing.JSplitPane repeatingSplitPane;
    private javax.swing.JButton repeatingYesButton;
    private javax.swing.JMenuItem resetMenuItem;
    private javax.swing.JLabel reverseLabel;
    private javax.swing.JPanel reversePanel;
    private javax.swing.JScrollPane reverseScrollPane;
    private javax.swing.JTextArea reverseTextArea;
    private javax.swing.JMenuItem saveAsMenuItem;
    private javax.swing.JButton saveButton;
    private javax.swing.JMenuItem saveMenuItem;
    private javax.swing.JButton searchButton;
    private javax.swing.JSeparator separator1;
    private javax.swing.JSeparator separator2;
    private javax.swing.JSeparator separator4;
    private javax.swing.JButton showMeButton;
    private javax.swing.JPanel showMeButtonPanel;
    private javax.swing.JCheckBox showTimerCheckBox;
    private javax.swing.JCheckBoxMenuItem showToolBarMenuItem;
    private javax.swing.JButton sortButton;
    private javax.swing.JLabel sortingLabel;
    private javax.swing.JPanel sortingMenuHeaderPanel;
    private javax.swing.JPopupMenu sortingPopupMenu;
    private javax.swing.JSplitPane splitPane;
    private pauker.program.gui.swing.StatisticPanel statisticPanel;
    private javax.swing.JLabel stmTimerLabel;
    private javax.swing.JProgressBar stmTimerProgressBar;
    private javax.swing.JButton switchRepeatingLayoutButton;
    private javax.swing.JButton switchUSTMLayoutButton;
    private javax.swing.JPanel timerCardPanel;
    private javax.swing.JPanel timerGridPanel1;
    private javax.swing.JPanel timerGridPanel2;
    private javax.swing.JPanel timerPanel;
    private javax.swing.JToolBar toolBar;
    private javax.swing.JPopupMenu toolBarPopupMenu;
    private javax.swing.JLabel transitionExplanationLabel;
    private javax.swing.JButton transitionOKButton;
    private javax.swing.JPanel transitionPanel;
    private javax.swing.JLabel transitoinIconLabel;
    private javax.swing.JMenuItem typeMenuItem;
    private javax.swing.JPanel typingErrorPanel;
    private javax.swing.JSplitPane typingErrorSplitPane;
    private javax.swing.JButton typingOKButton;
    private javax.swing.JPanel typingOKPanel;
    private javax.swing.JButton upButton;
    private javax.swing.JLabel ustmFrontSideLabel;
    private javax.swing.JPanel ustmFrontSidePanel;
    private javax.swing.JScrollPane ustmFrontSideScrollPane;
    private javax.swing.JTextArea ustmFrontSideTextArea;
    private javax.swing.JLabel ustmReverseSideLabel;
    private javax.swing.JPanel ustmReverseSidePanel;
    private javax.swing.JScrollPane ustmReverseSideScrollPane;
    private javax.swing.JTextArea ustmReverseSideTextArea;
    private javax.swing.JSplitPane ustmSplitPane;
    private javax.swing.JLabel ustmTimerLabel;
    private javax.swing.JProgressBar ustmTimerProgressBar;
    private javax.swing.JLabel waitForSTMLabel;
    private javax.swing.JPanel waitForSTMPanel;
    private javax.swing.JLabel waitForUSTMLabel;
    private javax.swing.JPanel waitForUSTMPanel;
    // End of variables declaration//GEN-END:variables
}

Generated by  Doxygen 1.6.0   Back to index