- Just some generification.
[speedith:speedith.git] / devel / Speedith / src / speedith / ui / selection / SelectionPanel.java
1 /*
2  *   Project: Speedith
3  * 
4  * File name: SelectionPanel.java
5  *    Author: Matej Urbas [matej.urbas@gmail.com]
6  * 
7  *  Copyright © 2012 Matej Urbas
8  * 
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  * 
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  * 
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25  * THE SOFTWARE.
26  */
27 package speedith.ui.selection;
28
29 import speedith.core.reasoning.args.selection.SelectionSequence;
30 import speedith.ui.CirclesPanel2;
31 import java.awt.event.ActionEvent;
32 import java.awt.event.ActionListener;
33 import java.util.*;
34 import javax.swing.DefaultListModel;
35 import speedith.core.lang.SpiderDiagram;
36 import speedith.core.reasoning.args.RuleArg;
37 import static speedith.i18n.Translations.i18n;
38 import speedith.ui.SpiderDiagramClickEvent;
39 import speedith.core.reasoning.args.selection.SelectionStep;
40 import speedith.core.reasoning.args.selection.SelectionStep.SelectionRejectionExplanation;
41
42 /**
43  * This is a GUI component that provides a step-by-step selection process on a
44  * selected spider diagram.<p>This is useful for interactively providing
45  * parameters for the application of an inference rule.</p> 
46  * <p>{@link SelectionDialog The selection dialog} may be more convenient for
47  * most use cases (as its use is quite straight-forward).</p>
48  *
49  * @author Matej Urbas [matej.urbas@gmail.com]
50  */
51 public class SelectionPanel extends javax.swing.JPanel {
52
53     // <editor-fold defaultstate="collapsed" desc="Fields">
54     private SelectionSequenceMutable selection;
55     private int curStep = -1;
56     private final DefaultListModel<String> selectionListModel = new DefaultListModel<String>();
57     private ArrayList<ActionListener> actionListeners;
58     /**
59      * This value is given as the {@link ActionEvent#getID() action ID} in the
60      * {@link SelectionPanel#addActionListener(java.awt.event.ActionListener)
61      * selection concluded event} if the user pressed on the <span
62      * style="font-style:italic;">finish</span> button.
63      */
64     public final static int Finish = 0;
65     /**
66      * This value is given as the {@link ActionEvent#getID() action ID} in the
67      * {@link SelectionPanel#addActionListener(java.awt.event.ActionListener)
68      * selection concluded event} if the user pressed on the <span
69      * style="font-style:italic;">finish</span> cancel.
70      */
71     public final static int Cancel = 1;
72     // </editor-fold>
73
74     //<editor-fold defaultstate="collapsed" desc="Constructors">
75     /**
76      * Initialises the selection panel with no diagram and no selection steps.
77      */
78     public SelectionPanel() {
79         initComponents();
80         refreshUI();
81     }
82
83     /**
84      * Initialises this selection panel with the given selection steps. <p><span
85      * style="font-weight:bold">Note</span>: this constructor makes a copy of
86      * the given array.</p>
87      *
88      * @param diagram the diagram from which to select elements.
89      * @param selectionSteps the selection steps this panel should display to
90      * the user.
91      */
92     public SelectionPanel(SpiderDiagram diagram, SelectionStep... selectionSteps) {
93         this(diagram, selectionSteps == null || selectionSteps.length == 0 ? null : new ArrayList<SelectionStep>(Arrays.asList(selectionSteps)));
94     }
95
96     /**
97      * Initialises this selection panel with the given selection steps. <p><span
98      * style="font-weight:bold">Note</span>: this constructor makes a copy of
99      * the given collection.</p>
100      *
101      * @param diagram the diagram from which to select elements.
102      * @param selectionSteps the selection steps this panel should display to
103      * the user.
104      */
105     public SelectionPanel(SpiderDiagram diagram, Collection<SelectionStep> selectionSteps) {
106         this(diagram, selectionSteps == null || selectionSteps.isEmpty() ? null : new ArrayList<SelectionStep>(selectionSteps));
107     }
108
109     /**
110      * Initialises this selection panel with the given selection steps. <p><span
111      * style="font-weight:bold">Note</span>: this constructor does not make a
112      * copy of the given array list.</p>
113      *
114      * @param diagram the diagram from which to select elements.
115      * @param selectionSteps the selection steps this panel should display to
116      * the user.
117      */
118     SelectionPanel(SpiderDiagram diagram, ArrayList<SelectionStep> selectionSteps) {
119         initComponents();
120         resetDiagramAndSelectionSteps(diagram, selectionSteps);
121     }
122     // </editor-fold>
123
124     //<editor-fold defaultstate="collapsed" desc="Autogenerated Code">
125     /**
126      * This method is called from within the constructor to initialize the form.
127      * WARNING: Do NOT modify this code. The content of this method is always
128      * regenerated by the Form Editor.
129      */
130     @SuppressWarnings("unchecked")
131     // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
132     private void initComponents() {
133
134         errorMessage = new javax.swing.JLabel();
135         stepInstructionMessage = new javax.swing.JLabel();
136         stepNumber = new javax.swing.JLabel();
137         finishButton = new javax.swing.JButton();
138         clearButton = new javax.swing.JButton();
139         nextButton = new javax.swing.JButton();
140         cancelButton = new javax.swing.JButton();
141         previousButton = new javax.swing.JButton();
142         diagramAndSelectionPanel = new javax.swing.JSplitPane();
143         jScrollPane2 = new javax.swing.JScrollPane();
144         spiderDiagramPanel = new speedith.ui.SpiderDiagramPanel();
145         selectionPanel = new javax.swing.JPanel();
146         selectionLabel = new javax.swing.JLabel();
147         javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane();
148         selectionList = new javax.swing.JList();
149
150         errorMessage.setFont(new java.awt.Font("Dialog", 0, 12)); // NOI18N
151         errorMessage.setForeground(new java.awt.Color(204, 0, 0));
152         errorMessage.setText("* Error message...");
153
154         stepInstructionMessage.setFont(new java.awt.Font("Dialog", 2, 12)); // NOI18N
155         stepInstructionMessage.setText("Step instruction message...");
156
157         stepNumber.setFont(new java.awt.Font("Dialog", 3, 12)); // NOI18N
158         stepNumber.setText("Step 1 of 5: ");
159
160         finishButton.setMnemonic(i18n("GSTR_FINISH_BUTTON_MNEMONIC").charAt(0));
161         finishButton.setText(i18n("GSTR_FINISH_BUTTON_TEXT")); // NOI18N
162         finishButton.setEnabled(false);
163         finishButton.addActionListener(new java.awt.event.ActionListener() {
164             public void actionPerformed(java.awt.event.ActionEvent evt) {
165                 finishButtonActionPerformed(evt);
166             }
167         });
168
169         clearButton.setMnemonic(i18n("GSTR_CLEAR_BUTTON_MNEMONIC").charAt(0));
170         clearButton.setText(i18n("GSTR_CLEAR_BUTTON_TEXT")); // NOI18N
171         clearButton.setToolTipText(i18n("SELSEQ_CLEAR_SELECTION")); // NOI18N
172         clearButton.setEnabled(false);
173         clearButton.addActionListener(new java.awt.event.ActionListener() {
174             public void actionPerformed(java.awt.event.ActionEvent evt) {
175                 clearButtonActionPerformed(evt);
176             }
177         });
178
179         nextButton.setMnemonic(i18n("GSTR_NEXT_BUTTON_MNEMONIC").charAt(0));
180         nextButton.setText(i18n("GSTR_NEXT_BUTTON_TEXT")); // NOI18N
181         nextButton.setEnabled(false);
182         nextButton.addActionListener(new java.awt.event.ActionListener() {
183             public void actionPerformed(java.awt.event.ActionEvent evt) {
184                 nextButtonActionPerformed(evt);
185             }
186         });
187
188         cancelButton.setMnemonic(i18n("GSTR_CANCEL_BUTTON_MNEMONIC").charAt(0));
189         cancelButton.setText(i18n("GSTR_CANCEL_BUTTON_TEXT")); // NOI18N
190         cancelButton.addActionListener(new java.awt.event.ActionListener() {
191             public void actionPerformed(java.awt.event.ActionEvent evt) {
192                 cancelButtonActionPerformed(evt);
193             }
194         });
195
196         previousButton.setMnemonic(i18n("GSTR_PREVIOUS_BUTTON_MNEMONIC").charAt(0));
197         previousButton.setText(i18n("GSTR_PREVIOUS_BUTTON_TEXT")); // NOI18N
198         previousButton.setEnabled(false);
199         previousButton.addActionListener(new java.awt.event.ActionListener() {
200             public void actionPerformed(java.awt.event.ActionEvent evt) {
201                 previousButtonActionPerformed(evt);
202             }
203         });
204
205         jScrollPane2.setMinimumSize(new java.awt.Dimension(450, 250));
206         jScrollPane2.setPreferredSize(new java.awt.Dimension(450, 250));
207
208         spiderDiagramPanel.addSpiderDiagramClickListener(new speedith.ui.SpiderDiagramClickListener() {
209             public void spiderDiagramClicked(speedith.ui.SpiderDiagramClickEvent evt) {
210                 onSpiderDiagramClicked(evt);
211             }
212         });
213         jScrollPane2.setViewportView(spiderDiagramPanel);
214
215         diagramAndSelectionPanel.setLeftComponent(jScrollPane2);
216
217         selectionPanel.setMinimumSize(new java.awt.Dimension(75, 150));
218         selectionPanel.setPreferredSize(new java.awt.Dimension(75, 150));
219
220         selectionLabel.setText("Selection:");
221
222         selectionList.setFont(new java.awt.Font("Dialog", 0, 12)); // NOI18N
223         selectionList.setModel(selectionListModel);
224         jScrollPane1.setViewportView(selectionList);
225
226         javax.swing.GroupLayout selectionPanelLayout = new javax.swing.GroupLayout(selectionPanel);
227         selectionPanel.setLayout(selectionPanelLayout);
228         selectionPanelLayout.setHorizontalGroup(
229             selectionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
230             .addGroup(selectionPanelLayout.createSequentialGroup()
231                 .addGap(0, 0, 0)
232                 .addGroup(selectionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
233                     .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
234                     .addComponent(selectionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 152, Short.MAX_VALUE))
235                 .addGap(0, 0, 0))
236         );
237         selectionPanelLayout.setVerticalGroup(
238             selectionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
239             .addGroup(selectionPanelLayout.createSequentialGroup()
240                 .addComponent(selectionLabel)
241                 .addGap(3, 3, 3)
242                 .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 243, Short.MAX_VALUE)
243                 .addGap(0, 0, 0))
244         );
245
246         diagramAndSelectionPanel.setRightComponent(selectionPanel);
247
248         javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
249         this.setLayout(layout);
250         layout.setHorizontalGroup(
251             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
252             .addGroup(layout.createSequentialGroup()
253                 .addComponent(finishButton)
254                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 139, Short.MAX_VALUE)
255                 .addComponent(previousButton)
256                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
257                 .addComponent(clearButton)
258                 .addGap(124, 124, 124)
259                 .addComponent(nextButton)
260                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
261                 .addComponent(cancelButton))
262             .addComponent(diagramAndSelectionPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
263             .addGroup(layout.createSequentialGroup()
264                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
265                     .addGroup(layout.createSequentialGroup()
266                         .addComponent(stepNumber)
267                         .addGap(1, 1, 1)
268                         .addComponent(stepInstructionMessage, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
269                     .addComponent(errorMessage, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
270                 .addContainerGap())
271         );
272         layout.setVerticalGroup(
273             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
274             .addGroup(layout.createSequentialGroup()
275                 .addComponent(diagramAndSelectionPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 263, Short.MAX_VALUE)
276                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
277                 .addComponent(errorMessage)
278                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
279                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
280                     .addComponent(stepNumber)
281                     .addComponent(stepInstructionMessage))
282                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
283                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
284                     .addComponent(cancelButton)
285                     .addComponent(nextButton)
286                     .addComponent(clearButton)
287                     .addComponent(finishButton)
288                     .addComponent(previousButton)))
289         );
290     }// </editor-fold>//GEN-END:initComponents
291
292     private void finishButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_finishButtonActionPerformed
293         fireSelectionEnd(Finish);
294     }//GEN-LAST:event_finishButtonActionPerformed
295
296     private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed
297         clearCurStepSelection(true, true);
298     }//GEN-LAST:event_clearButtonActionPerformed
299
300     private void nextButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextButtonActionPerformed
301         goToNextStep(true, true);
302     }//GEN-LAST:event_nextButtonActionPerformed
303
304     private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
305         fireSelectionEnd(Cancel);
306     }//GEN-LAST:event_cancelButtonActionPerformed
307
308     private void previousButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_previousButtonActionPerformed
309         goToPreviousStep(true);
310     }//GEN-LAST:event_previousButtonActionPerformed
311
312     private void onSpiderDiagramClicked(speedith.ui.SpiderDiagramClickEvent evt) {//GEN-FIRST:event_onSpiderDiagramClicked
313         SelectionStep curSelStep = getCurSelStep();
314         if (curSelStep != null && getCurrentStep() >= 0 && getCurrentStep() < getStepCount()) {
315             SelectionRejectionExplanation result = curSelStep.acceptSelection(evt.toRuleArg(), selection, getCurrentStep());
316             if (result == null) {
317                 selection.addAcceptedClick(getCurrentStep(), evt, evt.toRuleArg());
318                 // Check if the step is finished. If it is, go to the next one:
319                 goToNextStep(false, false);
320                 refreshUI();
321             } else {
322                 setErrorMsg(result.getExplanation());
323             }
324         }
325     }//GEN-LAST:event_onSpiderDiagramClicked
326     // Variables declaration - do not modify//GEN-BEGIN:variables
327     private javax.swing.JButton cancelButton;
328     private javax.swing.JButton clearButton;
329     private javax.swing.JSplitPane diagramAndSelectionPanel;
330     private javax.swing.JLabel errorMessage;
331     private javax.swing.JButton finishButton;
332     private javax.swing.JScrollPane jScrollPane2;
333     private javax.swing.JButton nextButton;
334     private javax.swing.JButton previousButton;
335     private javax.swing.JLabel selectionLabel;
336     private javax.swing.JList selectionList;
337     private javax.swing.JPanel selectionPanel;
338     private speedith.ui.SpiderDiagramPanel spiderDiagramPanel;
339     private javax.swing.JLabel stepInstructionMessage;
340     private javax.swing.JLabel stepNumber;
341     // End of variables declaration//GEN-END:variables
342     //</editor-fold>
343
344     // <editor-fold defaultstate="collapsed" desc="Public Properties">
345     /**
346      * Returns the current selection.
347      *
348      * @return the current selection.
349      */
350     public SelectionSequence getSelection() {
351         return selection;
352     }
353
354     /**
355      * @return the index of the current step.
356      */
357     public int getCurrentStep() {
358         return curStep;
359     }
360
361     /**
362      * Returns the currently displayed diagram (the diagram from which the user
363      * should choose elements).
364      *
365      * @return the currently displayed diagram (the diagram from which the user
366      * should choose elements).
367      */
368     public SpiderDiagram getDiagram() {
369         return this.spiderDiagramPanel.getDiagram();
370     }
371
372     /**
373      * Sets the new diagram to be displayed (the diagram from which the user
374      * should choose elements).
375      *
376      * @param diagram the new diagram to be displayed (the diagram from which
377      * the user should choose elements).
378      */
379     public void setDiagram(SpiderDiagram diagram) {
380         // Since we have changed the diagram, we also have to reset the current
381         // selection (as there are no guarantees that the selection will remain
382         // valid after the change of the diagram).
383         selection.clearCurrentSelection();
384         selection.setDiagram(diagram);
385         resetDiagram(diagram, true);
386     }
387
388     /**
389      * Returns the selection steps that will guide the user through the
390      * diagrammatic-element selection process.
391      *
392      * @return the selection steps that will guide the user through the
393      * diagrammatic-element selection process.
394      */
395     public List<SelectionStep> getSelectionSteps() {
396         return getSelection().getSelectionSteps();
397     }
398
399     /**
400      * Sets the selection steps that will guide the user through the
401      * diagrammatic-element selection process.
402      *
403      * @param steps the selection steps that will guide the user through the
404      * diagrammatic-element selection process.
405      */
406     public void setSelectionSteps(SelectionStep... steps) {
407         resetSelectionSteps(new ArrayList<SelectionStep>(Arrays.asList(steps)), true);
408     }
409
410     /**
411      * Sets the selection steps that will guide the user through the
412      * diagrammatic-element selection process.
413      *
414      * @param steps the selection steps that will guide the user through the
415      * diagrammatic-element selection process.
416      */
417     public void setSelectionSteps(Collection<SelectionStep> steps) {
418         resetSelectionSteps(new ArrayList<SelectionStep>(steps), true);
419     }
420
421     public void setDiagramAndSelectionSteps(SpiderDiagram diagram, Collection<? extends SelectionStep> steps) {
422         resetDiagramAndSelectionSteps(diagram, new ArrayList<SelectionStep>(steps));
423     }
424     // </editor-fold>
425
426     // <editor-fold defaultstate="collapsed" desc="Events">
427     /**
428      * Registers the given {@link ActionListener selection concluded
429      * listener}. <p>This {@link ActionListener#actionPerformed(java.awt.event.ActionEvent)
430      * event} is invoked whenever the user presses the <span
431      * style="font-style:italic;">finish</span> or the <span
432      * style="font-style:italic;">cancel</span> button.</p> <p>If the user
433      * clicked <span style="font-style:italic;">cancel</span> then the
434      * {@link ActionEvent#getID()} will be set to {@link SelectionPanel#Cancel}.
435      * Otherwise, in case the user pressed the <span
436      * style="font-style:italic;">finish</span> button, the ID will be set to
437      * {@link SelectionPanel#Finish}.</p>
438      *
439      * @param l the event listener to register.
440      */
441     public void addActionListener(ActionListener l) {
442         if (actionListeners == null) {
443             actionListeners = new ArrayList<ActionListener>();
444         }
445         this.actionListeners.add(l);
446     }
447
448     /**
449      * Removes the given {@link ActionListener selection concluded event listener}
450      * from the selection concluded event. <p>The given listener will no longer
451      * receive these events.</p>
452      *
453      * @param l the event listener to deregister.
454      */
455     public void removeActionListener(ActionListener l) {
456         if (actionListeners != null) {
457             actionListeners.remove(l);
458         }
459     }
460
461     /**
462      * Returns the array of all {@link SelectionPanel#addActionListener(ActionListener) registered}
463      * {@link ActionListener selection concluded listeners}.
464      *
465      * @return the array of all {@link SelectionPanel#addActionListener(ActionListener) registered}
466      * {@link ActionListener selection concluded listeners}.
467      */
468     public ActionListener[] getActionListeners() {
469         return listenerList.getListeners(ActionListener.class);
470     }
471
472     protected final void fireSelectionEnd(int actionID) {
473         if (actionListeners != null && actionListeners.size() > 0) {
474             ActionEvent ae = new ActionEvent(this, actionID, null);
475             for (ActionListener actionListener : actionListeners) {
476                 actionListener.actionPerformed(ae);
477             }
478         }
479     }
480     // </editor-fold>
481
482     // <editor-fold defaultstate="collapsed" desc="UI Refresh Methods">
483     private void refreshStepInstructionLabel() {
484         if (selection == null
485                 || getCurrentStep() < 0
486                 || getCurrentStep() >= getStepCount()) {
487             stepInstructionMessage.setText(null);
488         } else {
489             String instruction = selection.getSelectionStepAt(getCurrentStep()).getInstruction(selection, getCurrentStep());
490             stepInstructionMessage.setText(instruction);
491         }
492     }
493
494     private void refreshStepLabel() {
495         if (getCurrentStep() >= getStepCount()) {
496             stepNumber.setText(i18n("SELSEQ_STEP_FINISHED"));
497         } else if (getStepCount() > 1) {
498             stepNumber.setText(i18n("SELSEQ_STEP_N_OF_M", getCurrentStep() + 1, selection.getSelectionStepsCount()));
499         } else {
500             stepNumber.setText(null);
501         }
502     }
503
504     private void refreshUI() {
505         refreshAllButtons();
506         refreshDiagramPanel();
507         refreshAllLabels();
508         refreshSelectionList();
509     }
510
511     private void resetDiagram(SpiderDiagram diagram, boolean resetUI) throws IllegalArgumentException {
512         if (diagram == null) {
513             throw new IllegalArgumentException("The argument 'diagram' must not be null.");
514         }
515         this.spiderDiagramPanel.setDiagram(diagram);
516         if (resetUI) {
517             resetCurStepAndUI();
518         }
519     }
520
521     private void resetSelectionSteps(ArrayList<SelectionStep> selectionSteps, boolean resetUI) throws IllegalArgumentException {
522         if (selectionSteps == null || selectionSteps.isEmpty()) {
523             throw new IllegalArgumentException(speedith.core.i18n.Translations.i18n("GERR_EMPTY_ARGUMENT", "selectionSteps"));
524         }
525         // The collection of selection steps must not contain any null values.
526         for (SelectionStep selectionStep : selectionSteps) {
527             if (selectionStep == null) {
528                 throw new IllegalArgumentException(i18n("SELSEQ_NULL_STEPS"));
529             }
530         }
531         this.selection = new SelectionSequenceMutable(getDiagram(), selectionSteps);
532         if (resetUI) {
533             resetCurStepAndUI();
534         }
535     }
536
537     private void resetCurStepAndUI() {
538         // Some extra initialisation:
539         this.curStep = 0;
540         initiateStep();
541         refreshUI();
542     }
543
544     private void setErrorMsg(String msg) {
545         if (msg == null || msg.isEmpty()) {
546             errorMessage.setText(null);
547         } else {
548             errorMessage.setText(i18n("SELSEQ_ERROR_MSG", msg));
549         }
550     }
551
552     private void refreshAllLabels() {
553         refreshStepInstructionLabel();
554         refreshStepLabel();
555         setErrorMsg(null);
556     }
557
558     private void refreshAllButtons() {
559         refreshNextButton();
560         refreshPreviousButton();
561         refreshFinishButton();
562         refreshClearButton();
563     }
564
565     private void refreshNextButton() {
566         nextButton.setEnabled(selection != null && getCurrentStep() < getStepCount() - 1 && getCurSelStep().isSkippable(selection, getCurrentStep()));
567     }
568
569     /**
570      * The user can finish the selection only if all steps are skippable.
571      */
572     private void refreshFinishButton() {
573         if (selection != null) {
574             boolean canFinish = true;
575             for (int i = getCurrentStep(); i < getStepCount(); i++) {
576                 SelectionStep selStep = selection.getSelectionStepAt(i);
577                 if (!selStep.isSkippable(selection, i) && !selStep.isFinished(selection, i)) {
578                     canFinish = false;
579                     break;
580                 }
581             }
582             finishButton.setEnabled(canFinish);
583         } else {
584             finishButton.setEnabled(false);
585         }
586     }
587
588     private void refreshPreviousButton() {
589         previousButton.setEnabled(selection != null && getCurrentStep() > 0);
590     }
591
592     private void refreshClearButton() {
593         clearButton.setEnabled(selection != null && getCurSelStep() != null && selection.getAcceptedSelectionsCount(getCurrentStep()) > 0);
594     }
595
596     private void refreshDiagramPanel() {
597         // Disable highlighting in the diagram, if the whole thing is finished:
598         spiderDiagramPanel.setHighlightMode(getCurSelStep() == null || getCurrentStep() >= getStepCount() ? SelectionStep.None : getCurSelStep().getSelectableElements());
599     }
600
601     private void refreshSelectionList() {
602         selectionListModel.clear();
603         if (getCurSelStep() != null && selection.getAcceptedSelectionsCount(getCurrentStep()) > 0) {
604             for (SpiderDiagramClickEvent selectedElement : selection.acceptedClicks[getCurrentStep()]) {
605                 selectionListModel.addElement(selectedElement.toString());
606             }
607         }
608     }
609     // </editor-fold>
610
611     // <editor-fold defaultstate="collapsed" desc="Internal Logic Methods">
612     private void clearCurStepSelection(boolean force, boolean refreshUIIfChange) {
613         // Check whether we should clean the selection on starting this step?
614         SelectionStep curSelStep = getCurSelStep();
615         if (curSelStep != null && (force || curSelStep.cleanSelectionOnStart())) {
616             selection.clearCurrentSelection(getCurrentStep());
617             if (refreshUIIfChange) {
618                 refreshUI();
619             }
620         }
621     }
622
623     private void goToNextStep(boolean skip, boolean refreshUIIfNext) {
624         SelectionStep curSelStep = getCurSelStep();
625         if (curSelStep != null && (skip || curSelStep.isFinished(selection, getCurrentStep()))) {
626             ++curStep;
627             clearCurStepSelection(false, false);
628             initiateStep();
629             if (refreshUIIfNext) {
630                 refreshUI();
631             }
632         }
633     }
634
635     private void goToPreviousStep(boolean refreshUIIfChange) {
636         if (getCurrentStep() > 0) {
637             --curStep;
638             SelectionStep curSelStep = getCurSelStep();
639             clearCurStepSelection(false, false);
640             initiateStep();
641             if (refreshUIIfChange) {
642                 refreshUI();
643             }
644         }
645     }
646
647     public void initiateStep() {
648         SelectionStep curSelStep = getCurSelStep();
649         if (curSelStep != null) {
650             getCurSelStep().init(selection, getCurrentStep());
651         }
652     }
653
654     /**
655      * This method displays the diagram, sets the new selection steps and resets
656      * the UI.
657      *
658      * @param diagram
659      * @param selectionSteps
660      * @throws IllegalArgumentException
661      */
662     private void resetDiagramAndSelectionSteps(SpiderDiagram diagram, ArrayList<SelectionStep> selectionSteps) throws IllegalArgumentException {
663         resetDiagram(diagram, false);
664         resetSelectionSteps(selectionSteps, false);
665         resetCurStepAndUI();
666     }
667     // </editor-fold>
668
669     // <editor-fold defaultstate="collapsed" desc="Private Properties">
670     private SelectionStep getCurSelStep() {
671         return getCurrentStep() >= getStepCount() || getCurrentStep() < 0 || selection == null ? null : selection.getSelectionStepAt(getCurrentStep());
672     }
673
674     private int getStepCount() {
675         return selection == null ? 0 : selection.getSelectionStepsCount();
676     }
677     // </editor-fold>
678
679     //<editor-fold defaultstate="collapsed" desc="Helper Classes">
680     private static class SelectionSequenceMutable extends SelectionSequence {
681
682         protected ArrayList<SpiderDiagramClickEvent>[] acceptedClicks;
683
684         @SuppressWarnings("unchecked")
685         public SelectionSequenceMutable(SpiderDiagram diagram, ArrayList<SelectionStep> selectionSteps) {
686             super(diagram, selectionSteps);
687             this.acceptedClicks = new ArrayList[selectionSteps.size()];
688         }
689
690         void addAcceptedClick(int stepIndex, SpiderDiagramClickEvent evt, RuleArg arg) {
691             (acceptedSelections[stepIndex] == null
692                     ? (acceptedSelections[stepIndex] = new ArrayList<RuleArg>())
693                     : acceptedSelections[stepIndex]).add(arg);
694             (acceptedClicks[stepIndex] == null
695                     ? (acceptedClicks[stepIndex] = new ArrayList<SpiderDiagramClickEvent>())
696                     : acceptedClicks[stepIndex]).add(evt);
697         }
698
699         void clearCurrentSelection(int stepIndex) {
700             if (acceptedSelections[stepIndex] != null) {
701                 acceptedSelections[stepIndex].clear();
702             }
703             if (acceptedClicks[stepIndex] != null) {
704                 acceptedClicks[stepIndex].clear();
705             }
706         }
707         
708         void clearCurrentSelection() {
709             Arrays.fill(acceptedClicks, null);
710             Arrays.fill(acceptedSelections, null);
711         }
712
713         void setDiagram(SpiderDiagram diagram) {
714             this.diagram = diagram;
715         }
716     }
717     //</editor-fold>
718 }