Subversion Repositories DevTools

Rev

Rev 1295 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1293 dpurdie 1
Index: data/src/java/com/nuix/swing/filechooser/JFileChooserFactory.java
2
===================================================================
3
--- data/src/java/com/nuix/swing/filechooser/JFileChooserFactory.java	(revision 2561)
4
+++ data/src/java/com/nuix/swing/filechooser/JFileChooserFactory.java	(working copy)
5
@@ -36,6 +36,20 @@
6
     // Methods
7
 
8
     /**
9
+     * Convenience method to get the last directory for a given state key,
10
+     * without wasting time creating the file chooser itself.
11
+     *
12
+     * @param stateKey the key to use for storing the state.
13
+     * @return the last directory.
14
+     */
15
+    public static File getLastDirectory(String stateKey)
16
+    {
17
+        String value = prefs.get(stateKey, null);
18
+        return value == null ? null : new File(value);
19
+    }
20
+
21
+
22
+    /**
23
      * Gets a reference to the file chooser, preconfigured to the appropriate
24
      * state.
25
      * 
26
@@ -61,10 +75,10 @@
27
         });
28
 
29
         // Reset some of the chooser's properties to the defaults.
30
-        String lastDirectory = prefs.get(stateKey, null);
31
+        File lastDirectory = getLastDirectory(stateKey);
32
         if (lastDirectory != null)
33
         {
34
-            chooser.setCurrentDirectory(new File(lastDirectory));
35
+            chooser.setCurrentDirectory(lastDirectory);
36
         }
37
 
38
         return chooser;
39
Index: data/src/java/com/nuix/swing/widgets/FileChooserField.java
40
===================================================================
41
--- data/src/java/com/nuix/swing/widgets/FileChooserField.java	(revision 2561)
42
+++ data/src/java/com/nuix/swing/widgets/FileChooserField.java	(working copy)
43
@@ -150,6 +150,7 @@
44
         int buttonHeight = fileTextField.getPreferredSize().height +
45
                            (textFieldInsets.top + textFieldInsets.bottom) / 2;
46
         browseButton.setMargin(textFieldInsets);
47
+        //noinspection SuspiciousNameCombination
48
         browseButton.setPreferredSize(new Dimension(buttonHeight, buttonHeight));
49
         browseButton.addActionListener(new ActionListener()
50
         {
51
@@ -179,6 +180,16 @@
52
     // Methods
53
 
54
     /**
55
+     * Gets the initial directory.
56
+     *
57
+     * @return the initial directory.
58
+     */
59
+    public File getInitialDirectory()
60
+    {
61
+        return JFileChooserFactory.getLastDirectory(directoryStateKey);
62
+    }
63
+
64
+    /**
65
      * Tests if the input for this field is valid.  The input is valid if the file
66
      * passes the checks put in place by the file checker.
67
      *
68
Index: data/src/java/com/nuix/data/EvidenceInfo.java
69
===================================================================
70
--- data/src/java/com/nuix/data/EvidenceInfo.java	(revision 2561)
71
+++ data/src/java/com/nuix/data/EvidenceInfo.java	(working copy)
72
@@ -1,31 +1,31 @@
73
 package com.nuix.data;
74
 
75
-import com.nuix.investigator.cases.CaseEvidence;
76
-import com.nuix.investigator.cases.CaseUtils;
77
-import com.nuix.util.FileUtils;
78
-import com.nuix.log.Channel;
79
-import com.nuix.log.ChannelManager;
80
-import com.nuix.product.LicencingException;
81
-import com.nuix.product.Licence;
82
-import com.nuix.data.email.PstFileData;
83
-import com.nuix.data.email.DbxEmailFileData;
84
-import com.nuix.data.email.MbxEmailFileData;
85
-import com.nuix.data.email.NsfFileData;
86
-import com.nuix.data.email.MboxFileData;
87
-import com.nuix.data.email.EmlFileData;
88
-import com.nuix.data.email.ImapPopAccountData;
89
-
90
+import java.io.File;
91
+import java.io.IOException;
92
 import java.net.URI;
93
 import java.net.URISyntaxException;
94
+import java.util.ArrayList;
95
 import java.util.List;
96
-import java.util.ArrayList;
97
-import java.io.File;
98
-import java.io.IOException;
99
 
100
 import org.jdom.Document;
101
+import org.jdom.Element;
102
 import org.jdom.Namespace;
103
-import org.jdom.Element;
104
 
105
+import com.nuix.data.email.DbxEmailFileData;
106
+import com.nuix.data.email.EmlFileData;
107
+import com.nuix.data.email.ImapPopAccountData;
108
+import com.nuix.data.email.MboxFileData;
109
+import com.nuix.data.email.MbxEmailFileData;
110
+import com.nuix.data.email.NsfFileData;
111
+import com.nuix.data.email.PstFileData;
112
+import com.nuix.investigator.cases.CaseEvidence;
113
+import com.nuix.investigator.cases.CaseUtils;
114
+import com.nuix.log.Channel;
115
+import com.nuix.log.ChannelManager;
116
+import com.nuix.product.Licence;
117
+import com.nuix.product.LicencingException;
118
+import com.nuix.util.FileUtils;
119
+
120
 /**
121
  * Container class to hold the data required for a evidence group.
122
  */
123
@@ -57,6 +57,11 @@
124
         ChannelManager.getChannel("INVESTIGATOR.EvidenceGroup");
125
 
126
     /**
127
+     * Will be set to {@code true} later when the evidence is saved to disk.
128
+     */
129
+    private boolean saved;
130
+
131
+    /**
132
      * The {@link URI} instance encapsulated in this evidence group.
133
      */
134
     private List<URI> contents;
135
@@ -93,9 +98,15 @@
136
      * if it already existed in the set and hence wasn't added.
137
      * @throws LicencingException if the licence for the application does not
138
      *         permit the data to be processed.
139
+     * @throws IllegalStateException if this evidence is already saved to disk.
140
      */
141
     public boolean addURI(URI dataURI)
142
     {
143
+        if (saved)
144
+        {
145
+            throw new IllegalStateException("Cannot add URI to a saved evidence folder");
146
+        }
147
+
148
         // If general data is not enabled, we will potentially need to check
149
         // the type of the data.
150
         if (!Licence.getInstance().isEnabled(GENERAL_DATA_FEATURE_NAME))
151
@@ -136,11 +147,18 @@
152
     }
153
 
154
     /**
155
-     * Remove an {@link URI} from the set.
156
+     * Remove a {@link URI} from the set.
157
+     *
158
      * @param dataURIToRemove The {@link URI} to remove. 
159
+     * @throws IllegalStateException if this evidence is already saved to disk.
160
      */
161
     public void removeURI(URI dataURIToRemove)
162
     {
163
+        if (saved)
164
+        {
165
+            throw new IllegalStateException("Cannot remove URI from a saved evidence folder");
166
+        }
167
+
168
         contents.remove(dataURIToRemove);
169
     }
170
 
171
@@ -156,9 +174,16 @@
172
 
173
     /**
174
      * Clear out the contents of this EvidenceInfo instance.
175
+     *
176
+     * @throws IllegalStateException if this evidence is already saved to disk.
177
      */
178
     public void clearContents()
179
     {
180
+        if (saved)
181
+        {
182
+            throw new IllegalStateException("Cannot clear a saved evidence folder");
183
+        }
184
+
185
         contents.clear();
186
     }
187
 
188
@@ -174,6 +199,7 @@
189
 
190
     /**
191
      * Get the name of this set of evidence.
192
+     *
193
      * @return String The name of the evidence.
194
      */
195
     public String getName()
196
@@ -183,15 +209,23 @@
197
 
198
     /**
199
      * Set the name of the evidence.
200
+     *
201
      * @param name The name of the evidence.
202
+     * @throws IllegalStateException if this evidence is already saved to disk.
203
      */
204
     public void setName(String name)
205
     {
206
+        if (saved)
207
+        {
208
+            throw new IllegalStateException("Cannot set name on a saved evidence folder");
209
+        }
210
+
211
         this.name = name;
212
     }
213
 
214
     /**
215
      * Get the description associated with this set of evidence.
216
+     *
217
      * @return String the description.
218
      */
219
     public String getDescription()
220
@@ -201,14 +235,32 @@
221
 
222
     /**
223
      * Set the description of this evidence set.
224
+     *
225
      * @param description The description.
226
+     * @throws IllegalStateException if this evidence is already saved to disk.
227
      */
228
     public void setDescription(String description)
229
     {
230
+        if (saved)
231
+        {
232
+            throw new IllegalStateException("Cannot set description on a saved evidence folder");
233
+        }
234
+
235
         this.description = description;
236
     }
237
 
238
     /**
239
+     * Checks if this evidence has already been saved to disk.  If it is saved to disk
240
+     * already then attempts to modify it will fail.
241
+     *
242
+     * @return {@code true} if this evidence has been saved to disk, {@code false} otherwise.
243
+     */
244
+    public boolean isSaved()
245
+    {
246
+        return saved;
247
+    }
248
+
249
+    /**
250
      * Indicates whether some other object is "equal to" this one.
251
      *
252
      * @param obj the reference object with which to compare.
253
@@ -290,6 +342,8 @@
254
         try
255
         {
256
             CaseUtils.saveXml(xmlDoc, xmlFile);
257
+
258
+            saved = true;
259
         }
260
         catch (IOException e)
261
         {
262
@@ -341,6 +395,8 @@
263
                     contents.add(new URI(uriStr));
264
                 }
265
             }
266
+
267
+            saved = true;
268
         }
269
         catch (URISyntaxException e)
270
         {
271
Index: data/src/java/com/nuix/investigator/MainWindow.java
272
===================================================================
273
--- data/src/java/com/nuix/investigator/MainWindow.java	(revision 2561)
274
+++ data/src/java/com/nuix/investigator/MainWindow.java	(working copy)
275
@@ -9,7 +9,6 @@
276
 import java.awt.event.WindowEvent;
277
 import java.beans.PropertyChangeEvent;
278
 import java.beans.PropertyChangeListener;
279
-import java.util.List;
280
 
281
 import javax.swing.BorderFactory;
282
 import javax.swing.JFrame;
283
@@ -19,26 +18,24 @@
284
 import com.nuix.investigator.actions.file.ExitAction;
285
 import com.nuix.investigator.browser.BrowserPanel;
286
 import com.nuix.investigator.cases.Case;
287
-import com.nuix.investigator.cases.CaseEvidence;
288
 import com.nuix.investigator.cases.CaseHistoryDetail;
289
+import com.nuix.investigator.cases.CommonMetadata;
290
 import com.nuix.investigator.cases.ModifyCaseEvidencePane;
291
-import com.nuix.investigator.cases.CaseFactory;
292
-import com.nuix.investigator.cases.CommonMetadata;
293
-import com.nuix.investigator.cases.event.StatusBarLoadingAdapter;
294
+import com.nuix.investigator.cases.creation.AddLoadableEvidencePane;
295
 import com.nuix.investigator.history.HistoryRecord;
296
 import com.nuix.investigator.images.ImageFactory;
297
+import com.nuix.investigator.options.global.GlobalPreferences;
298
 import com.nuix.investigator.processing.ProcessingRunner;
299
 import com.nuix.investigator.search.SearchPanel;
300
-import com.nuix.investigator.options.global.GlobalPreferences;
301
 import com.nuix.log.Channel;
302
 import com.nuix.log.ChannelManager;
303
+import com.nuix.resources.ResourceFactory;
304
 import com.nuix.resources.ResourceGroup;
305
-import com.nuix.resources.ResourceFactory;
306
+import com.nuix.swing.context.ContextContainer;
307
+import com.nuix.swing.context.ContextTracker;
308
+import com.nuix.swing.context.JTabbedPaneContextHelper;
309
 import com.nuix.swing.widgets.JAutotitleTabbedPane;
310
 import com.nuix.swing.widgets.JStatusBar;
311
-import com.nuix.swing.context.ContextTracker;
312
-import com.nuix.swing.context.ContextContainer;
313
-import com.nuix.swing.context.JTabbedPaneContextHelper;
314
 
315
 /**
316
  * The main window of the application.
317
@@ -210,31 +207,26 @@
318
                         HistoryRecord.Type.SESSION, HistoryRecord.Point.START,
319
                         new CaseHistoryDetail(this.currentCase.getLocation())));
320
 
321
-                // Start with the processing if the previous run was not completed.
322
-                // Otherwise, start with a search panel.
323
-                // XXX: Come up with a better idea for detecting that there's work to be done.
324
-                ProcessingRunner runner = null;
325
-                List<CaseEvidence> evidenceSet = this.currentCase.getEvidenceSet();
326
-                if (evidenceSet.isEmpty())
327
+                if (this.currentCase.isCompound())
328
                 {
329
-                    new ModifyCaseEvidencePane(getCurrentCase()).showDialog(this);
330
+                    // If a compound case has no simple cases added to it, we prompt the
331
+                    // user to choose some simple cases to add.
332
+                    if (this.currentCase.isEmpty())
333
+                    {
334
+                        new ModifyCaseEvidencePane(this.currentCase).showDialog(this);
335
+                    }
336
+
337
+                    loadingCompleted();
338
                 }
339
-                else if (evidenceSet.size() == 1)
340
+                else
341
                 {
342
-                    runner = new ProcessingRunner(this, evidenceSet.get(0));
343
-                    if (runner.hasWork())
344
+                    // If a simple case has no evidence loaded in it, we prompt the user to load some.
345
+                    if (this.currentCase.isEmpty())
346
                     {
347
-                        runner.run();
348
+                        new AddLoadableEvidencePane(this.currentCase).showDialog(this);
349
                     }
350
-                    else
351
-                    {
352
-                        runner = null;
353
-                    }
354
-                }
355
 
356
-                if (runner == null)
357
-                {
358
-                    loadingCompleted();
359
+                    maybeLoadEvidence();
360
                 }
361
             }
362
 
363
@@ -244,6 +236,26 @@
364
     }
365
 
366
     /**
367
+     * Checks if there is any evidence yet to be loaded in the current case,
368
+     * and loads it if there is.
369
+     */
370
+    public void maybeLoadEvidence()
371
+    {
372
+        // Either the user just added evidence, or there was already evidence.
373
+        // Now complete any processing work that has to be done.
374
+        // XXX: Come up with a better idea for detecting that there's work to be done.
375
+        ProcessingRunner runner = new ProcessingRunner(this, this.currentCase.getEvidenceSet().get(0));
376
+        if (runner.hasWork())
377
+        {
378
+            runner.run();
379
+        }
380
+        else
381
+        {
382
+            loadingCompleted();
383
+        }
384
+    }
385
+
386
+    /**
387
      * Called when loading completes.
388
      * <p>
389
      * Populates the initial tabs in the main window and refreshes the case in case
390
Index: data/src/java/com/nuix/investigator/cases/CaseContentTreeModel.java
391
===================================================================
392
--- data/src/java/com/nuix/investigator/cases/CaseContentTreeModel.java	(revision 2561)
393
+++ data/src/java/com/nuix/investigator/cases/CaseContentTreeModel.java	(working copy)
394
@@ -1,18 +1,19 @@
395
 package com.nuix.investigator.cases;
396
 
397
+import java.net.URI;
398
+import java.util.ArrayList;
399
+import java.util.List;
400
+
401
+import javax.swing.event.EventListenerList;
402
+import javax.swing.event.TreeModelEvent;
403
+import javax.swing.event.TreeModelListener;
404
+import javax.swing.tree.TreeModel;
405
+import javax.swing.tree.TreePath;
406
+
407
 import com.nuix.data.EvidenceInfo;
408
 import com.nuix.log.Channel;
409
 import com.nuix.log.ChannelManager;
410
 
411
-import javax.swing.tree.TreeModel;
412
-import javax.swing.tree.TreePath;
413
-import javax.swing.event.TreeModelListener;
414
-import javax.swing.event.TreeModelEvent;
415
-import javax.swing.event.EventListenerList;
416
-import java.util.List;
417
-import java.util.ArrayList;
418
-import java.net.URI;
419
-
420
 /**
421
  * An implementation of TreeModel to capture the evidence structure for a case.
422
  */ 
423
@@ -148,14 +149,30 @@
424
     {
425
         if (parent == ROOT_NODE)
426
         {
427
-            return roots.indexOf(child);
428
+            if (child instanceof EvidenceInfo)
429
+            {
430
+                //noinspection SuspiciousMethodCalls
431
+                return roots.indexOf(child);
432
+            }
433
+            else
434
+            {
435
+                return -1;
436
+            }
437
         }
438
         else if (parent instanceof EvidenceInfo)
439
         {
440
-            EvidenceInfo evidenceInfo = (EvidenceInfo) parent;
441
-            // Get the child.
442
-            List<URI> contents = evidenceInfo.getContents();
443
-            return contents.indexOf(child);
444
+            if (child instanceof URI)
445
+            {
446
+                EvidenceInfo evidenceInfo = (EvidenceInfo) parent;
447
+                // Get the child.
448
+                List<URI> contents = evidenceInfo.getContents();
449
+                //noinspection SuspiciousMethodCalls
450
+                return contents.indexOf(child);
451
+            }
452
+            else
453
+            {
454
+                return -1;
455
+            }
456
         }
457
 
458
         return -1;
459
@@ -258,6 +275,8 @@
460
 
461
     /**
462
      * Get all the EvidenceInfo instances in the tree.
463
+     *
464
+     * @return the list of evidence roots.
465
      */ 
466
     public List<EvidenceInfo> getEvidence()
467
     {
468
Index: data/src/java/com/nuix/investigator/cases/Case.java
469
===================================================================
470
--- data/src/java/com/nuix/investigator/cases/Case.java	(revision 2561)
471
+++ data/src/java/com/nuix/investigator/cases/Case.java	(working copy)
472
@@ -33,7 +33,6 @@
473
 import com.nuix.store.user.DefaultSession;
474
 import com.nuix.store.user.Session;
475
 import com.nuix.util.FileUtils;
476
-import com.nuix.util.WrappedIOException;
477
 
478
 /**
479
  * A case, which has a number of properties as well as a number of loaded files.
480
@@ -163,6 +162,32 @@
481
     }
482
 
483
     /**
484
+     * <p>Convenience method for detecting whether this case is empty.  In the case of a simple
485
+     * case this means no evidence is loaded.  In the case of a compound case, this means no
486
+     * simple cases are added to it.</p>
487
+     *
488
+     * <p>The situation of a compound case composed of multiple empty simple cases is considered
489
+     * to not be empty.</p>
490
+     *
491
+     * @return {@code true} if the case is empty, {@code false} otherwise.
492
+     */
493
+    public boolean isEmpty()
494
+    {
495
+        if (isCompound())
496
+        {
497
+            return evidenceSet.isEmpty();
498
+        }
499
+        else
500
+        {
501
+            // TODO: Do we consider it to have data if there is work on the queue?
502
+            // We might want a more convenient way to determine that there is work on the queue.
503
+            // e.g., can we make it so if the directory exists, there is definitely work to be done?
504
+
505
+            return getEvidenceSet().get(0).getItemCount() == 0;
506
+        }
507
+    }
508
+
509
+    /**
510
      * Gets the count of the total number of items in the case.
511
      *
512
      * @return the number of items in the case.
513
@@ -402,7 +427,7 @@
514
         }
515
         catch (SQLException e)
516
         {
517
-            throw new WrappedIOException("Error creating initial schema for analysis database", e);
518
+            throw new IOException("Error creating initial schema for analysis database", e);
519
         }
520
 
521
         container.registerComponentInstance(Database.class, database);
522
@@ -413,7 +438,7 @@
523
         }
524
         catch (MigrationException e)
525
         {
526
-            throw new WrappedIOException("Error initialising stores", e);
527
+            throw new IOException("Error initialising stores", e);
528
         }
529
 
530
         save();
531
Index: data/src/java/com/nuix/investigator/cases/cases.xml
532
===================================================================
533
--- data/src/java/com/nuix/investigator/cases/cases.xml	(revision 2561)
534
+++ data/src/java/com/nuix/investigator/cases/cases.xml	(working copy)
535
@@ -5,6 +5,142 @@
536
 - Resources for the wizards.
537
 -->
538
 <Resources>
539
+    <Group name="AddLoadableEvidencePane">
540
+        <String name="Title" value="Add Case Evidence"/>
541
+
542
+        <String name="Text" value="Please choose the files and directories you wish to load into this case."/>
543
+
544
+        <String name="Add" value="Add..."/>
545
+        <String name="Remove" value="Remove"/>
546
+        <String name="Edit" value="Edit..."/>
547
+        <String name="EvidencePrefix" value="Evidence {0}"/>
548
+        <String name="EvidenceNameFormat" value="{0} ({1})"/>
549
+        <String name="EvidenceNameFormatNoDescription" value="{0}"/>
550
+
551
+        <Group name="MustSpecifyUniqueName">
552
+            <String name="Title" value="Evidence Name Already Exists"/>
553
+            <String name="Text" value="&lt;html&gt;
554
+                You must specify a unique evidence name.
555
+                &lt;/html&gt;"/>
556
+        </Group>
557
+
558
+        <Group name="MustAddContent">
559
+            <String name="Title" value="Missing User Input"/>
560
+            <String name="Text" value="&lt;html&gt;
561
+                You must add at least one file or directory before progressing&lt;br&gt;
562
+                to the next page.
563
+                &lt;/html&gt;"/>
564
+        </Group>
565
+    </Group>
566
+
567
+    <Group name="EvidenceInputPane">
568
+        <String name="Add" value="Add..."/>
569
+        <String name="AddFile" value="Add File..."/>
570
+        <String name="AddDirectory" value="Add Directory..."/>
571
+        <String name="AddMailStore" value="Add Mail Store..."/>
572
+        <String name="Remove" value="Remove"/>
573
+        <String name="EvidenceInput" value="Add/Edit Evidence"/>
574
+        <String name="Content" value="Content:"/>
575
+        <String name="EvidenceName" value="Evidence name:"/>
576
+        <String name="EvidenceComments" value="Comments:"/>
577
+        <String name="DirectoryTitle" value="Add Directory(s)"/>
578
+        <String name="FileTitle" value="Add File(s)"/>
579
+
580
+        <Group name="NonexistentFile">
581
+            <String name="Title" value="Nonexistent File"/>
582
+            <String name="Text" value="&lt;html&gt;
583
+                The file you have chosen does not exist:&lt;br&gt;
584
+                {0}
585
+                &lt;/html&gt;"/>
586
+        </Group>
587
+
588
+        <Group name="NonexistentDirectory">
589
+            <String name="Title" value="Nonexistent Directory"/>
590
+            <String name="Text" value="&lt;html&gt;
591
+                The directory you have chosen does not exist:&lt;br&gt;
592
+                {0}
593
+                &lt;/html&gt;"/>
594
+        </Group>
595
+
596
+        <Group name="MustAddEvidence">
597
+            <String name="Title" value="Missing User Input"/>
598
+            <String name="Text" value="&lt;html&gt;
599
+                You must add at least one file or directory before progressing.
600
+                &lt;/html&gt;"/>
601
+        </Group>
602
+
603
+        <Group name="MustSpecifyName">
604
+            <String name="Title" value="Missing Evidence Name"/>
605
+            <String name="Text" value="&lt;html&gt;
606
+                You must specify the evidence name before progressing.
607
+                &lt;/html&gt;"/>
608
+        </Group>
609
+
610
+        <Group name="RestrictedFile">
611
+            <String name="Title" value="Restricted File"/>
612
+            <String name="Text" value="&lt;html&gt;
613
+                The file you have chosen cannot be loaded due to restrictions&lt;br&gt;
614
+                in your software licence:&lt;br&gt;
615
+                {0}
616
+                &lt;p&gt;
617
+                To remove this restriction, please contact &CompanyNameShort; to obtain a full licence.
618
+                &lt;/html&gt;"/>
619
+        </Group>
620
+
621
+        <Group name="SomeItemsNotAddedDueToLimit">
622
+            <String name="Title" value="Some Items Not Added"/>
623
+            <String name="Text" value="&lt;html&gt;
624
+                Some items were not added due to the file limit of {0} permitted by your licence.
625
+                &lt;p&gt;
626
+                To remove this limit, please contact &CompanyNameShort; to obtain a full licence.
627
+                &lt;/html&gt;"/>
628
+        </Group>
629
+
630
+        <Group name="Duplicate">
631
+            <String name="Title" value="Duplicate entry"/>
632
+            <String name="Text" value="&lt;html&gt;
633
+                The item you selected was already in the list.
634
+                &lt;/html&gt;"/>
635
+        </Group>
636
+
637
+        <Group name="Duplicates">
638
+            <String name="Title" value="Duplicate entries"/>
639
+            <String name="Text" value="&lt;html&gt;
640
+                {0} of the items you selected {0,choice,1#was|1&lt;were} already in the list.
641
+                &lt;/html&gt;"/>
642
+        </Group>
643
+    </Group>
644
+
645
+    <Group name="MailStoreInputPane">
646
+        <String name="Title" value="Add Mail Store"/>
647
+
648
+        <!-- Fields -->
649
+        <String name="Protocol" value="Mail Store Type:"/>
650
+        <String name="Host" value="Server Hostname:"/>
651
+        <String name="Port" value="Server Port:"/>
652
+        <String name="Username" value="Username:"/>
653
+        <String name="Password" value="Password:"/>
654
+
655
+        <!-- Protocols -->
656
+        <String name="PleaseSelect" value="Please select:"/>
657
+        <String name="pop" value="POP"/>
658
+        <String name="imap" value="IMAP"/>
659
+
660
+        <!-- Errors -->
661
+        <Group name="FieldsNotComplete">
662
+            <String name="Title" value="Missing User Input"/>
663
+            <String name="Text" value="&lt;html&gt;
664
+                You must fill in all fields.
665
+                &lt;/html&gt;"/>
666
+        </Group>
667
+        <Group name="FieldsInvalid">
668
+            <String name="Title" value="Invalid User Input"/>
669
+            <String name="Text" value="&lt;html&gt;
670
+                Some of the fields you entered are invalid.
671
+                &lt;/html&gt;"/>
672
+        </Group>
673
+    </Group>
674
+    
675
     <Group name="ModifyCaseEvidencePane">
676
         <String name="Title" value="Add Case Evidence"/>
677
         <String name="Text" value="&lt;html&gt;
678
@@ -102,4 +238,142 @@
679
         <String name="Evidence.DatabaseReadOnly"
680
                 value="Database is read-only.  Annotations will be viewable but not editable, and history will not be recorded."/>
681
     </Group>
682
+
683
+    <Group name="NewCasePane">
684
+        <String name="Title" value="New Case"/>
685
+
686
+        <String name="CaseSettings" value="Case settings"/>
687
+        <String name="TextProcessingSettings" value="Text processing settings"/>
688
+        <String name="OtherProcessingSettings" value="Other processing settings"/>
689
+    </Group>
690
+
691
+    <Group name="CaseSettingsPanel">
692
+        <String name="Name" value="Name:"/>
693
+        <String name="DefaultNameFormat" value="Case {0}"/>
694
+        <String name="Directory" value="Directory:"/>
695
+        <String name="Investigator" value="Investigator:"/>
696
+        <String name="Description" value="Description:"/>
697
+        <String name="Type" value="Case type:"/>
698
+        <String name="SimpleCase" value="Simple (contains loaded evidence)"/>
699
+        <String name="CompoundCase" value="Compound (contains other cases)"/>
700
+
701
+
702
+        <Group name="MustEnterDirectory">
703
+            <String name="Title" value="Missing user input"/>
704
+            <String name="Text" value="&lt;html&gt;
705
+                You must enter a directory.
706
+                &lt;/html&gt;"/>
707
+        </Group>
708
+
709
+        <Group name="RootNotPossible">
710
+            <String name="Title" value="Invalid user input"/>
711
+            <String name="Text" value="&lt;html&gt;
712
+                Case files cannot reside in the root of a hard drive.
713
+                &lt;p&gt;
714
+                Please choose a subdirectory.
715
+                &lt;/html&gt;"/>
716
+        </Group>
717
+
718
+        <Group name="NoParentDirectory">
719
+            <String name="Title" value="Invalid user input"/>
720
+            <String name="Text" value="&lt;html&gt;
721
+                The directory you have entered is invalid because the parent&lt;br&gt;
722
+                directory does not exist.
723
+                &lt;/html&gt;"/>
724
+        </Group>
725
+
726
+        <Group name="NotADirectory">
727
+            <String name="Title" value="Invalid user input"/>
728
+            <String name="Text" value="&lt;html&gt;
729
+                Ths file you have chosen is not a directory.
730
+                &lt;/html&gt;"/>
731
+        </Group>
732
+
733
+        <Group name="DirectoryNotEmpty">
734
+            <String name="Title" value="Invalid user input"/>
735
+            <String name="Text" value="&lt;html&gt;
736
+                The directory you have entered contains files already.
737
+                &lt;p&gt;
738
+                Please choose an empty directory.
739
+                &lt;/html&gt;"/>
740
+        </Group>
741
+
742
+        <Group name="FieldsNotComplete">
743
+            <String name="Title" value="Missing User Input"/>
744
+            <String name="Text" value="&lt;html&gt;
745
+                You must fill in the name and investigator fields.
746
+                &lt;/html&gt;"/>
747
+        </Group>
748
+    </Group>
749
+
750
+    <Group name="TextProcessingSettingsPanel">
751
+        <String name="ProcessTextOption" value="Store and index text of data items"/>
752
+        <String name="ProcessTextOptionToolTip"
753
+                value="&lt;html&gt;
754
+                       Selecting this option will make the system store and index&lt;br&gt;
755
+                       text for each data item processed.  This will increase&lt;br&gt;
756
+                       processing time, and thus might be disabled if you know&lt;br&gt;
757
+                       in advance that you won't need to perform any text searching.
758
+                       &lt;/html&gt;"/>
759
+        <String name="StopWordsPolicyLabel" value="Use Stop Words:"/>
760
+        <String name="StemmingPolicyLabel" value="Use Stemming:"/>
761
+    </Group>
762
+
763
+    <Group name="OtherProcessingSettingsPanel">
764
+        <String name="DeletedEmailsOption" value="Extract from slack space of email boxes"/>
765
+        <String name="DeletedEmailsOptionToolTip"
766
+                value="&lt;html&gt;
767
+                       Attempt to retrieve deleted emails located in the slack
768
+                       space of a mail box file. &lt;br&gt;This is applicable only with PST,
769
+                       OST, DBX and EDB/STM files.
770
+                       &lt;/html&gt;"/>
771
+        <String name="StoreBinaryOption" value="Store binary of data items"/>
772
+        <String name="StoreBinaryOptionToolTip"
773
+                value="&lt;html&gt;
774
+                       Selecting this option will make the system store binary data&lt;br&gt;
775
+                       for each item processed.  This will speed up exports but increase&lt;br&gt;
776
+                       processing time and storage.
777
+                       &lt;/html&gt;"/>
778
+        <String name="DirectAccessOption" value="Enable direct access to NSF email boxes"/>
779
+        <String name="DirectAccessOptionToolTip"
780
+                value="&lt;html&gt;
781
+                       Directly accessing NSF files results in access records&lt;br&gt;
782
+                       within the file being updated, which in turn modifies the file.&lt;br&gt;
783
+                       The internal data itself is unchanged.  Selecting this option&lt;br&gt;
784
+                       will ensure a copy of the mailbox is performed and processing&lt;br&gt;
785
+                       is done only on the copy, rather than the source data, at the&lt;br&gt;
786
+                       expense of more processing time.  If an NSF file is read-only,&lt;br&gt;
787
+                       a copy will be made irrespective of this setting.&lt;br&gt;
788
+                       &lt;/html&gt;"/>
789
+        <String name="ExtractEmbeddedImagesOption" value="Extract embedded images"/>
790
+        <String name="ExtractEmbeddedImagesOptionToolTip"
791
+                value="&lt;html&gt;
792
+                      Extract images embedded in items such as Office documents.
793
+                      &lt;/html&gt;"/>
794
+        <String name="CreateThumbnailsOption" value="Create thumbnails for image data items"/>
795
+        <String name="CreateThumbnailsOptionToolTip"
796
+                value="&lt;html&gt;
797
+                      Selecting this option will generate a thumbnail&lt;br&gt;
798
+                      image for each image data item detected.  This&lt;br&gt;
799
+                      will increase processing time, but will enable the&lt;br&gt;
800
+                      &quot;Thumbnail&quot; tabs within the analysis interface,&lt;br&gt;
801
+                      for quickly inspecting image data.&lt;br&gt;
802
+                      &lt;/html&gt;"/>
803
+        <String name="DeduplicateDataOption" value="De-duplicate data"/>
804
+        <String name="DeduplicateDataOptionToolTip"
805
+                value="&lt;html&gt;
806
+                      Selecting this option will prevent duplicate data&lt;br&gt;
807
+                      items being processed more than once.&lt;br&gt;
808
+                      Instead their properties and content will be blank&lt;br&gt;
809
+                      and they will be marked as duplicates.&lt;br&gt;
810
+                      &lt;/html&gt;"/>
811
+        <String name="SkinToneAnalysisOption" value="Skin tone analysis"/>
812
+        <String name="SkinToneAnalysisOptionToolTip"
813
+                value="&lt;html&gt;
814
+                      Selecting this option will perform skin-tone analysis&lt;br&gt;
815
+                      over all detected images.  Once the case evidence has&lt;br&gt;
816
+                      been loaded, the skin tone filter can be used to display&lt;br&gt;
817
+                      images with significant amount of skin tones present.&lt;br&gt;
818
+                      &lt;/html&gt;"/>
819
+    </Group>
820
 </Resources>
821
Index: data/src/java/com/nuix/investigator/cases/creation/OtherProcessingSettingsPanel.java
822
===================================================================
823
--- data/src/java/com/nuix/investigator/cases/creation/OtherProcessingSettingsPanel.java	(revision 2511)
824
+++ data/src/java/com/nuix/investigator/cases/creation/OtherProcessingSettingsPanel.java	(working copy)
825
@@ -1,70 +1,40 @@
826
-package com.nuix.investigator.wizard.panels;
827
+package com.nuix.investigator.cases.creation;
828
 
829
-import com.nuix.resources.ResourceGroup;
830
-import com.nuix.swing.wizard.AbstractWizardPanel;
831
-import com.nuix.swing.wizard.AbstractWizardModel;
832
-import com.nuix.investigator.images.ImageFactory;
833
-import com.nuix.investigator.wizard.NewCaseWizardModel;
834
-import com.nuix.data.DataProcessingSettings;
835
-import com.nuix.store.index.settings.StopWordsPolicy;
836
-import com.nuix.store.index.settings.StemmingPolicy;
837
-import com.nuix.store.index.settings.TextIndexSettings;
838
-import com.nuix.store.index.settings.AbstractPolicy;
839
+import java.awt.GridBagConstraints;
840
+import java.awt.GridBagLayout;
841
+import java.awt.Insets;
842
+import java.awt.event.ActionEvent;
843
+import java.awt.event.ActionListener;
844
 
845
 import javax.swing.JCheckBox;
846
-import javax.swing.JLabel;
847
 import javax.swing.JPanel;
848
-import javax.swing.BoxLayout;
849
-import javax.swing.Box;
850
 import javax.swing.SwingUtilities;
851
-import javax.swing.BorderFactory;
852
-import javax.swing.JComboBox;
853
-import javax.swing.DefaultComboBoxModel;
854
 
855
-import java.awt.GridBagLayout;
856
-import java.awt.GridBagConstraints;
857
-import java.awt.Insets;
858
-import java.awt.Container;
859
-import java.awt.event.ActionListener;
860
-import java.awt.event.ActionEvent;
861
+import com.nuix.data.DataProcessingSettings;
862
+import com.nuix.resources.ResourceFactory;
863
+import com.nuix.resources.ResourceGroup;
864
 
865
 /**
866
- * Wizard step for specifying the data processing settings for each case.
867
+ * Panel for specifying other data processing settings.
868
  */
869
-public class CaseContentPropertiesPanel extends AbstractWizardPanel
870
+public class OtherProcessingSettingsPanel extends JPanel
871
 {
872
     ///////////////////////////////////////////////////////////////////////////
873
-    // Constants
874
-
875
-    ///////////////////////////////////////////////////////////////////////////
876
     // Fields
877
 
878
     /**
879
      * The resources for the panel.
880
      */
881
-    private ResourceGroup resources;
882
+    private ResourceGroup resources =
883
+        ResourceFactory.get("/com/nuix/investigator/cases/cases.xml")
884
+            .getSubgroup("OtherProcessingSettingsPanel");
885
 
886
     /**
887
-     * The "process text" checkbox.
888
-     */
889
-    private JCheckBox processTextCheckBox;
890
-
891
-    /**
892
      * The "store binary" checkbox.
893
      */
894
     private JCheckBox storeBinaryCheckBox;
895
 
896
     /**
897
-     * The stop words policy combobox.
898
-     */
899
-    private JComboBox stopWordsPolicyComboBox;
900
-
901
-    /**
902
-     * The stemming policy combo box.
903
-     */
904
-    private JComboBox stemmingPolicyComboBox;
905
-
906
-    /**
907
      * A reference to the "extract from slack space" checkbox.
908
      */
909
     private JCheckBox extractFromSlackSpaceCheckBox = null;
910
@@ -98,21 +68,48 @@
911
     // Constructors
912
 
913
     /**
914
-     * Constructor initialising resources.
915
-     * @param resources The {@link ResourceGroup} to initialise with.
916
+     * Constructs the panel.
917
      */
918
-    public CaseContentPropertiesPanel(ResourceGroup resources)
919
+    public OtherProcessingSettingsPanel()
920
     {
921
-        super("CaseContentPropertiesPanel");
922
-        setLogo(ImageFactory.createIcon("WizardLeft.png"));
923
-        this.resources = resources;
924
+        super(new GridBagLayout());
925
+
926
+        GridBagConstraints c1 = new GridBagConstraints();
927
+        c1.insets = new Insets(4, 4, 4, 4);
928
+        c1.anchor = GridBagConstraints.LINE_START;
929
+        GridBagConstraints c2 = (GridBagConstraints) c1.clone();
930
+        c2.weightx = 1.0;
931
+        c2.gridwidth = GridBagConstraints.REMAINDER;
932
+
933
+        // Remaining options.
934
+        storeBinaryCheckBox = addJCheckbox("StoreBinaryOption", c2);
935
+        extractFromSlackSpaceCheckBox = addJCheckbox("DeletedEmailsOption", c2);
936
+        directAccessCheckBox = addJCheckbox("DirectAccessOption", c2);
937
+        extractEmbeddedImagesCheckBox = addJCheckbox("ExtractEmbeddedImagesOption", c2);
938
+        createThumbnailsCheckBox = addJCheckbox("CreateThumbnailsOption", c2);
939
+        deduplicateDataCheckBox = addJCheckbox("DeduplicateDataOption", c2);
940
+        skinToneAnalysisCheckBox = addJCheckbox("SkinToneAnalysisOption", c2);
941
+
942
+        // If skinToneAnalysisCheckbox is selected, then the createThumbnailsCheckbox
943
+        // must be enabled.
944
+        skinToneAnalysisCheckBox.addActionListener(new ActionListener()
945
+        {
946
+            public void actionPerformed(ActionEvent e)
947
+            {
948
+                updateState();
949
+            }
950
+        });
951
+
952
+        // Load default state from a dummy model.
953
+        importModel(new NewCaseModel());
954
+        updateState();
955
     }
956
 
957
     ///////////////////////////////////////////////////////////////////////////
958
     // Methods
959
 
960
     /**
961
-     * Validates the data entered by the user. This is always true since 
962
+     * Validates the data entered by the user. This is always true since
963
      * we're simply altering the boolean state of checkboxes.
964
      *
965
      * @return <code>true</code> if the data in this panel is valid,
966
@@ -128,12 +125,9 @@
967
      *
968
      * @param model the wizard model.
969
      */
970
-    public void importModel(AbstractWizardModel model)
971
+    private void importModel(NewCaseModel model)
972
     {
973
-        NewCaseWizardModel m = (NewCaseWizardModel) model;
974
-
975
-        DataProcessingSettings processingSettings = m.getProcessingSettings();
976
-        processTextCheckBox.setSelected(processingSettings.getProcessText());
977
+        DataProcessingSettings processingSettings = model.getProcessingSettings();
978
         storeBinaryCheckBox.setSelected(processingSettings.getStoreBinary());
979
         extractFromSlackSpaceCheckBox.setSelected(processingSettings.getExtractFromSlackSpace());
980
         directAccessCheckBox.setSelected(processingSettings.getDirectAccessToMailboxes());
981
@@ -141,12 +135,6 @@
982
         createThumbnailsCheckBox.setSelected(processingSettings.getCreateThumbnails());
983
         deduplicateDataCheckBox.setSelected(processingSettings.getDeduplicateData());
984
         skinToneAnalysisCheckBox.setSelected(processingSettings.getSkinToneAnalysis());
985
-
986
-        TextIndexSettings textIndexSettings = m.getCaseEvidenceSettings().getTextIndexSettings();
987
-        stopWordsPolicyComboBox.setSelectedItem(new PolicyContainer(textIndexSettings.getStopWordsPolicy()));
988
-        stemmingPolicyComboBox.setSelectedItem(new PolicyContainer(textIndexSettings.getStemmingPolicy()));
989
-
990
-        wireCheckboxes();
991
     }
992
 
993
     /**
994
@@ -154,12 +142,9 @@
995
      *
996
      * @param model the wizard model.
997
      */
998
-    public void exportModel(AbstractWizardModel model)
999
+    public void exportModel(NewCaseModel model)
1000
     {
1001
-        NewCaseWizardModel m = (NewCaseWizardModel) model;
1002
-
1003
-        DataProcessingSettings processingSettings = m.getProcessingSettings();
1004
-        processingSettings.setProcessText(processTextCheckBox.isSelected());
1005
+        DataProcessingSettings processingSettings = model.getProcessingSettings();
1006
         processingSettings.setStoreBinary(storeBinaryCheckBox.isSelected());
1007
         processingSettings.setExtractFromSlackSpace(extractFromSlackSpaceCheckBox.isSelected());
1008
         processingSettings.setDirectAccessToMailboxes(directAccessCheckBox.isSelected());
1009
@@ -167,83 +152,41 @@
1010
         processingSettings.setCreateThumbnails(createThumbnailsCheckBox.isSelected());
1011
         processingSettings.setDeduplicateData(deduplicateDataCheckBox.isSelected());
1012
         processingSettings.setSkinToneAnalysis(skinToneAnalysisCheckBox.isSelected());
1013
-
1014
-        TextIndexSettings textIndexSettings = m.getCaseEvidenceSettings().getTextIndexSettings();
1015
-        PolicyContainer policyContainer = (PolicyContainer) stopWordsPolicyComboBox.getSelectedItem();
1016
-        textIndexSettings.setStopWordsPolicy((StopWordsPolicy) policyContainer.policy);
1017
-        policyContainer = (PolicyContainer) stemmingPolicyComboBox.getSelectedItem();
1018
-        textIndexSettings.setStemmingPolicy((StemmingPolicy) policyContainer.policy);
1019
     }
1020
 
1021
     /**
1022
-     * Called at the appropriate time, to initialise the contents of the panel.
1023
+     * Updates the enabled state of the individual components.
1024
      */
1025
-    protected void initialise()
1026
+    private void updateState()
1027
     {
1028
-        getContentPane().setLayout(new GridBagLayout());
1029
-
1030
-        GridBagConstraints c1 = new GridBagConstraints();
1031
-        c1.insets = new Insets(2, 4, 2, 4);
1032
-        c1.anchor = GridBagConstraints.FIRST_LINE_START;
1033
-        GridBagConstraints c2 = (GridBagConstraints) c1.clone();
1034
-        c2.weightx = 1.0;
1035
-        c2.gridwidth = GridBagConstraints.REMAINDER;
1036
-
1037
-        // Text processing options.
1038
-        JPanel textPanel = new JPanel(new GridBagLayout());
1039
-        textPanel.setBorder(BorderFactory.createTitledBorder(
1040
-            resources.getString("TextProcessingSettingsHeader")));
1041
-        processTextCheckBox = addJCheckbox("ProcessTextOption", textPanel, c2);
1042
-        stopWordsPolicyComboBox = addJComboBox("StopWordsPolicy", textPanel, c1, c1,
1043
-                                               StopWordsPolicy.getAll());
1044
-        stemmingPolicyComboBox = addJComboBox("StemmingPolicy", textPanel, c1, c2,
1045
-                                              StemmingPolicy.getAll());
1046
-
1047
-        // Remaining options.
1048
-        Box otherPanel = new Box(BoxLayout.Y_AXIS);
1049
-        otherPanel.setBorder(BorderFactory.createTitledBorder(
1050
-            resources.getString("OtherSettingsHeader")));
1051
-        storeBinaryCheckBox = addJCheckbox("StoreBinaryOption", otherPanel, c2);
1052
-        extractFromSlackSpaceCheckBox = addJCheckbox("DeletedEmailsOption", otherPanel, c2);
1053
-        directAccessCheckBox = addJCheckbox("DirectAccessOption", otherPanel, c2);
1054
-        extractEmbeddedImagesCheckBox = addJCheckbox("ExtractEmbeddedImagesOption", otherPanel, c2);
1055
-        createThumbnailsCheckBox = addJCheckbox("CreateThumbnailsOption", otherPanel, c2);
1056
-        deduplicateDataCheckBox = addJCheckbox("DeduplicateDataOption", otherPanel, c2);
1057
-        skinToneAnalysisCheckBox = addJCheckbox("SkinToneAnalysisOption", otherPanel, c2);
1058
-
1059
-        // If skinToneAnalysisCheckbox is selected, then the createThumbnailsCheckbox
1060
-        // must be enabled.
1061
-        skinToneAnalysisCheckBox.addActionListener(new ActionListener()
1062
+        if (isEnabled())
1063
         {
1064
-            public void actionPerformed(ActionEvent e)
1065
+            storeBinaryCheckBox.setEnabled(true);
1066
+            extractFromSlackSpaceCheckBox.setEnabled(true);
1067
+            directAccessCheckBox.setEnabled(true);
1068
+            extractEmbeddedImagesCheckBox.setEnabled(true);
1069
+            deduplicateDataCheckBox.setEnabled(true);
1070
+            skinToneAnalysisCheckBox.setEnabled(true);
1071
+
1072
+            if (skinToneAnalysisCheckBox.isSelected())
1073
             {
1074
-                wireCheckboxes();
1075
+                createThumbnailsCheckBox.setSelected(true);
1076
+                createThumbnailsCheckBox.setEnabled(false);
1077
             }
1078
-        });
1079
-
1080
-        // Put the whole thing together.
1081
-        c2.fill = GridBagConstraints.BOTH;
1082
-        getContentPane().add(new JLabel(resources.getString("Text")), c2);
1083
-        getContentPane().add(textPanel, c2);
1084
-        getContentPane().add(otherPanel, c2);
1085
-        c2.weighty = 1.0;
1086
-        getContentPane().add(new JPanel(), c2); // Filler
1087
-    }
1088
-
1089
-    /**
1090
-     * Make sure that any dependencies between checkboxes are handled.  Currently, if
1091
-     * the skin-tone analysis checkbox is enabled, then so must the thumbnails checkbox.
1092
-     */
1093
-    private void wireCheckboxes()
1094
-    {
1095
-        if (skinToneAnalysisCheckBox.isSelected())
1096
-        {
1097
-            createThumbnailsCheckBox.setSelected(true);
1098
-            createThumbnailsCheckBox.setEnabled(false);
1099
+            else
1100
+            {
1101
+                createThumbnailsCheckBox.setEnabled(true);
1102
+            }
1103
         }
1104
         else
1105
         {
1106
-            createThumbnailsCheckBox.setEnabled(true);
1107
+            storeBinaryCheckBox.setEnabled(false);
1108
+            extractFromSlackSpaceCheckBox.setEnabled(false);
1109
+            directAccessCheckBox.setEnabled(false);
1110
+            extractEmbeddedImagesCheckBox.setEnabled(false);
1111
+            createThumbnailsCheckBox.setEnabled(false);
1112
+            deduplicateDataCheckBox.setEnabled(false);
1113
+            skinToneAnalysisCheckBox.setEnabled(false);
1114
         }
1115
     }
1116
 
1117
@@ -263,74 +206,26 @@
1118
      * Adds a checkbox, handling resources and so forth so that the caller doesn't need to.
1119
      *
1120
      * @param key the base key for looking up the resources.
1121
-     * @param container the container to add the component to.
1122
      * @param constraints layout constraints for the checkbox.
1123
      * @return the checkbox.
1124
      */
1125
-    public JCheckBox addJCheckbox(String key, Container container, Object constraints)
1126
+    public JCheckBox addJCheckbox(String key, Object constraints)
1127
     {
1128
         JCheckBox checkBox = new JCheckBox(resources.getString(key));
1129
         checkBox.setToolTipText(resources.getString(key + "ToolTip"));
1130
-        container.add(checkBox, constraints);
1131
+        add(checkBox, constraints);
1132
         return checkBox;
1133
     }
1134
 
1135
     /**
1136
-     * Adds a combo box and its label, handling resources and so forth so that
1137
-     * the caller doesn't need to.
1138
+     * Overridden to enable/disable the individual fields.
1139
      *
1140
-     * @param key the base key for looking up the resources.
1141
-     * @param container the container to add the component to.
1142
-     * @param labelConstraints layout constraints for the label.
1143
-     * @param comboBoxConstraints layout constraints for the combo box.
1144
-     * @param values the values to put in the combo box.
1145
+     * @param enabled true if this component should be enabled, false otherwise
1146
      */
1147
-    private JComboBox addJComboBox(String key, Container container,
1148
-                                   Object labelConstraints, Object comboBoxConstraints,
1149
-                                   AbstractPolicy[] values)
1150
+    public void setEnabled(boolean enabled)
1151
     {
1152
-        DefaultComboBoxModel model = new DefaultComboBoxModel();
1153
-        for (AbstractPolicy value : values)
1154
-        {
1155
-            model.addElement(new PolicyContainer(value));
1156
-        }
1157
-
1158
-        JComboBox comboBox = new JComboBox(model);
1159
-        comboBox.setPrototypeDisplayValue("English    "); // Long enough for now.
1160
-        container.add(new JLabel(resources.getString(key + "Label")), labelConstraints);
1161
-        container.add(comboBox, comboBoxConstraints);
1162
-        return comboBox;
1163
+        super.setEnabled(enabled);
1164
+        updateState();
1165
     }
1166
 
1167
-    ///////////////////////////////////////////////////////////////////////////
1168
-    // Inner Classes
1169
-
1170
-    /**
1171
-     * A container for a policy to make <code>toString()</code> return a human-readable
1172
-     * value instead of the system one.
1173
-     */
1174
-    private static class PolicyContainer
1175
-    {
1176
-        private AbstractPolicy policy;
1177
-
1178
-        private PolicyContainer(AbstractPolicy policy)
1179
-        {
1180
-            this.policy = policy;
1181
-        }
1182
-
1183
-        public String toString()
1184
-        {
1185
-            return policy.toDisplayString();
1186
-        }
1187
-
1188
-        public boolean equals(Object other)
1189
-        {
1190
-            return (other instanceof PolicyContainer) && policy.equals(((PolicyContainer) other).policy);
1191
-        }
1192
-
1193
-        public int hashCode()
1194
-        {
1195
-            return policy.hashCode();
1196
-        }
1197
-    }
1198
 }
1199
 
1200
Property changes on: data/src/java/com/nuix/investigator/cases/creation/OtherProcessingSettingsPanel.java
1201
___________________________________________________________________
1202
Name: svn:executable
1203
   + *
1204
Name: svn:keywords
1205
   + Author Date Id Revision
1206
Name: svn:eol-style
1207
   + native
1208
 
1209
Index: data/src/java/com/nuix/investigator/cases/creation/AddLoadableEvidenceModel.java
1210
===================================================================
1211
--- data/src/java/com/nuix/investigator/cases/creation/AddLoadableEvidenceModel.java	(revision 0)
1212
+++ data/src/java/com/nuix/investigator/cases/creation/AddLoadableEvidenceModel.java	(revision 0)
1213
@@ -0,0 +1,41 @@
1214
+package com.nuix.investigator.cases.creation;
1215
+
1216
+import java.util.List;
1217
+
1218
+import com.nuix.data.EvidenceInfo;
1219
+
1220
+/**
1221
+ * Model class created by the {@link AddLoadableEvidencePane}.
1222
+ */
1223
+public class AddLoadableEvidenceModel
1224
+{
1225
+    //////////////////////////////////////////////////////////////////////////////////////
1226
+    // Fields
1227
+
1228
+    /**
1229
+     * The content which will be added to the case.
1230
+     */
1231
+    private List<EvidenceInfo> caseContents;
1232
+
1233
+    //////////////////////////////////////////////////////////////////////////////////////
1234
+    // Methods
1235
+
1236
+    /**
1237
+     * Gets the content which will be added to the case.
1238
+     * @return the content which will be added to the case.
1239
+     */
1240
+    public List<EvidenceInfo> getCaseContents()
1241
+    {
1242
+        return caseContents;
1243
+    }
1244
+
1245
+    /**
1246
+     * Sets the content which will be added to the case.
1247
+     * @param caseContents the content which will be added to the case.
1248
+     */
1249
+    public void setCaseContents(List<EvidenceInfo> caseContents)
1250
+    {
1251
+        this.caseContents = caseContents;
1252
+    }
1253
+   
1254
+}
1255
Index: data/src/java/com/nuix/investigator/cases/creation/TextProcessingSettingsPanel.java
1256
===================================================================
1257
--- data/src/java/com/nuix/investigator/cases/creation/TextProcessingSettingsPanel.java	(revision 0)
1258
+++ data/src/java/com/nuix/investigator/cases/creation/TextProcessingSettingsPanel.java	(revision 0)
1259
@@ -0,0 +1,228 @@
1260
+package com.nuix.investigator.cases.creation;
1261
+
1262
+import java.awt.GridBagConstraints;
1263
+import java.awt.GridBagLayout;
1264
+import java.awt.Insets;
1265
+import java.awt.event.ActionListener;
1266
+import java.awt.event.ActionEvent;
1267
+
1268
+import javax.swing.DefaultComboBoxModel;
1269
+import javax.swing.JCheckBox;
1270
+import javax.swing.JComboBox;
1271
+import javax.swing.JLabel;
1272
+import javax.swing.JPanel;
1273
+
1274
+import com.nuix.data.DataProcessingSettings;
1275
+import com.nuix.resources.ResourceFactory;
1276
+import com.nuix.resources.ResourceGroup;
1277
+import com.nuix.store.index.settings.AbstractPolicy;
1278
+import com.nuix.store.index.settings.StemmingPolicy;
1279
+import com.nuix.store.index.settings.StopWordsPolicy;
1280
+import com.nuix.store.index.settings.TextIndexSettings;
1281
+
1282
+/**
1283
+ * Panel for specifying text data processing settings.
1284
+ */
1285
+public class TextProcessingSettingsPanel extends JPanel
1286
+{
1287
+    ///////////////////////////////////////////////////////////////////////////
1288
+    // Fields
1289
+
1290
+    /**
1291
+     * The resources for the panel.
1292
+     */
1293
+    private ResourceGroup resources =
1294
+        ResourceFactory.get("/com/nuix/investigator/cases/cases.xml")
1295
+            .getSubgroup("TextProcessingSettingsPanel");
1296
+
1297
+    /**
1298
+     * The "process text" checkbox.
1299
+     */
1300
+    private JCheckBox processTextCheckBox;
1301
+
1302
+    /**
1303
+     * The stop words policy combobox.
1304
+     */
1305
+    private JComboBox stopWordsPolicyComboBox;
1306
+
1307
+    /**
1308
+     * The stemming policy combo box.
1309
+     */
1310
+    private JComboBox stemmingPolicyComboBox;
1311
+
1312
+    ///////////////////////////////////////////////////////////////////////////
1313
+    // Constructors
1314
+
1315
+    /**
1316
+     * Create a new buffered JPanel with the specified layout manager
1317
+     */
1318
+    public TextProcessingSettingsPanel()
1319
+    {
1320
+        super(new GridBagLayout());
1321
+
1322
+        GridBagConstraints c1 = new GridBagConstraints();
1323
+        c1.insets = new Insets(4, 4, 4, 4);
1324
+        c1.anchor = GridBagConstraints.LINE_START;
1325
+        GridBagConstraints c2 = (GridBagConstraints) c1.clone();
1326
+        c2.weightx = 1.0;
1327
+        c2.gridwidth = GridBagConstraints.REMAINDER;
1328
+
1329
+        processTextCheckBox = addJCheckbox("ProcessTextOption", c2);
1330
+        stopWordsPolicyComboBox = addJComboBox("StopWordsPolicy", c1, c2,
1331
+                                               StopWordsPolicy.getAll());
1332
+        stemmingPolicyComboBox = addJComboBox("StemmingPolicy", c1, c2,
1333
+                                              StemmingPolicy.getAll());
1334
+
1335
+        processTextCheckBox.addActionListener(new ActionListener()
1336
+        {
1337
+            public void actionPerformed(ActionEvent e)
1338
+            {
1339
+                updateState();
1340
+            }
1341
+        });
1342
+
1343
+        // Load default state from a dummy model.
1344
+        importModel(new NewCaseModel());
1345
+        updateState();
1346
+    }
1347
+
1348
+    ///////////////////////////////////////////////////////////////////////////
1349
+    // Methods
1350
+
1351
+    /**
1352
+     * Copies data from the model into the user interface.
1353
+     *
1354
+     * @param model the wizard model.
1355
+     */
1356
+    private void importModel(NewCaseModel model)
1357
+    {
1358
+        DataProcessingSettings processingSettings = model.getProcessingSettings();
1359
+        processTextCheckBox.setSelected(processingSettings.getProcessText());
1360
+
1361
+        TextIndexSettings textIndexSettings = model.getCaseEvidenceSettings().getTextIndexSettings();
1362
+        stopWordsPolicyComboBox.setSelectedItem(new PolicyContainer(textIndexSettings.getStopWordsPolicy()));
1363
+        stemmingPolicyComboBox.setSelectedItem(new PolicyContainer(textIndexSettings.getStemmingPolicy()));
1364
+    }
1365
+
1366
+    /**
1367
+     * Copies data from the user interface into the model.
1368
+     *
1369
+     * @param model the wizard model.
1370
+     */
1371
+    public void exportModel(NewCaseModel model)
1372
+    {
1373
+        DataProcessingSettings processingSettings = model.getProcessingSettings();
1374
+        processingSettings.setProcessText(processTextCheckBox.isSelected());
1375
+        TextIndexSettings textIndexSettings = model.getCaseEvidenceSettings().getTextIndexSettings();
1376
+
1377
+        PolicyContainer policyContainer = (PolicyContainer) stopWordsPolicyComboBox.getSelectedItem();
1378
+        textIndexSettings.setStopWordsPolicy((StopWordsPolicy) policyContainer.policy);
1379
+        policyContainer = (PolicyContainer) stemmingPolicyComboBox.getSelectedItem();
1380
+        textIndexSettings.setStemmingPolicy((StemmingPolicy) policyContainer.policy);
1381
+    }
1382
+
1383
+    /**
1384
+     * Updates the enabled state of the individual components.
1385
+     */
1386
+    private void updateState()
1387
+    {
1388
+        if (isEnabled())
1389
+        {
1390
+            processTextCheckBox.setEnabled(true);
1391
+            boolean enable = processTextCheckBox.isSelected();
1392
+            stopWordsPolicyComboBox.setEnabled(enable);
1393
+            stemmingPolicyComboBox.setEnabled(enable);
1394
+        }
1395
+        else
1396
+        {
1397
+            processTextCheckBox.setEnabled(false);
1398
+            stopWordsPolicyComboBox.setEnabled(false);
1399
+            stemmingPolicyComboBox.setEnabled(false);
1400
+        }
1401
+    }
1402
+
1403
+    /**
1404
+     * Adds a checkbox, handling resources and so forth so that the caller doesn't need to.
1405
+     *
1406
+     * @param key the base key for looking up the resources.
1407
+     * @param constraints layout constraints for the checkbox.
1408
+     * @return the checkbox.
1409
+     */
1410
+    public JCheckBox addJCheckbox(String key, Object constraints)
1411
+    {
1412
+        JCheckBox checkBox = new JCheckBox(resources.getString(key));
1413
+        checkBox.setToolTipText(resources.getString(key + "ToolTip"));
1414
+        add(checkBox, constraints);
1415
+        return checkBox;
1416
+    }
1417
+
1418
+    /**
1419
+     * Adds a combo box and its label, handling resources and so forth so that
1420
+     * the caller doesn't need to.
1421
+     *
1422
+     * @param key the base key for looking up the resources.
1423
+     * @param labelConstraints layout constraints for the label.
1424
+     * @param comboBoxConstraints layout constraints for the combo box.
1425
+     * @param values the values to put in the combo box.
1426
+     * @return the created combo box.
1427
+     */
1428
+    private JComboBox addJComboBox(String key,
1429
+                                   Object labelConstraints, Object comboBoxConstraints,
1430
+                                   AbstractPolicy[] values)
1431
+    {
1432
+        DefaultComboBoxModel model = new DefaultComboBoxModel();
1433
+        for (AbstractPolicy value : values)
1434
+        {
1435
+            model.addElement(new PolicyContainer(value));
1436
+        }
1437
+
1438
+        JComboBox comboBox = new JComboBox(model);
1439
+        comboBox.setPrototypeDisplayValue("English    "); // Long enough for now.
1440
+        add(new JLabel(resources.getString(key + "Label")), labelConstraints);
1441
+        add(comboBox, comboBoxConstraints);
1442
+        return comboBox;
1443
+    }
1444
+
1445
+    /**
1446
+     * Overridden to enable/disable the individual fields.
1447
+     *
1448
+     * @param enabled true if this component should be enabled, false otherwise
1449
+     */
1450
+    public void setEnabled(boolean enabled)
1451
+    {
1452
+        super.setEnabled(enabled);
1453
+        updateState();
1454
+    }
1455
+
1456
+    ///////////////////////////////////////////////////////////////////////////
1457
+    // Inner Classes
1458
+
1459
+    /**
1460
+     * A container for a policy to make <code>toString()</code> return a human-readable
1461
+     * value instead of the system one.
1462
+     */
1463
+    private static class PolicyContainer
1464
+    {
1465
+        private AbstractPolicy policy;
1466
+
1467
+        private PolicyContainer(AbstractPolicy policy)
1468
+        {
1469
+            this.policy = policy;
1470
+        }
1471
+
1472
+        public String toString()
1473
+        {
1474
+            return policy.toDisplayString();
1475
+        }
1476
+
1477
+        public boolean equals(Object other)
1478
+        {
1479
+            return (other instanceof PolicyContainer) && policy.equals(((PolicyContainer) other).policy);
1480
+        }
1481
+
1482
+        public int hashCode()
1483
+        {
1484
+            return policy.hashCode();
1485
+        }
1486
+    }
1487
+}
1488
Index: data/src/java/com/nuix/investigator/cases/creation/AddLoadableEvidencePane.java
1489
===================================================================
1490
--- data/src/java/com/nuix/investigator/cases/creation/AddLoadableEvidencePane.java	(revision 0)
1491
+++ data/src/java/com/nuix/investigator/cases/creation/AddLoadableEvidencePane.java	(revision 0)
1492
@@ -0,0 +1,577 @@
1493
+package com.nuix.investigator.cases.creation;
1494
+
1495
+import java.awt.Component;
1496
+import java.awt.FlowLayout;
1497
+import java.awt.GridBagConstraints;
1498
+import java.awt.GridBagLayout;
1499
+import java.awt.Insets;
1500
+import java.awt.SystemColor;
1501
+import java.io.File;
1502
+import java.io.IOException;
1503
+import java.net.URI;
1504
+
1505
+import javax.swing.Action;
1506
+import javax.swing.JButton;
1507
+import javax.swing.JComponent;
1508
+import javax.swing.JLabel;
1509
+import javax.swing.JPanel;
1510
+import javax.swing.JScrollPane;
1511
+import javax.swing.JTree;
1512
+import javax.swing.event.TreeModelEvent;
1513
+import javax.swing.event.TreeModelListener;
1514
+import javax.swing.event.TreeSelectionEvent;
1515
+import javax.swing.event.TreeSelectionListener;
1516
+import javax.swing.tree.DefaultTreeCellRenderer;
1517
+import javax.swing.tree.TreePath;
1518
+import javax.swing.tree.TreeSelectionModel;
1519
+
1520
+import com.nuix.data.DefaultDataFactory;
1521
+import com.nuix.data.Environment;
1522
+import com.nuix.data.EvidenceInfo;
1523
+import com.nuix.investigator.cases.Case;
1524
+import com.nuix.investigator.cases.CaseContentTreeModel;
1525
+import com.nuix.investigator.cases.CaseEvidence;
1526
+import com.nuix.processor.PersistentProcessingQueue;
1527
+import com.nuix.product.Licence;
1528
+import com.nuix.resources.ResourceFactory;
1529
+import com.nuix.resources.ResourceGroup;
1530
+import com.nuix.swing.actions.BaseAction;
1531
+import com.nuix.swing.builders.DialogBuilder;
1532
+import com.nuix.swing.errors.ExpandableErrorPane;
1533
+import com.nuix.swing.widgets.ValidatingOptionPane;
1534
+import com.nuix.util.StringUtils;
1535
+
1536
+/**
1537
+ * Pane allowing the user to add loadable evidence to a simple case.
1538
+ */
1539
+public class AddLoadableEvidencePane extends ValidatingOptionPane
1540
+{
1541
+    //////////////////////////////////////////////////////////////////////////////////////
1542
+    // Fields
1543
+
1544
+    /**
1545
+     * Resources for the pane.
1546
+     */
1547
+    private static final ResourceGroup resources = ResourceFactory.get("/com/nuix/investigator/cases/cases.xml")
1548
+            .getSubgroup("AddLoadableEvidencePane");
1549
+
1550
+    /**
1551
+     * The current case.
1552
+     */
1553
+    private Case currentCase;
1554
+
1555
+    /**
1556
+     * The tree containing a view of the contents which will be indexed in the case.
1557
+     */
1558
+    private JTree caseContentTree = null;
1559
+
1560
+    /**
1561
+     * The model for the tree.
1562
+     */
1563
+    private CaseContentTreeModel caseContentTreeModel = null;
1564
+
1565
+    /**
1566
+     * A reference to the Add button.
1567
+     */
1568
+    private JButton addButton;
1569
+
1570
+    /**
1571
+     * A reference to the Remove button.
1572
+     */
1573
+    private JButton removeButton;
1574
+
1575
+    /**
1576
+     * A reference to the Edit button.
1577
+     */
1578
+    private JButton editButton;
1579
+
1580
+    /**
1581
+     * Default EvidenceInfo to use.
1582
+     */
1583
+    private EvidenceInfo lastEvidence = null;
1584
+
1585
+    /**
1586
+     * The maximum number of items the user can add to the evidence.
1587
+     */
1588
+    private int limit;
1589
+
1590
+    //////////////////////////////////////////////////////////////////////////////////////
1591
+    // Constructors
1592
+
1593
+    /**
1594
+     * Constructs the pane.
1595
+     *
1596
+     * @param currentCase the case being manipulated.
1597
+     */
1598
+    public AddLoadableEvidencePane(Case currentCase)
1599
+    {
1600
+        this.currentCase = currentCase;
1601
+
1602
+        // Is there a licence limit in place?
1603
+        String limitString = Licence.getInstance().getProperty("limit.toplevel-items");
1604
+        if (limitString != null)
1605
+        {
1606
+            limit = Integer.parseInt(limitString);
1607
+        }
1608
+
1609
+        caseContentTreeModel = new CaseContentTreeModel();
1610
+
1611
+        // Add the evidence which already exists in the case.
1612
+        // We're doing this in the constructor so that it can fail faster and bomb out
1613
+        // the action which is displaying the
1614
+        try
1615
+        {
1616
+            File evidenceLocation = currentCase.getEvidenceSet().get(0).getEvidenceLocation();
1617
+            for (File file : evidenceLocation.listFiles())
1618
+            {
1619
+                EvidenceInfo info = new EvidenceInfo();
1620
+                info.loadFromFile(file);
1621
+                caseContentTreeModel.addEvidence(info);
1622
+            }
1623
+        }
1624
+        catch (IOException e)
1625
+        {
1626
+            // Not expected to ever happen, show generic error message and throw illegal state.
1627
+            ExpandableErrorPane.showDialog(getRootPane(), e);
1628
+            throw new IllegalStateException("Error determining existing case evidence", e);
1629
+        }
1630
+    }
1631
+
1632
+    //////////////////////////////////////////////////////////////////////////////////////
1633
+    // Methods
1634
+
1635
+    /**
1636
+     * Gets the title of the dialog which will be displayed.
1637
+     *
1638
+     * @return the title.
1639
+     */
1640
+    protected String getTitle()
1641
+    {
1642
+        return resources.getString("Title");
1643
+    }
1644
+
1645
+    /**
1646
+     * Builds the components where the user can input data.
1647
+     *
1648
+     * @return the input panel.
1649
+     */
1650
+    protected JComponent buildInputPanel()
1651
+    {
1652
+        JPanel inputPanel = new JPanel(new GridBagLayout());
1653
+        GridBagConstraints c = new GridBagConstraints();
1654
+        c.insets = new Insets(0, 0, 8, 0);
1655
+        c.gridwidth = GridBagConstraints.REMAINDER;
1656
+        c.anchor = GridBagConstraints.FIRST_LINE_START;
1657
+        c.weightx = 1.0;
1658
+        c.fill = GridBagConstraints.HORIZONTAL;
1659
+
1660
+        // Top label.
1661
+        inputPanel.add(new JLabel(resources.getString("Text")), c);
1662
+
1663
+        // Case content tree.
1664
+        caseContentTree =  new JTree(caseContentTreeModel);
1665
+        caseContentTree.setRootVisible(false);
1666
+        caseContentTree.setShowsRootHandles(true);
1667
+        caseContentTree.putClientProperty("JTree.lineStyle", "Angled");
1668
+        caseContentTree.setCellRenderer(new EvidenceNameRenderer());
1669
+        caseContentTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
1670
+
1671
+        c.weighty = 1.0;
1672
+        c.fill = GridBagConstraints.BOTH;
1673
+        inputPanel.add(new JScrollPane(caseContentTree), c);
1674
+
1675
+        // Actions.
1676
+        Action addAction = new AddAction();
1677
+        Action removeAction = new RemoveAction();
1678
+        Action editAction = new EditAction();
1679
+
1680
+        // Button panel.
1681
+        addButton = new JButton(addAction);
1682
+        addButton.setDefaultCapable(false);
1683
+        removeButton = new JButton(removeAction);
1684
+        removeButton.setDefaultCapable(false);
1685
+        editButton = new JButton(editAction);
1686
+        editButton.setDefaultCapable(false);
1687
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
1688
+        buttonPanel.add(addButton);
1689
+        buttonPanel.add(removeButton);
1690
+        buttonPanel.add(editButton);
1691
+        c.weighty = 0.0;
1692
+        c.fill = GridBagConstraints.HORIZONTAL;
1693
+        inputPanel.add(buttonPanel, c);
1694
+
1695
+        // Wire the list events to enable the buttons as appropriate.
1696
+        TreeChangeListener treeChangeListener = new TreeChangeListener();
1697
+        caseContentTreeModel.addTreeModelListener(treeChangeListener);
1698
+        caseContentTree.getSelectionModel().addTreeSelectionListener(treeChangeListener);
1699
+
1700
+        return inputPanel;
1701
+    }
1702
+
1703
+    /**
1704
+     * Requests that the initial value be selected, which will set
1705
+     * focus to the initial value. This method
1706
+     * should be invoked after the window containing the option pane
1707
+     * is made visible.
1708
+     */
1709
+    public void selectInitialValue()
1710
+    {
1711
+        addButton.requestFocusInWindow();
1712
+    }
1713
+
1714
+    /**
1715
+     * Validates the input and performs the result of the dialog.
1716
+     *
1717
+     * @return <code>true</code> on success.
1718
+     */
1719
+    protected boolean validateAndPerform()
1720
+    {
1721
+        // We know the evidence sets themselves are valid, beacuse we've
1722
+        // checked them on creation.
1723
+        if (caseContentTreeModel.getChildCount(CaseContentTreeModel.ROOT_NODE) == 0)
1724
+        {
1725
+            new DialogBuilder(getRootPane(), resources).error("MustAddContent");
1726
+            return false;
1727
+        }
1728
+        else
1729
+        {
1730
+            // We already know it's a simple case.
1731
+            CaseEvidence evidence = currentCase.getEvidenceSet().get(0);
1732
+
1733
+            File persistentDir = new File(evidence.getLocation(), "Stores/PersistentQueue");
1734
+            try
1735
+            {
1736
+                // Initialise the queue first.  The factory here doesn't matter because we're
1737
+                // just using this to serialise the queue to disk.
1738
+                PersistentProcessingQueue queue = new PersistentProcessingQueue(
1739
+                        persistentDir, new DefaultDataFactory(new Environment()));
1740
+
1741
+                for (EvidenceInfo evidenceInfo : caseContentTreeModel.getEvidence())
1742
+                {
1743
+                    // Don't add it to the queue if the file is already saved.
1744
+                    if (!evidenceInfo.isSaved())
1745
+                    {
1746
+                        queue.addDataRoot(evidenceInfo.saveToFile(evidence));
1747
+                    }
1748
+                }
1749
+
1750
+                // Saves state as a side-effect.
1751
+                queue.cleanup();
1752
+                return true;
1753
+            }
1754
+            catch (IOException e)
1755
+            {
1756
+                // Not expected to ever happen, show generic error message.
1757
+                ExpandableErrorPane.showDialog(getRootPane(), e);
1758
+                return false;
1759
+            }
1760
+        }
1761
+    }
1762
+
1763
+    /**
1764
+     * To be performed after the Add and Edit actions.
1765
+     */
1766
+    private void doPostAction()
1767
+    {
1768
+        // Select the last modified EvidenceInfo instance.
1769
+        if (lastEvidence != null)
1770
+        {
1771
+            TreePath lastEvidencePath =
1772
+                new TreePath(new Object[] {CaseContentTreeModel.ROOT_NODE, lastEvidence});
1773
+            caseContentTree.expandPath(lastEvidencePath);
1774
+        }
1775
+    }
1776
+
1777
+    /**
1778
+     * Counts the number of items already added.
1779
+     *
1780
+     * @return the number of items already added.
1781
+     */
1782
+    private int countAddedItems()
1783
+    {
1784
+        int count = 0;
1785
+        for (EvidenceInfo info : caseContentTreeModel.getEvidence())
1786
+        {
1787
+            count += info.getContents().size();
1788
+        }
1789
+        return count;
1790
+    }
1791
+
1792
+    //////////////////////////////////////////////////////////////////////////////////////
1793
+    // Inner Classes
1794
+
1795
+    /**
1796
+     * Action on the Add button, which just pops up the real menu.
1797
+     */
1798
+    private class AddAction extends BaseAction
1799
+    {
1800
+        public AddAction()
1801
+        {
1802
+            super(AddLoadableEvidencePane.this, resources.getString("Add"));
1803
+        }
1804
+
1805
+        public void execute()
1806
+        {
1807
+            EvidenceInfo defaultData = new EvidenceInfo();
1808
+            defaultData.setName(generateDefaultName());
1809
+            EvidenceInputPane pane = new EvidenceInputPane(defaultData, limit, countAddedItems());
1810
+            if (pane.showDialog(getRootPane()))
1811
+            {
1812
+                EvidenceInfo choice = pane.getEvidenceInfo();
1813
+
1814
+                // Set this choice as the default.
1815
+                lastEvidence = choice;
1816
+                while (choice != null && caseContentTreeModel.containsEvidence(choice))
1817
+                {
1818
+                    // We need to prompt them to enter in another name.
1819
+                    new DialogBuilder(AddLoadableEvidencePane.this, resources).error("MustSpecifyUniqueName");
1820
+
1821
+                    // Send them back.
1822
+                    choice = null;
1823
+                    if (pane.showDialog(getRootPane()))
1824
+                    {
1825
+                        choice = pane.getEvidenceInfo();
1826
+                    }
1827
+                }
1828
+
1829
+                if (choice != null)
1830
+                {
1831
+                    caseContentTreeModel.addEvidence(choice);
1832
+                }
1833
+
1834
+                doPostAction();
1835
+            }
1836
+        }
1837
+
1838
+        /**
1839
+         * Generates a sensible default name for the evidence.
1840
+         *
1841
+         * @return the name.
1842
+         */
1843
+        private String generateDefaultName()
1844
+        {
1845
+            int counter = 1;
1846
+            boolean clash = true;
1847
+            String name = null;
1848
+            while (clash)
1849
+            {
1850
+                name = resources.getString("EvidencePrefix", counter++);
1851
+
1852
+                clash = false;
1853
+                for (EvidenceInfo info : caseContentTreeModel.getEvidence())
1854
+                {
1855
+                    if (name.equals(info.getName()))
1856
+                    {
1857
+                        clash = true;
1858
+                    }
1859
+                }
1860
+            }
1861
+            return name;
1862
+        }
1863
+    }
1864
+
1865
+    /**
1866
+     * Action on the Add button, which just pops up the real menu.
1867
+     */
1868
+    private class EditAction extends BaseAction
1869
+    {
1870
+        public EditAction()
1871
+        {
1872
+            super(AddLoadableEvidencePane.this, resources.getString("Edit"));
1873
+        }
1874
+
1875
+        public void execute()
1876
+        {
1877
+            // Get the EvidenceInfo instance selected.
1878
+            TreePath selectedPath = caseContentTree.getSelectionPath();
1879
+            // The EvidenceInfo instance is always the 2nd element.
1880
+            if (selectedPath != null)
1881
+            {
1882
+                EvidenceInfo evidenceToEdit =
1883
+                    (EvidenceInfo) selectedPath.getPath()[1];
1884
+
1885
+                // The folder we're editing isn't included in the count.
1886
+                int alreadyAdded = countAddedItems() - evidenceToEdit.getContents().size();
1887
+                EvidenceInputPane pane = new EvidenceInputPane(evidenceToEdit, limit, alreadyAdded);
1888
+                if (pane.showDialog(getRootPane()))
1889
+                {
1890
+                    // Set this choice as the default.
1891
+                    lastEvidence = pane.getEvidenceInfo();
1892
+
1893
+                    caseContentTreeModel.fireTreeStructureChanged();
1894
+                    doPostAction();
1895
+                }
1896
+            }
1897
+        }
1898
+    }
1899
+
1900
+    /**
1901
+     * Action to remove an item or items from the list.
1902
+     */
1903
+    private class RemoveAction extends BaseAction
1904
+    {
1905
+        public RemoveAction()
1906
+        {
1907
+            super(AddLoadableEvidencePane.this, resources.getString("Remove"));
1908
+        }
1909
+
1910
+        public void execute()
1911
+        {
1912
+            TreePath[] selectedPaths = caseContentTree.getSelectionPaths();
1913
+            if (selectedPaths == null)
1914
+            {
1915
+                return;
1916
+            }
1917
+
1918
+            for (TreePath selectedPath : selectedPaths)
1919
+            {
1920
+                // Get the EvidenceInfo object.
1921
+                Object[] path = selectedPath.getPath();
1922
+                // Object 0 is always CaseContentTreeModel.ROOT_NODE.
1923
+                Object evidenceItem = path[1];
1924
+                if (evidenceItem instanceof EvidenceInfo)
1925
+                {
1926
+                    // Now check if we are removing the whole EvidenceInfo
1927
+                    // or just a child.
1928
+                    if (path.length > 2)
1929
+                    {
1930
+                        // Remove the item.
1931
+                        Object item = path[2];
1932
+                        ((EvidenceInfo) evidenceItem).removeURI((URI) item);
1933
+                    }
1934
+                    else
1935
+                    {
1936
+                        // Remove the whole evidence group.
1937
+                        caseContentTreeModel.removeEvidence((EvidenceInfo) evidenceItem);
1938
+                    }
1939
+                }
1940
+            }
1941
+        }
1942
+    }
1943
+
1944
+    /**
1945
+     * A custom tree cell renderer which renders the name of the evidence items
1946
+     * instead of using <code>toString()</code>.
1947
+     */
1948
+    private class EvidenceNameRenderer extends DefaultTreeCellRenderer
1949
+    {
1950
+        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel,
1951
+                                                      boolean expanded, boolean leaf,
1952
+                                                      int row, boolean hasFocus)
1953
+        {
1954
+            super.getTreeCellRendererComponent(tree, value, sel, expanded,
1955
+                                               leaf, row, hasFocus);
1956
+
1957
+            if (value != CaseContentTreeModel.ROOT_NODE)
1958
+            {
1959
+                if (value instanceof EvidenceInfo)
1960
+                {
1961
+                    EvidenceInfo evidence = (EvidenceInfo) value;
1962
+                    if (StringUtils.isEmpty(evidence.getDescription()))
1963
+                    {
1964
+                        setText(resources.getString("EvidenceNameFormatNoDescription",
1965
+                                                    evidence.getName()));
1966
+                    }
1967
+                    else
1968
+                    {
1969
+                        setText(resources.getString("EvidenceNameFormat",
1970
+                                                    evidence.getName(),
1971
+                                                    evidence.getDescription()));
1972
+                    }
1973
+
1974
+                    if (evidence.isSaved())
1975
+                    {
1976
+                        setForeground(SystemColor.textInactiveText);
1977
+                    }
1978
+                }
1979
+                else
1980
+                {
1981
+                    setIcon(null);
1982
+
1983
+                    // Disable if the path contains a saved EvidenceInfo somewhere in it.
1984
+                    TreePath path = tree.getPathForRow(row);
1985
+                    while (path != null)
1986
+                    {
1987
+                        Object element = path.getLastPathComponent();
1988
+                        if (element instanceof EvidenceInfo && ((EvidenceInfo) element).isSaved())
1989
+                        {
1990
+                            setForeground(SystemColor.textInactiveText);
1991
+                            break;
1992
+                        }
1993
+                        path = path.getParentPath();
1994
+                    }
1995
+                }
1996
+            }
1997
+
1998
+            return this;
1999
+        }
2000
+    }
2001
+
2002
+
2003
+    /**
2004
+     * Updates the state of the buttons when the contents or the selections on the tree change.
2005
+     */
2006
+    private class TreeChangeListener implements TreeModelListener, TreeSelectionListener
2007
+    {
2008
+        private TreeChangeListener()
2009
+        {
2010
+            updateButtons();
2011
+        }
2012
+
2013
+        public void treeNodesChanged(TreeModelEvent event)
2014
+        {
2015
+            updateButtons();
2016
+        }
2017
+
2018
+        public void treeNodesInserted(TreeModelEvent event)
2019
+        {
2020
+            updateButtons();
2021
+        }
2022
+
2023
+        public void treeNodesRemoved(TreeModelEvent event)
2024
+        {
2025
+            updateButtons();
2026
+        }
2027
+
2028
+        public void treeStructureChanged(TreeModelEvent event)
2029
+        {
2030
+            updateButtons();
2031
+        }
2032
+
2033
+        public void valueChanged(TreeSelectionEvent event)
2034
+        {
2035
+            updateButtons();
2036
+        }
2037
+
2038
+        private void updateButtons()
2039
+        {
2040
+            boolean atLimit = limit > 0 && countAddedItems() >= limit;
2041
+
2042
+            int selectedEvidenceCount = 0;
2043
+            TreePath[] paths = caseContentTree.getSelectionPaths();
2044
+            if (paths != null)
2045
+            {
2046
+                for (TreePath path : paths)
2047
+                {
2048
+                    Object last = path.getLastPathComponent();
2049
+                    if (last instanceof EvidenceInfo && !((EvidenceInfo) last).isSaved())
2050
+                    {
2051
+                        selectedEvidenceCount++;
2052
+                    }
2053
+                    else
2054
+                    {
2055
+                        // Not evidence, treat this as having selected nothing.
2056
+                        selectedEvidenceCount = 0;
2057
+                        break;
2058
+                    }
2059
+                }
2060
+            }
2061
+
2062
+            // The old code used to check that there was at least one evidence present, but actually
2063
+            // it's impossible for there to be selected evidence without there being evidence to select.
2064
+            addButton.setEnabled(!atLimit);
2065
+            removeButton.setEnabled(selectedEvidenceCount > 0);
2066
+            editButton.setEnabled(selectedEvidenceCount == 1);
2067
+        }
2068
+    }
2069
+}
2070
Index: data/src/java/com/nuix/investigator/cases/creation/MailStoreInputPane.java
2071
===================================================================
2072
--- data/src/java/com/nuix/investigator/cases/creation/MailStoreInputPane.java	(revision 0)
2073
+++ data/src/java/com/nuix/investigator/cases/creation/MailStoreInputPane.java	(working copy)
2074
@@ -1,4 +1,4 @@
2075
-package com.nuix.investigator.wizard.dialogs;
2076
+package com.nuix.investigator.cases.creation;
2077
 
2078
 import java.awt.GridBagConstraints;
2079
 import java.awt.GridBagLayout;
2080
@@ -52,11 +52,7 @@
2081
      * Resources for the pane.
2082
      */
2083
     private static ResourceGroup resources =
2084
-            ResourceFactory.get("/com/nuix/investigator/wizard/wizard.xml")
2085
-                    .getSubgroup("NewCaseWizard")
2086
-                    .getSubgroup("AddCaseContent")
2087
-                    .getSubgroup("EvidenceInputPane")
2088
-                    .getSubgroup("MailStoreInputPane");
2089
+            ResourceFactory.get("/com/nuix/investigator/cases/cases.xml").getSubgroup("MailStoreInputPane");
2090
 
2091
     /**
2092
      * The combo box for choosing the type of mail store.
2093
@@ -195,7 +191,7 @@
2094
         }
2095
 
2096
         // POP3 requires a password.
2097
-        if ("pop3".equals(protocol) && StringUtils.isEmpty(password))
2098
+        if ("pop3".equals(protocol.protocolName) && StringUtils.isEmpty(password))
2099
         {
2100
             // USABILITY: Different error message for this?
2101
             new DialogBuilder(this, resources).error("FieldsNotComplete");
2102
 
2103
Property changes on: data/src/java/com/nuix/investigator/cases/creation/MailStoreInputPane.java
2104
___________________________________________________________________
2105
Name: svn:executable
2106
   + *
2107
Name: svn:keywords
2108
   + Author Date Id Revision
2109
Name: svn:eol-style
2110
   + native
2111
 
2112
Index: data/src/java/com/nuix/investigator/cases/creation/EvidenceInputPane.java
2113
===================================================================
2114
--- data/src/java/com/nuix/investigator/cases/creation/EvidenceInputPane.java	(revision 0)
2115
+++ data/src/java/com/nuix/investigator/cases/creation/EvidenceInputPane.java	(working copy)
2116
@@ -1,4 +1,4 @@
2117
-package com.nuix.investigator.wizard.dialogs;
2118
+package com.nuix.investigator.cases.creation;
2119
 
2120
 import java.awt.Dimension;
2121
 import java.awt.FlowLayout;
2122
@@ -11,6 +11,7 @@
2123
 
2124
 import javax.swing.DefaultListModel;
2125
 import javax.swing.JButton;
2126
+import javax.swing.JComponent;
2127
 import javax.swing.JFileChooser;
2128
 import javax.swing.JLabel;
2129
 import javax.swing.JList;
2130
@@ -20,30 +21,29 @@
2131
 import javax.swing.JTextArea;
2132
 import javax.swing.JTextField;
2133
 import javax.swing.JToggleButton;
2134
-import javax.swing.JComponent;
2135
 import javax.swing.SwingUtilities;
2136
+import javax.swing.event.ListDataEvent;
2137
+import javax.swing.event.ListDataListener;
2138
 import javax.swing.event.ListSelectionEvent;
2139
 import javax.swing.event.ListSelectionListener;
2140
 import javax.swing.event.PopupMenuEvent;
2141
 import javax.swing.event.PopupMenuListener;
2142
-import javax.swing.event.ListDataListener;
2143
-import javax.swing.event.ListDataEvent;
2144
 
2145
 import com.nuix.data.EvidenceInfo;
2146
 import com.nuix.data.email.DefaultImapPopDataFactory;
2147
+import com.nuix.investigator.options.global.GlobalPreferences;
2148
+import com.nuix.log.Channel;
2149
+import com.nuix.log.ChannelManager;
2150
 import com.nuix.product.Licence;
2151
 import com.nuix.product.LicencingException;
2152
-import com.nuix.resources.ResourceGroup;
2153
 import com.nuix.resources.ResourceFactory;
2154
+import com.nuix.resources.ResourceGroup;
2155
 import com.nuix.swing.actions.BaseAction;
2156
-import com.nuix.swing.builders.JPopupMenuBuilder;
2157
 import com.nuix.swing.builders.DialogBuilder;
2158
+import com.nuix.swing.builders.JPopupMenuBuilder;
2159
 import com.nuix.swing.filechooser.JFileChooserFactory;
2160
 import com.nuix.swing.widgets.ValidatingOptionPane;
2161
 import com.nuix.util.StringUtils;
2162
-import com.nuix.investigator.options.global.GlobalPreferences;
2163
-import com.nuix.log.Channel;
2164
-import com.nuix.log.ChannelManager;
2165
 
2166
 /**
2167
  * {@link JPanel} that shows a dialog box for the selection 
2168
@@ -72,9 +72,7 @@
2169
      * Resources for the pane.
2170
      */
2171
     private static ResourceGroup resources =
2172
-            ResourceFactory.get("/com/nuix/investigator/wizard/wizard.xml")
2173
-                    .getSubgroup("NewCaseWizard")
2174
-                    .getSubgroup("AddCaseContent")
2175
+            ResourceFactory.get("/com/nuix/investigator/cases/cases.xml")
2176
                     .getSubgroup("EvidenceInputPane");
2177
 
2178
     /**
2179
 
2180
Property changes on: data/src/java/com/nuix/investigator/cases/creation/EvidenceInputPane.java
2181
___________________________________________________________________
2182
Name: svn:executable
2183
   + *
2184
Name: svn:keywords
2185
   + Author Date Id Revision
2186
Name: svn:eol-style
2187
   + native
2188
 
2189
Index: data/src/java/com/nuix/investigator/cases/creation/NewCaseModel.java
2190
===================================================================
2191
--- data/src/java/com/nuix/investigator/cases/creation/NewCaseModel.java	(revision 2511)
2192
+++ data/src/java/com/nuix/investigator/cases/creation/NewCaseModel.java	(working copy)
2193
@@ -1,23 +1,17 @@
2194
-package com.nuix.investigator.wizard;
2195
+package com.nuix.investigator.cases.creation;
2196
 
2197
 import java.io.File;
2198
 import java.util.prefs.Preferences;
2199
-import java.util.List;
2200
 
2201
-import com.nuix.swing.wizard.AbstractWizardModel;
2202
-import com.nuix.data.EvidenceInfo;
2203
 import com.nuix.data.DataProcessingSettings;
2204
 import com.nuix.investigator.cases.CaseEvidenceSettings;
2205
 
2206
 /**
2207
- * A model for the New Case wizard.
2208
+ * A model for creating a new case, created by a {@link NewCasePane}.
2209
  */
2210
-public class NewCaseWizardModel extends AbstractWizardModel
2211
+public class NewCaseModel
2212
 {
2213
     //////////////////////////////////////////////////////////////////////////////////////
2214
-    // Constants
2215
-
2216
-    //////////////////////////////////////////////////////////////////////////////////////
2217
     // Fields
2218
 
2219
     /**
2220
@@ -46,11 +40,6 @@
2221
     private String caseInvestigator;
2222
 
2223
     /**
2224
-     * The content which will be added to the case.
2225
-     */
2226
-    private List<EvidenceInfo> caseContents;
2227
-
2228
-    /**
2229
      * Settings for creating the case evidence.
2230
      */
2231
     private CaseEvidenceSettings caseEvidenceSettings;
2232
@@ -71,7 +60,7 @@
2233
     /**
2234
      * Creates the wizard model.
2235
      */
2236
-    public NewCaseWizardModel()
2237
+    public NewCaseModel()
2238
     {
2239
         // Set from preferences.
2240
         prefs = Preferences.userRoot().node("/com/nuix/investigator/wizard");
2241
@@ -179,24 +168,6 @@
2242
     }
2243
 
2244
     /**
2245
-     * Gets the content which will be added to the case.
2246
-     * @return the content which will be added to the case.
2247
-     */
2248
-    public List<EvidenceInfo> getCaseContents()
2249
-    {
2250
-        return caseContents;
2251
-    }
2252
-
2253
-    /**
2254
-     * Sets the content which will be added to the case.
2255
-     * @param caseContents the content which will be added to the case.
2256
-     */
2257
-    public void setCaseContents(List<EvidenceInfo> caseContents)
2258
-    {
2259
-        this.caseContents = caseContents;
2260
-    }
2261
-
2262
-    /**
2263
      * Gets the case evidence settings.
2264
      *
2265
      * @return the case evidence settings.
2266
@@ -217,14 +188,11 @@
2267
     }
2268
 
2269
     /**
2270
-     * Sets if the wizard was completed.
2271
-     *
2272
-     * @param completed <code>true</code> if the wizard was completed, <code>false</code> otherwise.
2273
+     * Saves the preferences in the model which are useful for the next time the user
2274
+     * creates a case.
2275
      */
2276
-    public void setCompleted(boolean completed)
2277
+    public void savePrefs()
2278
     {
2279
-        super.setCompleted(completed);
2280
-
2281
         caseEvidenceSettings.storeToPreferences(prefs.node("caseEvidenceSettings"));
2282
         processingSettings.storeToPreferences(prefs.node("processingSettings"));
2283
     }
2284
 
2285
Property changes on: data/src/java/com/nuix/investigator/cases/creation/NewCaseModel.java
2286
___________________________________________________________________
2287
Name: svn:executable
2288
   + *
2289
Name: svn:keywords
2290
   + Author Date Id Revision
2291
Name: svn:eol-style
2292
   + native
2293
 
2294
Index: data/src/java/com/nuix/investigator/cases/creation/NewCasePane.java
2295
===================================================================
2296
--- data/src/java/com/nuix/investigator/cases/creation/NewCasePane.java	(revision 0)
2297
+++ data/src/java/com/nuix/investigator/cases/creation/NewCasePane.java	(revision 0)
2298
@@ -0,0 +1,145 @@
2299
+package com.nuix.investigator.cases.creation;
2300
+
2301
+import java.awt.GridBagConstraints;
2302
+import java.awt.GridBagLayout;
2303
+import java.beans.PropertyChangeListener;
2304
+import java.beans.PropertyChangeEvent;
2305
+
2306
+import javax.swing.BorderFactory;
2307
+import javax.swing.JComponent;
2308
+import javax.swing.JPanel;
2309
+
2310
+import com.nuix.resources.ResourceFactory;
2311
+import com.nuix.resources.ResourceGroup;
2312
+import com.nuix.swing.widgets.ValidatingOptionPane;
2313
+
2314
+/**
2315
+ * Pane for creating a new case.
2316
+ */
2317
+public class NewCasePane extends ValidatingOptionPane
2318
+{
2319
+    //////////////////////////////////////////////////////////////////////////////////////
2320
+    // Fields
2321
+
2322
+    /**
2323
+     * The resources for the panel.
2324
+     */
2325
+    private ResourceGroup resources =
2326
+        ResourceFactory.get("/com/nuix/investigator/cases/cases.xml").
2327
+                getSubgroup("NewCasePane");
2328
+
2329
+    /**
2330
+     * Panel for entering settings for the case itself.
2331
+     */
2332
+    private CaseSettingsPanel caseSettingsPanel;
2333
+
2334
+    /**
2335
+     * Panel for entering text processing settings.
2336
+     */
2337
+    private TextProcessingSettingsPanel textProcessingSettingsPanel;
2338
+
2339
+    /**
2340
+     * Panel for entering other processing settings.
2341
+     */
2342
+    private OtherProcessingSettingsPanel otherProcessingSettingsPanel;
2343
+
2344
+    //////////////////////////////////////////////////////////////////////////////////////
2345
+    // Methods
2346
+
2347
+    /**
2348
+     * Gets the title of the dialog which will be displayed.
2349
+     *
2350
+     * @return the title.
2351
+     */
2352
+    protected String getTitle()
2353
+    {
2354
+        return resources.getString("Title");
2355
+    }
2356
+
2357
+    /**
2358
+     * Builds the components where the user can input data.
2359
+     *
2360
+     * @return the input panel.
2361
+     */
2362
+    protected JComponent buildInputPanel()
2363
+    {
2364
+        JPanel inputPanel = new JPanel(new GridBagLayout());
2365
+
2366
+        caseSettingsPanel = new CaseSettingsPanel();
2367
+        caseSettingsPanel.setBorder(
2368
+                BorderFactory.createTitledBorder(resources.getString("CaseSettings")));
2369
+
2370
+        textProcessingSettingsPanel = new TextProcessingSettingsPanel();
2371
+        textProcessingSettingsPanel.setBorder(
2372
+                BorderFactory.createTitledBorder(resources.getString("TextProcessingSettings")));
2373
+
2374
+        otherProcessingSettingsPanel = new OtherProcessingSettingsPanel();
2375
+        otherProcessingSettingsPanel.setBorder(
2376
+                BorderFactory.createTitledBorder(resources.getString("OtherProcessingSettings")));
2377
+
2378
+        // Disable the processing settings panels if the case is not a simple case.
2379
+        caseSettingsPanel.addPropertyChangeListener(
2380
+                CaseSettingsPanel.COMPOUND_PROPERTY,
2381
+                new PropertyChangeListener()
2382
+                {
2383
+                    public void propertyChange(PropertyChangeEvent event)
2384
+                    {
2385
+                        boolean simpleCase = !((Boolean) event.getNewValue());
2386
+                        textProcessingSettingsPanel.setEnabled(simpleCase);
2387
+                        otherProcessingSettingsPanel.setEnabled(simpleCase);
2388
+                    }
2389
+                });
2390
+
2391
+        GridBagConstraints c = new GridBagConstraints();
2392
+        c.anchor = GridBagConstraints.PAGE_START;
2393
+        c.weightx = 1.0;
2394
+        c.fill = GridBagConstraints.BOTH;
2395
+        c.gridheight = 2;
2396
+        inputPanel.add(caseSettingsPanel, c);
2397
+        c.gridheight = 1;
2398
+        c.gridwidth = GridBagConstraints.REMAINDER;
2399
+        inputPanel.add(textProcessingSettingsPanel, c);
2400
+        inputPanel.add(otherProcessingSettingsPanel, c);
2401
+        return inputPanel;
2402
+    }
2403
+
2404
+
2405
+    /**
2406
+     * Requests that the initial value be selected, which will set
2407
+     * focus to the initial value.
2408
+     */
2409
+    public void selectInitialValue()
2410
+    {
2411
+        caseSettingsPanel.selectInitialValue();
2412
+    }
2413
+
2414
+    /**
2415
+     * Validates the input and performs the result of the dialog.
2416
+     *
2417
+     * @return <code>true</code> on success.
2418
+     */
2419
+    protected boolean validateAndPerform()
2420
+    {
2421
+        return caseSettingsPanel.validateInput();
2422
+    }
2423
+
2424
+    /**
2425
+     * Creates a model holding the settings in the pane.  The result of calling
2426
+     * this method will only be defined if the user has confirmed the dialog and their
2427
+     * input was determined to be valid.
2428
+     *
2429
+     * @return the new case model.
2430
+     */
2431
+    public NewCaseModel createModel()
2432
+    {
2433
+        NewCaseModel model = new NewCaseModel();
2434
+        caseSettingsPanel.exportModel(model);
2435
+        textProcessingSettingsPanel.exportModel(model);
2436
+        otherProcessingSettingsPanel.exportModel(model);
2437
+
2438
+        // Safe to save the preferences at this point.
2439
+        model.savePrefs();
2440
+
2441
+        return model;
2442
+    }
2443
+}
2444
Index: data/src/java/com/nuix/investigator/cases/creation/CaseSettingsPanel.java
2445
===================================================================
2446
--- data/src/java/com/nuix/investigator/cases/creation/CaseSettingsPanel.java	(revision 0)
2447
+++ data/src/java/com/nuix/investigator/cases/creation/CaseSettingsPanel.java	(revision 0)
2448
@@ -0,0 +1,291 @@
2449
+package com.nuix.investigator.cases.creation;
2450
+
2451
+import java.awt.GridBagConstraints;
2452
+import java.awt.GridBagLayout;
2453
+import java.awt.GridLayout;
2454
+import java.awt.Insets;
2455
+import java.awt.event.ItemListener;
2456
+import java.awt.event.ItemEvent;
2457
+import java.io.File;
2458
+import java.text.MessageFormat;
2459
+
2460
+import javax.swing.ButtonGroup;
2461
+import javax.swing.JLabel;
2462
+import javax.swing.JPanel;
2463
+import javax.swing.JRadioButton;
2464
+import javax.swing.JTextField;
2465
+import javax.swing.event.DocumentEvent;
2466
+import javax.swing.event.DocumentListener;
2467
+import javax.swing.text.JTextComponent;
2468
+
2469
+import com.nuix.investigator.cases.CaseFileView;
2470
+import com.nuix.investigator.options.global.GlobalPreferences;
2471
+import com.nuix.os.user.NativeUserUtils;
2472
+import com.nuix.product.Licence;
2473
+import com.nuix.resources.ResourceFactory;
2474
+import com.nuix.resources.ResourceGroup;
2475
+import com.nuix.swing.builders.DialogBuilder;
2476
+import com.nuix.swing.widgets.FileChooserField;
2477
+import com.nuix.util.FileUtils;
2478
+import com.nuix.util.StringUtils;
2479
+
2480
+/**
2481
+ * Panel for entering the case settings.
2482
+ */
2483
+public class CaseSettingsPanel extends JPanel
2484
+{
2485
+    //////////////////////////////////////////////////////////////////////////////////////
2486
+    // Constants
2487
+
2488
+    /**
2489
+     * The property to listen for changes in, to track the compound case checkbox.
2490
+     */
2491
+    static final String COMPOUND_PROPERTY = "compound";
2492
+
2493
+    //////////////////////////////////////////////////////////////////////////////////////
2494
+    // Fields
2495
+
2496
+    /**
2497
+     * The resources for the panel.
2498
+     */
2499
+    private ResourceGroup resources =
2500
+        ResourceFactory.get("/com/nuix/investigator/cases/cases.xml").
2501
+                getSubgroup("CaseSettingsPanel");
2502
+
2503
+    /**
2504
+     * The field which will contain the selected directory.
2505
+     */
2506
+    private FileChooserField directoryField;
2507
+
2508
+    /**
2509
+     * The field containing the case name.
2510
+     */
2511
+    private JTextComponent nameField;
2512
+
2513
+    /**
2514
+     * The field containing the case investigator.
2515
+     */
2516
+    private JTextComponent investigatorField;
2517
+
2518
+    /**
2519
+     * The field containing the case description.
2520
+     */
2521
+    private JTextComponent descriptionField;
2522
+
2523
+    /**
2524
+     * Radio button indicating that the case will be compound.
2525
+     */
2526
+    private JRadioButton compoundButton;
2527
+
2528
+    //////////////////////////////////////////////////////////////////////////////////////
2529
+    // Constructors
2530
+
2531
+    /**
2532
+     * Constructs the panel.
2533
+     */
2534
+    public CaseSettingsPanel()
2535
+    {
2536
+        JPanel panel = new JPanel(new GridBagLayout());
2537
+
2538
+        GridBagConstraints c1 = new GridBagConstraints();
2539
+        c1.insets = new Insets(4, 4, 4, 4);
2540
+        c1.anchor = GridBagConstraints.LINE_START;
2541
+        GridBagConstraints c2 = (GridBagConstraints) c1.clone();
2542
+        c2.weightx = 1.0;
2543
+        c2.fill = GridBagConstraints.HORIZONTAL;
2544
+        c2.gridwidth = GridBagConstraints.REMAINDER;
2545
+
2546
+        // Case name
2547
+        panel.add(new JLabel(resources.getString("Name")), c1);
2548
+        nameField = new JTextField(20);
2549
+        panel.add(nameField, c2);
2550
+
2551
+        // Case directory
2552
+        panel.add(new JLabel(resources.getString("Directory")), c1);
2553
+        directoryField = new FileChooserField(GlobalPreferences.CASE_DIRECTORY_KEY,
2554
+                                              FileChooserField.FILES_ONLY);
2555
+        //directoryField.setFileChecker(new NewDirectoryChecker(false));
2556
+        directoryField.setFileView(new CaseFileView());
2557
+        panel.add(directoryField, c2);
2558
+        syncDirectoryFromName();
2559
+
2560
+        // Case investigator
2561
+        panel.add(new JLabel(resources.getString("Investigator")), c1);
2562
+        investigatorField = new JTextField();
2563
+        panel.add(investigatorField, c2);
2564
+
2565
+        // Set the investigator's name automatically.
2566
+        // XXX: Later, get this from the user manager in the case?
2567
+        String investigator = NativeUserUtils.getInstance().getLongUserName();
2568
+        if (StringUtils.isEmpty(investigator))
2569
+        {
2570
+            investigator = NativeUserUtils.getInstance().getShortUserName();
2571
+        }
2572
+        investigatorField.setText(investigator);
2573
+
2574
+        // Case description
2575
+        panel.add(new JLabel(resources.getString("Description")), c1);
2576
+        descriptionField = new JTextField();
2577
+        panel.add(descriptionField, c2);
2578
+
2579
+        // Case type.  Disable compound case creation if the licence says so.
2580
+        if (Licence.getInstance().isEnabled("compound-cases"))
2581
+        {
2582
+            panel.add(new JLabel(resources.getString("Type")), c1);
2583
+            JRadioButton simpleButton = new JRadioButton(resources.getString("SimpleCase"), true);
2584
+            compoundButton = new JRadioButton(resources.getString("CompoundCase"));
2585
+            JPanel typeButtonPanel = new JPanel(new GridLayout(2, 1));
2586
+            ButtonGroup typeButtonGroup = new ButtonGroup();
2587
+            typeButtonPanel.add(simpleButton);
2588
+            typeButtonGroup.add(simpleButton);
2589
+            typeButtonPanel.add(compoundButton);
2590
+            typeButtonGroup.add(compoundButton);
2591
+            panel.add(typeButtonPanel, c2);
2592
+
2593
+            // Changes to the compound button get exposed as a property change event for the
2594
+            // property "compound".
2595
+            compoundButton.addItemListener(new ItemListener()
2596
+            {
2597
+                public void itemStateChanged(ItemEvent event)
2598
+                {
2599
+                    boolean newValue = event.getStateChange() == ItemEvent.SELECTED;
2600
+                    firePropertyChange(COMPOUND_PROPERTY, !newValue, newValue);
2601
+                }
2602
+            });
2603
+        }
2604
+
2605
+        // Auto update the name when the user specifies the directory.
2606
+        nameField.getDocument().addDocumentListener(new DocumentListener()
2607
+        {
2608
+            public void insertUpdate(DocumentEvent event)
2609
+            {
2610
+                syncDirectoryFromName();
2611
+            }
2612
+
2613
+            public void removeUpdate(DocumentEvent event)
2614
+            {
2615
+                syncDirectoryFromName();
2616
+            }
2617
+
2618
+            public void changedUpdate(DocumentEvent event)
2619
+            {
2620
+                syncDirectoryFromName();
2621
+            }
2622
+        });
2623
+
2624
+        // Set the default name.
2625
+        nameField.setText(createDefaultName());
2626
+
2627
+        // XXX: Turn off the automatic name updating if the user changes the file themselves?
2628
+        //      But how do we know it was the user?
2629
+
2630
+        // I know there is only one component here, but this helps it keep the same
2631
+        // proportions as the ProcessingSettingsPanel, which does the same layout.
2632
+        c2.fill = GridBagConstraints.BOTH;
2633
+        add(panel, c2);
2634
+        c2.weighty = 1.0;
2635
+        add(new JPanel(), c2); // Filler
2636
+    }
2637
+
2638
+    //////////////////////////////////////////////////////////////////////////////////////
2639
+    // Methods
2640
+
2641
+    /**
2642
+     * Copies data from the user interface into the model.
2643
+     *
2644
+     * @param model the model.
2645
+     */
2646
+    public void exportModel(NewCaseModel model)
2647
+    {
2648
+        model.setCaseDirectory(directoryField.getFile());
2649
+        model.setCaseName(nameField.getText());
2650
+        model.setCaseInvestigator(investigatorField.getText());
2651
+        model.setCaseDescription(descriptionField.getText());
2652
+        model.setCompound(compoundButton != null && compoundButton.isSelected());
2653
+    }
2654
+
2655
+    /**
2656
+     * Creates the default name to use for the case.  Will increment until it finds
2657
+     * a name which isn't already in the case directory.
2658
+     *
2659
+     * @return the default name.
2660
+     */
2661
+    private String createDefaultName()
2662
+    {
2663
+        MessageFormat format = new MessageFormat(resources.getString("DefaultNameFormat"));
2664
+        for (int i = 1; ; i++)
2665
+        {
2666
+            String name = format.format(new Object[] { i });
2667
+            if (!new File(directoryField.getInitialDirectory(), name).exists())
2668
+            {
2669
+                return name;
2670
+            }
2671
+        }
2672
+    }
2673
+
2674
+    /**
2675
+     * Copies the name into the directory field, with the appropriate parent directory.
2676
+     */
2677
+    private void syncDirectoryFromName()
2678
+    {
2679
+        directoryField.setFile(new File(directoryField.getInitialDirectory(),
2680
+                                        FileUtils.safeFileName(nameField.getText())));
2681
+    }
2682
+
2683
+    /**
2684
+     * Requests that the initial value be selected, which will set
2685
+     * focus to the initial value.
2686
+     */
2687
+    public void selectInitialValue()
2688
+    {
2689
+        nameField.requestFocusInWindow();
2690
+        nameField.selectAll();
2691
+    }
2692
+
2693
+    /**
2694
+     * Validates the input.
2695
+     *
2696
+     * @return <code>true</code> on success.
2697
+     */
2698
+    protected boolean validateInput()
2699
+    {
2700
+        if (directoryField.getFile() == null)
2701
+        {
2702
+            new DialogBuilder(getRootPane(), resources).error("MustEnterDirectory");
2703
+            return false;
2704
+        }
2705
+        else if (directoryField.getFile().getParentFile() == null)
2706
+        {
2707
+            new DialogBuilder(getRootPane(), resources).error("RootNotPossible");
2708
+            return false;
2709
+        }
2710
+        else if (!directoryField.getFile().getParentFile().exists())
2711
+        {
2712
+            new DialogBuilder(getRootPane(), resources).error("NoParentDirectory");
2713
+            return false;
2714
+        }
2715
+        else if (!directoryField.getFile().exists())
2716
+        {
2717
+            return true;
2718
+        }
2719
+        else if (!directoryField.getFile().isDirectory())
2720
+        {
2721
+            new DialogBuilder(getRootPane(), resources).error("NotADirectory");
2722
+            return false;
2723
+        }
2724
+        else if (directoryField.getFile().list().length > 0)
2725
+        {
2726
+            new DialogBuilder(getRootPane(), resources).error("DirectoryNotEmpty");
2727
+            return false;
2728
+        }
2729
+
2730
+        if (StringUtils.isEmpty(nameField.getText()) ||
2731
+            StringUtils.isEmpty(investigatorField.getText()))
2732
+        {
2733
+            new DialogBuilder(getRootPane(), resources).error("FieldsNotComplete");
2734
+            return false;
2735
+        }
2736
+
2737
+        return true;
2738
+    }
2739
+}
2740
Index: data/src/java/com/nuix/investigator/cases/creation/OtherProcessingSettingsPanel.java
2741
===================================================================
2742
--- data/src/java/com/nuix/investigator/cases/creation/OtherProcessingSettingsPanel.java	(revision 2511)
2743
+++ data/src/java/com/nuix/investigator/cases/creation/OtherProcessingSettingsPanel.java	(working copy)
2744
@@ -1,70 +1,40 @@
2745
-package com.nuix.investigator.wizard.panels;
2746
+package com.nuix.investigator.cases.creation;
2747
 
2748
-import com.nuix.resources.ResourceGroup;
2749
-import com.nuix.swing.wizard.AbstractWizardPanel;
2750
-import com.nuix.swing.wizard.AbstractWizardModel;
2751
-import com.nuix.investigator.images.ImageFactory;
2752
-import com.nuix.investigator.wizard.NewCaseWizardModel;
2753
-import com.nuix.data.DataProcessingSettings;
2754
-import com.nuix.store.index.settings.StopWordsPolicy;
2755
-import com.nuix.store.index.settings.StemmingPolicy;
2756
-import com.nuix.store.index.settings.TextIndexSettings;
2757
-import com.nuix.store.index.settings.AbstractPolicy;
2758
+import java.awt.GridBagConstraints;
2759
+import java.awt.GridBagLayout;
2760
+import java.awt.Insets;
2761
+import java.awt.event.ActionEvent;
2762
+import java.awt.event.ActionListener;
2763
 
2764
 import javax.swing.JCheckBox;
2765
-import javax.swing.JLabel;
2766
 import javax.swing.JPanel;
2767
-import javax.swing.BoxLayout;
2768
-import javax.swing.Box;
2769
 import javax.swing.SwingUtilities;
2770
-import javax.swing.BorderFactory;
2771
-import javax.swing.JComboBox;
2772
-import javax.swing.DefaultComboBoxModel;
2773
 
2774
-import java.awt.GridBagLayout;
2775
-import java.awt.GridBagConstraints;
2776
-import java.awt.Insets;
2777
-import java.awt.Container;
2778
-import java.awt.event.ActionListener;
2779
-import java.awt.event.ActionEvent;
2780
+import com.nuix.data.DataProcessingSettings;
2781
+import com.nuix.resources.ResourceFactory;
2782
+import com.nuix.resources.ResourceGroup;
2783
 
2784
 /**
2785
- * Wizard step for specifying the data processing settings for each case.
2786
+ * Panel for specifying other data processing settings.
2787
  */
2788
-public class CaseContentPropertiesPanel extends AbstractWizardPanel
2789
+public class OtherProcessingSettingsPanel extends JPanel
2790
 {
2791
     ///////////////////////////////////////////////////////////////////////////
2792
-    // Constants
2793
-
2794
-    ///////////////////////////////////////////////////////////////////////////
2795
     // Fields
2796
 
2797
     /**
2798
      * The resources for the panel.
2799
      */
2800
-    private ResourceGroup resources;
2801
+    private ResourceGroup resources =
2802
+        ResourceFactory.get("/com/nuix/investigator/cases/cases.xml")
2803
+            .getSubgroup("OtherProcessingSettingsPanel");
2804
 
2805
     /**
2806
-     * The "process text" checkbox.
2807
-     */
2808
-    private JCheckBox processTextCheckBox;
2809
-
2810
-    /**
2811
      * The "store binary" checkbox.
2812
      */
2813
     private JCheckBox storeBinaryCheckBox;
2814
 
2815
     /**
2816
-     * The stop words policy combobox.
2817
-     */
2818
-    private JComboBox stopWordsPolicyComboBox;
2819
-
2820
-    /**
2821
-     * The stemming policy combo box.
2822
-     */
2823
-    private JComboBox stemmingPolicyComboBox;
2824
-
2825
-    /**
2826
      * A reference to the "extract from slack space" checkbox.
2827
      */
2828
     private JCheckBox extractFromSlackSpaceCheckBox = null;
2829
@@ -98,21 +68,48 @@
2830
     // Constructors
2831
 
2832
     /**
2833
-     * Constructor initialising resources.
2834
-     * @param resources The {@link ResourceGroup} to initialise with.
2835
+     * Constructs the panel.
2836
      */
2837
-    public CaseContentPropertiesPanel(ResourceGroup resources)
2838
+    public OtherProcessingSettingsPanel()
2839
     {
2840
-        super("CaseContentPropertiesPanel");
2841
-        setLogo(ImageFactory.createIcon("WizardLeft.png"));
2842
-        this.resources = resources;
2843
+        super(new GridBagLayout());
2844
+
2845
+        GridBagConstraints c1 = new GridBagConstraints();
2846
+        c1.insets = new Insets(4, 4, 4, 4);
2847
+        c1.anchor = GridBagConstraints.LINE_START;
2848
+        GridBagConstraints c2 = (GridBagConstraints) c1.clone();
2849
+        c2.weightx = 1.0;
2850
+        c2.gridwidth = GridBagConstraints.REMAINDER;
2851
+
2852
+        // Remaining options.
2853
+        storeBinaryCheckBox = addJCheckbox("StoreBinaryOption", c2);
2854
+        extractFromSlackSpaceCheckBox = addJCheckbox("DeletedEmailsOption", c2);
2855
+        directAccessCheckBox = addJCheckbox("DirectAccessOption", c2);
2856
+        extractEmbeddedImagesCheckBox = addJCheckbox("ExtractEmbeddedImagesOption", c2);
2857
+        createThumbnailsCheckBox = addJCheckbox("CreateThumbnailsOption", c2);
2858
+        deduplicateDataCheckBox = addJCheckbox("DeduplicateDataOption", c2);
2859
+        skinToneAnalysisCheckBox = addJCheckbox("SkinToneAnalysisOption", c2);
2860
+
2861
+        // If skinToneAnalysisCheckbox is selected, then the createThumbnailsCheckbox
2862
+        // must be enabled.
2863
+        skinToneAnalysisCheckBox.addActionListener(new ActionListener()
2864
+        {
2865
+            public void actionPerformed(ActionEvent e)
2866
+            {
2867
+                updateState();
2868
+            }
2869
+        });
2870
+
2871
+        // Load default state from a dummy model.
2872
+        importModel(new NewCaseModel());
2873
+        updateState();
2874
     }
2875
 
2876
     ///////////////////////////////////////////////////////////////////////////
2877
     // Methods
2878
 
2879
     /**
2880
-     * Validates the data entered by the user. This is always true since 
2881
+     * Validates the data entered by the user. This is always true since
2882
      * we're simply altering the boolean state of checkboxes.
2883
      *
2884
      * @return <code>true</code> if the data in this panel is valid,
2885
@@ -128,12 +125,9 @@
2886
      *
2887
      * @param model the wizard model.
2888
      */
2889
-    public void importModel(AbstractWizardModel model)
2890
+    private void importModel(NewCaseModel model)
2891
     {
2892
-        NewCaseWizardModel m = (NewCaseWizardModel) model;
2893
-
2894
-        DataProcessingSettings processingSettings = m.getProcessingSettings();
2895
-        processTextCheckBox.setSelected(processingSettings.getProcessText());
2896
+        DataProcessingSettings processingSettings = model.getProcessingSettings();
2897
         storeBinaryCheckBox.setSelected(processingSettings.getStoreBinary());
2898
         extractFromSlackSpaceCheckBox.setSelected(processingSettings.getExtractFromSlackSpace());
2899
         directAccessCheckBox.setSelected(processingSettings.getDirectAccessToMailboxes());
2900
@@ -141,12 +135,6 @@
2901
         createThumbnailsCheckBox.setSelected(processingSettings.getCreateThumbnails());
2902
         deduplicateDataCheckBox.setSelected(processingSettings.getDeduplicateData());
2903
         skinToneAnalysisCheckBox.setSelected(processingSettings.getSkinToneAnalysis());
2904
-
2905
-        TextIndexSettings textIndexSettings = m.getCaseEvidenceSettings().getTextIndexSettings();
2906
-        stopWordsPolicyComboBox.setSelectedItem(new PolicyContainer(textIndexSettings.getStopWordsPolicy()));
2907
-        stemmingPolicyComboBox.setSelectedItem(new PolicyContainer(textIndexSettings.getStemmingPolicy()));
2908
-
2909
-        wireCheckboxes();
2910
     }
2911
 
2912
     /**
2913
@@ -154,12 +142,9 @@
2914
      *
2915
      * @param model the wizard model.
2916
      */
2917
-    public void exportModel(AbstractWizardModel model)
2918
+    public void exportModel(NewCaseModel model)
2919
     {
2920
-        NewCaseWizardModel m = (NewCaseWizardModel) model;
2921
-
2922
-        DataProcessingSettings processingSettings = m.getProcessingSettings();
2923
-        processingSettings.setProcessText(processTextCheckBox.isSelected());
2924
+        DataProcessingSettings processingSettings = model.getProcessingSettings();
2925
         processingSettings.setStoreBinary(storeBinaryCheckBox.isSelected());
2926
         processingSettings.setExtractFromSlackSpace(extractFromSlackSpaceCheckBox.isSelected());
2927
         processingSettings.setDirectAccessToMailboxes(directAccessCheckBox.isSelected());
2928
@@ -167,83 +152,41 @@
2929
         processingSettings.setCreateThumbnails(createThumbnailsCheckBox.isSelected());
2930
         processingSettings.setDeduplicateData(deduplicateDataCheckBox.isSelected());
2931
         processingSettings.setSkinToneAnalysis(skinToneAnalysisCheckBox.isSelected());
2932
-
2933
-        TextIndexSettings textIndexSettings = m.getCaseEvidenceSettings().getTextIndexSettings();
2934
-        PolicyContainer policyContainer = (PolicyContainer) stopWordsPolicyComboBox.getSelectedItem();
2935
-        textIndexSettings.setStopWordsPolicy((StopWordsPolicy) policyContainer.policy);
2936
-        policyContainer = (PolicyContainer) stemmingPolicyComboBox.getSelectedItem();
2937
-        textIndexSettings.setStemmingPolicy((StemmingPolicy) policyContainer.policy);
2938
     }
2939
 
2940
     /**
2941
-     * Called at the appropriate time, to initialise the contents of the panel.
2942
+     * Updates the enabled state of the individual components.
2943
      */
2944
-    protected void initialise()
2945
+    private void updateState()
2946
     {
2947
-        getContentPane().setLayout(new GridBagLayout());
2948
-
2949
-        GridBagConstraints c1 = new GridBagConstraints();
2950
-        c1.insets = new Insets(2, 4, 2, 4);
2951
-        c1.anchor = GridBagConstraints.FIRST_LINE_START;
2952
-        GridBagConstraints c2 = (GridBagConstraints) c1.clone();
2953
-        c2.weightx = 1.0;
2954
-        c2.gridwidth = GridBagConstraints.REMAINDER;
2955
-
2956
-        // Text processing options.
2957
-        JPanel textPanel = new JPanel(new GridBagLayout());
2958
-        textPanel.setBorder(BorderFactory.createTitledBorder(
2959
-            resources.getString("TextProcessingSettingsHeader")));
2960
-        processTextCheckBox = addJCheckbox("ProcessTextOption", textPanel, c2);
2961
-        stopWordsPolicyComboBox = addJComboBox("StopWordsPolicy", textPanel, c1, c1,
2962
-                                               StopWordsPolicy.getAll());
2963
-        stemmingPolicyComboBox = addJComboBox("StemmingPolicy", textPanel, c1, c2,
2964
-                                              StemmingPolicy.getAll());
2965
-
2966
-        // Remaining options.
2967
-        Box otherPanel = new Box(BoxLayout.Y_AXIS);
2968
-        otherPanel.setBorder(BorderFactory.createTitledBorder(
2969
-            resources.getString("OtherSettingsHeader")));
2970
-        storeBinaryCheckBox = addJCheckbox("StoreBinaryOption", otherPanel, c2);
2971
-        extractFromSlackSpaceCheckBox = addJCheckbox("DeletedEmailsOption", otherPanel, c2);
2972
-        directAccessCheckBox = addJCheckbox("DirectAccessOption", otherPanel, c2);
2973
-        extractEmbeddedImagesCheckBox = addJCheckbox("ExtractEmbeddedImagesOption", otherPanel, c2);
2974
-        createThumbnailsCheckBox = addJCheckbox("CreateThumbnailsOption", otherPanel, c2);
2975
-        deduplicateDataCheckBox = addJCheckbox("DeduplicateDataOption", otherPanel, c2);
2976
-        skinToneAnalysisCheckBox = addJCheckbox("SkinToneAnalysisOption", otherPanel, c2);
2977
-
2978
-        // If skinToneAnalysisCheckbox is selected, then the createThumbnailsCheckbox
2979
-        // must be enabled.
2980
-        skinToneAnalysisCheckBox.addActionListener(new ActionListener()
2981
+        if (isEnabled())
2982
         {
2983
-            public void actionPerformed(ActionEvent e)
2984
+            storeBinaryCheckBox.setEnabled(true);
2985
+            extractFromSlackSpaceCheckBox.setEnabled(true);
2986
+            directAccessCheckBox.setEnabled(true);
2987
+            extractEmbeddedImagesCheckBox.setEnabled(true);
2988
+            deduplicateDataCheckBox.setEnabled(true);
2989
+            skinToneAnalysisCheckBox.setEnabled(true);
2990
+
2991
+            if (skinToneAnalysisCheckBox.isSelected())
2992
             {
2993
-                wireCheckboxes();
2994
+                createThumbnailsCheckBox.setSelected(true);
2995
+                createThumbnailsCheckBox.setEnabled(false);
2996
             }
2997
-        });
2998
-
2999
-        // Put the whole thing together.
3000
-        c2.fill = GridBagConstraints.BOTH;
3001
-        getContentPane().add(new JLabel(resources.getString("Text")), c2);
3002
-        getContentPane().add(textPanel, c2);
3003
-        getContentPane().add(otherPanel, c2);
3004
-        c2.weighty = 1.0;
3005
-        getContentPane().add(new JPanel(), c2); // Filler
3006
-    }
3007
-
3008
-    /**
3009
-     * Make sure that any dependencies between checkboxes are handled.  Currently, if
3010
-     * the skin-tone analysis checkbox is enabled, then so must the thumbnails checkbox.
3011
-     */
3012
-    private void wireCheckboxes()
3013
-    {
3014
-        if (skinToneAnalysisCheckBox.isSelected())
3015
-        {
3016
-            createThumbnailsCheckBox.setSelected(true);
3017
-            createThumbnailsCheckBox.setEnabled(false);
3018
+            else
3019
+            {
3020
+                createThumbnailsCheckBox.setEnabled(true);
3021
+            }
3022
         }
3023
         else
3024
         {
3025
-            createThumbnailsCheckBox.setEnabled(true);
3026
+            storeBinaryCheckBox.setEnabled(false);
3027
+            extractFromSlackSpaceCheckBox.setEnabled(false);
3028
+            directAccessCheckBox.setEnabled(false);
3029
+            extractEmbeddedImagesCheckBox.setEnabled(false);
3030
+            createThumbnailsCheckBox.setEnabled(false);
3031
+            deduplicateDataCheckBox.setEnabled(false);
3032
+            skinToneAnalysisCheckBox.setEnabled(false);
3033
         }
3034
     }
3035
 
3036
@@ -263,74 +206,26 @@
3037
      * Adds a checkbox, handling resources and so forth so that the caller doesn't need to.
3038
      *
3039
      * @param key the base key for looking up the resources.
3040
-     * @param container the container to add the component to.
3041
      * @param constraints layout constraints for the checkbox.
3042
      * @return the checkbox.
3043
      */
3044
-    public JCheckBox addJCheckbox(String key, Container container, Object constraints)
3045
+    public JCheckBox addJCheckbox(String key, Object constraints)
3046
     {
3047
         JCheckBox checkBox = new JCheckBox(resources.getString(key));
3048
         checkBox.setToolTipText(resources.getString(key + "ToolTip"));
3049
-        container.add(checkBox, constraints);
3050
+        add(checkBox, constraints);
3051
         return checkBox;
3052
     }
3053
 
3054
     /**
3055
-     * Adds a combo box and its label, handling resources and so forth so that
3056
-     * the caller doesn't need to.
3057
+     * Overridden to enable/disable the individual fields.
3058
      *
3059
-     * @param key the base key for looking up the resources.
3060
-     * @param container the container to add the component to.
3061
-     * @param labelConstraints layout constraints for the label.
3062
-     * @param comboBoxConstraints layout constraints for the combo box.
3063
-     * @param values the values to put in the combo box.
3064
+     * @param enabled true if this component should be enabled, false otherwise
3065
      */
3066
-    private JComboBox addJComboBox(String key, Container container,
3067
-                                   Object labelConstraints, Object comboBoxConstraints,
3068
-                                   AbstractPolicy[] values)
3069
+    public void setEnabled(boolean enabled)
3070
     {
3071
-        DefaultComboBoxModel model = new DefaultComboBoxModel();
3072
-        for (AbstractPolicy value : values)
3073
-        {
3074
-            model.addElement(new PolicyContainer(value));
3075
-        }
3076
-
3077
-        JComboBox comboBox = new JComboBox(model);
3078
-        comboBox.setPrototypeDisplayValue("English    "); // Long enough for now.
3079
-        container.add(new JLabel(resources.getString(key + "Label")), labelConstraints);
3080
-        container.add(comboBox, comboBoxConstraints);
3081
-        return comboBox;
3082
+        super.setEnabled(enabled);
3083
+        updateState();
3084
     }
3085
 
3086
-    ///////////////////////////////////////////////////////////////////////////
3087
-    // Inner Classes
3088
-
3089
-    /**
3090
-     * A container for a policy to make <code>toString()</code> return a human-readable
3091
-     * value instead of the system one.
3092
-     */
3093
-    private static class PolicyContainer
3094
-    {
3095
-        private AbstractPolicy policy;
3096
-
3097
-        private PolicyContainer(AbstractPolicy policy)
3098
-        {
3099
-            this.policy = policy;
3100
-        }
3101
-
3102
-        public String toString()
3103
-        {
3104
-            return policy.toDisplayString();
3105
-        }
3106
-
3107
-        public boolean equals(Object other)
3108
-        {
3109
-            return (other instanceof PolicyContainer) && policy.equals(((PolicyContainer) other).policy);
3110
-        }
3111
-
3112
-        public int hashCode()
3113
-        {
3114
-            return policy.hashCode();
3115
-        }
3116
-    }
3117
 }
3118
 
3119
Property changes on: data/src/java/com/nuix/investigator/cases/creation/OtherProcessingSettingsPanel.java
3120
___________________________________________________________________
3121
Name: svn:executable
3122
   + *
3123
Name: svn:keywords
3124
   + Author Date Id Revision
3125
Name: svn:eol-style
3126
   + native
3127
 
3128
Index: data/src/java/com/nuix/investigator/cases/creation/AddLoadableEvidenceModel.java
3129
===================================================================
3130
--- data/src/java/com/nuix/investigator/cases/creation/AddLoadableEvidenceModel.java	(revision 0)
3131
+++ data/src/java/com/nuix/investigator/cases/creation/AddLoadableEvidenceModel.java	(revision 0)
3132
@@ -0,0 +1,41 @@
3133
+package com.nuix.investigator.cases.creation;
3134
+
3135
+import java.util.List;
3136
+
3137
+import com.nuix.data.EvidenceInfo;
3138
+
3139
+/**
3140
+ * Model class created by the {@link AddLoadableEvidencePane}.
3141
+ */
3142
+public class AddLoadableEvidenceModel
3143
+{
3144
+    //////////////////////////////////////////////////////////////////////////////////////
3145
+    // Fields
3146
+
3147
+    /**
3148
+     * The content which will be added to the case.
3149
+     */
3150
+    private List<EvidenceInfo> caseContents;
3151
+
3152
+    //////////////////////////////////////////////////////////////////////////////////////
3153
+    // Methods
3154
+
3155
+    /**
3156
+     * Gets the content which will be added to the case.
3157
+     * @return the content which will be added to the case.
3158
+     */
3159
+    public List<EvidenceInfo> getCaseContents()
3160
+    {
3161
+        return caseContents;
3162
+    }
3163
+
3164
+    /**
3165
+     * Sets the content which will be added to the case.
3166
+     * @param caseContents the content which will be added to the case.
3167
+     */
3168
+    public void setCaseContents(List<EvidenceInfo> caseContents)
3169
+    {
3170
+        this.caseContents = caseContents;
3171
+    }
3172
+   
3173
+}
3174
Index: data/src/java/com/nuix/investigator/cases/creation/TextProcessingSettingsPanel.java
3175
===================================================================
3176
--- data/src/java/com/nuix/investigator/cases/creation/TextProcessingSettingsPanel.java	(revision 0)
3177
+++ data/src/java/com/nuix/investigator/cases/creation/TextProcessingSettingsPanel.java	(revision 0)
3178
@@ -0,0 +1,228 @@
3179
+package com.nuix.investigator.cases.creation;
3180
+
3181
+import java.awt.GridBagConstraints;
3182
+import java.awt.GridBagLayout;
3183
+import java.awt.Insets;
3184
+import java.awt.event.ActionListener;
3185
+import java.awt.event.ActionEvent;
3186
+
3187
+import javax.swing.DefaultComboBoxModel;
3188
+import javax.swing.JCheckBox;
3189
+import javax.swing.JComboBox;
3190
+import javax.swing.JLabel;
3191
+import javax.swing.JPanel;
3192
+
3193
+import com.nuix.data.DataProcessingSettings;
3194
+import com.nuix.resources.ResourceFactory;
3195
+import com.nuix.resources.ResourceGroup;
3196
+import com.nuix.store.index.settings.AbstractPolicy;
3197
+import com.nuix.store.index.settings.StemmingPolicy;
3198
+import com.nuix.store.index.settings.StopWordsPolicy;
3199
+import com.nuix.store.index.settings.TextIndexSettings;
3200
+
3201
+/**
3202
+ * Panel for specifying text data processing settings.
3203
+ */
3204
+public class TextProcessingSettingsPanel extends JPanel
3205
+{
3206
+    ///////////////////////////////////////////////////////////////////////////
3207
+    // Fields
3208
+
3209
+    /**
3210
+     * The resources for the panel.
3211
+     */
3212
+    private ResourceGroup resources =
3213
+        ResourceFactory.get("/com/nuix/investigator/cases/cases.xml")
3214
+            .getSubgroup("TextProcessingSettingsPanel");
3215
+
3216
+    /**
3217
+     * The "process text" checkbox.
3218
+     */
3219
+    private JCheckBox processTextCheckBox;
3220
+
3221
+    /**
3222
+     * The stop words policy combobox.
3223
+     */
3224
+    private JComboBox stopWordsPolicyComboBox;
3225
+
3226
+    /**
3227
+     * The stemming policy combo box.
3228
+     */
3229
+    private JComboBox stemmingPolicyComboBox;
3230
+
3231
+    ///////////////////////////////////////////////////////////////////////////
3232
+    // Constructors
3233
+
3234
+    /**
3235
+     * Create a new buffered JPanel with the specified layout manager
3236
+     */
3237
+    public TextProcessingSettingsPanel()
3238
+    {
3239
+        super(new GridBagLayout());
3240
+
3241
+        GridBagConstraints c1 = new GridBagConstraints();
3242
+        c1.insets = new Insets(4, 4, 4, 4);
3243
+        c1.anchor = GridBagConstraints.LINE_START;
3244
+        GridBagConstraints c2 = (GridBagConstraints) c1.clone();
3245
+        c2.weightx = 1.0;
3246
+        c2.gridwidth = GridBagConstraints.REMAINDER;
3247
+
3248
+        processTextCheckBox = addJCheckbox("ProcessTextOption", c2);
3249
+        stopWordsPolicyComboBox = addJComboBox("StopWordsPolicy", c1, c2,
3250
+                                               StopWordsPolicy.getAll());
3251
+        stemmingPolicyComboBox = addJComboBox("StemmingPolicy", c1, c2,
3252
+                                              StemmingPolicy.getAll());
3253
+
3254
+        processTextCheckBox.addActionListener(new ActionListener()
3255
+        {
3256
+            public void actionPerformed(ActionEvent e)
3257
+            {
3258
+                updateState();
3259
+            }
3260
+        });
3261
+
3262
+        // Load default state from a dummy model.
3263
+        importModel(new NewCaseModel());
3264
+        updateState();
3265
+    }
3266
+
3267
+    ///////////////////////////////////////////////////////////////////////////
3268
+    // Methods
3269
+
3270
+    /**
3271
+     * Copies data from the model into the user interface.
3272
+     *
3273
+     * @param model the wizard model.
3274
+     */
3275
+    private void importModel(NewCaseModel model)
3276
+    {
3277
+        DataProcessingSettings processingSettings = model.getProcessingSettings();
3278
+        processTextCheckBox.setSelected(processingSettings.getProcessText());
3279
+
3280
+        TextIndexSettings textIndexSettings = model.getCaseEvidenceSettings().getTextIndexSettings();
3281
+        stopWordsPolicyComboBox.setSelectedItem(new PolicyContainer(textIndexSettings.getStopWordsPolicy()));
3282
+        stemmingPolicyComboBox.setSelectedItem(new PolicyContainer(textIndexSettings.getStemmingPolicy()));
3283
+    }
3284
+
3285
+    /**
3286
+     * Copies data from the user interface into the model.
3287
+     *
3288
+     * @param model the wizard model.
3289
+     */
3290
+    public void exportModel(NewCaseModel model)
3291
+    {
3292
+        DataProcessingSettings processingSettings = model.getProcessingSettings();
3293
+        processingSettings.setProcessText(processTextCheckBox.isSelected());
3294
+        TextIndexSettings textIndexSettings = model.getCaseEvidenceSettings().getTextIndexSettings();
3295
+
3296
+        PolicyContainer policyContainer = (PolicyContainer) stopWordsPolicyComboBox.getSelectedItem();
3297
+        textIndexSettings.setStopWordsPolicy((StopWordsPolicy) policyContainer.policy);
3298
+        policyContainer = (PolicyContainer) stemmingPolicyComboBox.getSelectedItem();
3299
+        textIndexSettings.setStemmingPolicy((StemmingPolicy) policyContainer.policy);
3300
+    }
3301
+
3302
+    /**
3303
+     * Updates the enabled state of the individual components.
3304
+     */
3305
+    private void updateState()
3306
+    {
3307
+        if (isEnabled())
3308
+        {
3309
+            processTextCheckBox.setEnabled(true);
3310
+            boolean enable = processTextCheckBox.isSelected();
3311
+            stopWordsPolicyComboBox.setEnabled(enable);
3312
+            stemmingPolicyComboBox.setEnabled(enable);
3313
+        }
3314
+        else
3315
+        {
3316
+            processTextCheckBox.setEnabled(false);
3317
+            stopWordsPolicyComboBox.setEnabled(false);
3318
+            stemmingPolicyComboBox.setEnabled(false);
3319
+        }
3320
+    }
3321
+
3322
+    /**
3323
+     * Adds a checkbox, handling resources and so forth so that the caller doesn't need to.
3324
+     *
3325
+     * @param key the base key for looking up the resources.
3326
+     * @param constraints layout constraints for the checkbox.
3327
+     * @return the checkbox.
3328
+     */
3329
+    public JCheckBox addJCheckbox(String key, Object constraints)
3330
+    {
3331
+        JCheckBox checkBox = new JCheckBox(resources.getString(key));
3332
+        checkBox.setToolTipText(resources.getString(key + "ToolTip"));
3333
+        add(checkBox, constraints);
3334
+        return checkBox;
3335
+    }
3336
+
3337
+    /**
3338
+     * Adds a combo box and its label, handling resources and so forth so that
3339
+     * the caller doesn't need to.
3340
+     *
3341
+     * @param key the base key for looking up the resources.
3342
+     * @param labelConstraints layout constraints for the label.
3343
+     * @param comboBoxConstraints layout constraints for the combo box.
3344
+     * @param values the values to put in the combo box.
3345
+     * @return the created combo box.
3346
+     */
3347
+    private JComboBox addJComboBox(String key,
3348
+                                   Object labelConstraints, Object comboBoxConstraints,
3349
+                                   AbstractPolicy[] values)
3350
+    {
3351
+        DefaultComboBoxModel model = new DefaultComboBoxModel();
3352
+        for (AbstractPolicy value : values)
3353
+        {
3354
+            model.addElement(new PolicyContainer(value));
3355
+        }
3356
+
3357
+        JComboBox comboBox = new JComboBox(model);
3358
+        comboBox.setPrototypeDisplayValue("English    "); // Long enough for now.
3359
+        add(new JLabel(resources.getString(key + "Label")), labelConstraints);
3360
+        add(comboBox, comboBoxConstraints);
3361
+        return comboBox;
3362
+    }
3363
+
3364
+    /**
3365
+     * Overridden to enable/disable the individual fields.
3366
+     *
3367
+     * @param enabled true if this component should be enabled, false otherwise
3368
+     */
3369
+    public void setEnabled(boolean enabled)
3370
+    {
3371
+        super.setEnabled(enabled);
3372
+        updateState();
3373
+    }
3374
+
3375
+    ///////////////////////////////////////////////////////////////////////////
3376
+    // Inner Classes
3377
+
3378
+    /**
3379
+     * A container for a policy to make <code>toString()</code> return a human-readable
3380
+     * value instead of the system one.
3381
+     */
3382
+    private static class PolicyContainer
3383
+    {
3384
+        private AbstractPolicy policy;
3385
+
3386
+        private PolicyContainer(AbstractPolicy policy)
3387
+        {
3388
+            this.policy = policy;
3389
+        }
3390
+
3391
+        public String toString()
3392
+        {
3393
+            return policy.toDisplayString();
3394
+        }
3395
+
3396
+        public boolean equals(Object other)
3397
+        {
3398
+            return (other instanceof PolicyContainer) && policy.equals(((PolicyContainer) other).policy);
3399
+        }
3400
+
3401
+        public int hashCode()
3402
+        {
3403
+            return policy.hashCode();
3404
+        }
3405
+    }
3406
+}
3407
Index: data/src/java/com/nuix/investigator/cases/creation/AddLoadableEvidencePane.java
3408
===================================================================
3409
--- data/src/java/com/nuix/investigator/cases/creation/AddLoadableEvidencePane.java	(revision 0)
3410
+++ data/src/java/com/nuix/investigator/cases/creation/AddLoadableEvidencePane.java	(revision 0)
3411
@@ -0,0 +1,577 @@
3412
+package com.nuix.investigator.cases.creation;
3413
+
3414
+import java.awt.Component;
3415
+import java.awt.FlowLayout;
3416
+import java.awt.GridBagConstraints;
3417
+import java.awt.GridBagLayout;
3418
+import java.awt.Insets;
3419
+import java.awt.SystemColor;
3420
+import java.io.File;
3421
+import java.io.IOException;
3422
+import java.net.URI;
3423
+
3424
+import javax.swing.Action;
3425
+import javax.swing.JButton;
3426
+import javax.swing.JComponent;
3427
+import javax.swing.JLabel;
3428
+import javax.swing.JPanel;
3429
+import javax.swing.JScrollPane;
3430
+import javax.swing.JTree;
3431
+import javax.swing.event.TreeModelEvent;
3432
+import javax.swing.event.TreeModelListener;
3433
+import javax.swing.event.TreeSelectionEvent;
3434
+import javax.swing.event.TreeSelectionListener;
3435
+import javax.swing.tree.DefaultTreeCellRenderer;
3436
+import javax.swing.tree.TreePath;
3437
+import javax.swing.tree.TreeSelectionModel;
3438
+
3439
+import com.nuix.data.DefaultDataFactory;
3440
+import com.nuix.data.Environment;
3441
+import com.nuix.data.EvidenceInfo;
3442
+import com.nuix.investigator.cases.Case;
3443
+import com.nuix.investigator.cases.CaseContentTreeModel;
3444
+import com.nuix.investigator.cases.CaseEvidence;
3445
+import com.nuix.processor.PersistentProcessingQueue;
3446
+import com.nuix.product.Licence;
3447
+import com.nuix.resources.ResourceFactory;
3448
+import com.nuix.resources.ResourceGroup;
3449
+import com.nuix.swing.actions.BaseAction;
3450
+import com.nuix.swing.builders.DialogBuilder;
3451
+import com.nuix.swing.errors.ExpandableErrorPane;
3452
+import com.nuix.swing.widgets.ValidatingOptionPane;
3453
+import com.nuix.util.StringUtils;
3454
+
3455
+/**
3456
+ * Pane allowing the user to add loadable evidence to a simple case.
3457
+ */
3458
+public class AddLoadableEvidencePane extends ValidatingOptionPane
3459
+{
3460
+    //////////////////////////////////////////////////////////////////////////////////////
3461
+    // Fields
3462
+
3463
+    /**
3464
+     * Resources for the pane.
3465
+     */
3466
+    private static final ResourceGroup resources = ResourceFactory.get("/com/nuix/investigator/cases/cases.xml")
3467
+            .getSubgroup("AddLoadableEvidencePane");
3468
+
3469
+    /**
3470
+     * The current case.
3471
+     */
3472
+    private Case currentCase;
3473
+
3474
+    /**
3475
+     * The tree containing a view of the contents which will be indexed in the case.
3476
+     */
3477
+    private JTree caseContentTree = null;
3478
+
3479
+    /**
3480
+     * The model for the tree.
3481
+     */
3482
+    private CaseContentTreeModel caseContentTreeModel = null;
3483
+
3484
+    /**
3485
+     * A reference to the Add button.
3486
+     */
3487
+    private JButton addButton;
3488
+
3489
+    /**
3490
+     * A reference to the Remove button.
3491
+     */
3492
+    private JButton removeButton;
3493
+
3494
+    /**
3495
+     * A reference to the Edit button.
3496
+     */
3497
+    private JButton editButton;
3498
+
3499
+    /**
3500
+     * Default EvidenceInfo to use.
3501
+     */
3502
+    private EvidenceInfo lastEvidence = null;
3503
+
3504
+    /**
3505
+     * The maximum number of items the user can add to the evidence.
3506
+     */
3507
+    private int limit;
3508
+
3509
+    //////////////////////////////////////////////////////////////////////////////////////
3510
+    // Constructors
3511
+
3512
+    /**
3513
+     * Constructs the pane.
3514
+     *
3515
+     * @param currentCase the case being manipulated.
3516
+     */
3517
+    public AddLoadableEvidencePane(Case currentCase)
3518
+    {
3519
+        this.currentCase = currentCase;
3520
+
3521
+        // Is there a licence limit in place?
3522
+        String limitString = Licence.getInstance().getProperty("limit.toplevel-items");
3523
+        if (limitString != null)
3524
+        {
3525
+            limit = Integer.parseInt(limitString);
3526
+        }
3527
+
3528
+        caseContentTreeModel = new CaseContentTreeModel();
3529
+
3530
+        // Add the evidence which already exists in the case.
3531
+        // We're doing this in the constructor so that it can fail faster and bomb out
3532
+        // the action which is displaying the
3533
+        try
3534
+        {
3535
+            File evidenceLocation = currentCase.getEvidenceSet().get(0).getEvidenceLocation();
3536
+            for (File file : evidenceLocation.listFiles())
3537
+            {
3538
+                EvidenceInfo info = new EvidenceInfo();
3539
+                info.loadFromFile(file);
3540
+                caseContentTreeModel.addEvidence(info);
3541
+            }
3542
+        }
3543
+        catch (IOException e)
3544
+        {
3545
+            // Not expected to ever happen, show generic error message and throw illegal state.
3546
+            ExpandableErrorPane.showDialog(getRootPane(), e);
3547
+            throw new IllegalStateException("Error determining existing case evidence", e);
3548
+        }
3549
+    }
3550
+
3551
+    //////////////////////////////////////////////////////////////////////////////////////
3552
+    // Methods
3553
+
3554
+    /**
3555
+     * Gets the title of the dialog which will be displayed.
3556
+     *
3557
+     * @return the title.
3558
+     */
3559
+    protected String getTitle()
3560
+    {
3561
+        return resources.getString("Title");
3562
+    }
3563
+
3564
+    /**
3565
+     * Builds the components where the user can input data.
3566
+     *
3567
+     * @return the input panel.
3568
+     */
3569
+    protected JComponent buildInputPanel()
3570
+    {
3571
+        JPanel inputPanel = new JPanel(new GridBagLayout());
3572
+        GridBagConstraints c = new GridBagConstraints();
3573
+        c.insets = new Insets(0, 0, 8, 0);
3574
+        c.gridwidth = GridBagConstraints.REMAINDER;
3575
+        c.anchor = GridBagConstraints.FIRST_LINE_START;
3576
+        c.weightx = 1.0;
3577
+        c.fill = GridBagConstraints.HORIZONTAL;
3578
+
3579
+        // Top label.
3580
+        inputPanel.add(new JLabel(resources.getString("Text")), c);
3581
+
3582
+        // Case content tree.
3583
+        caseContentTree =  new JTree(caseContentTreeModel);
3584
+        caseContentTree.setRootVisible(false);
3585
+        caseContentTree.setShowsRootHandles(true);
3586
+        caseContentTree.putClientProperty("JTree.lineStyle", "Angled");
3587
+        caseContentTree.setCellRenderer(new EvidenceNameRenderer());
3588
+        caseContentTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
3589
+
3590
+        c.weighty = 1.0;
3591
+        c.fill = GridBagConstraints.BOTH;
3592
+        inputPanel.add(new JScrollPane(caseContentTree), c);
3593
+
3594
+        // Actions.
3595
+        Action addAction = new AddAction();
3596
+        Action removeAction = new RemoveAction();
3597
+        Action editAction = new EditAction();
3598
+
3599
+        // Button panel.
3600
+        addButton = new JButton(addAction);
3601
+        addButton.setDefaultCapable(false);
3602
+        removeButton = new JButton(removeAction);
3603
+        removeButton.setDefaultCapable(false);
3604
+        editButton = new JButton(editAction);
3605
+        editButton.setDefaultCapable(false);
3606
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
3607
+        buttonPanel.add(addButton);
3608
+        buttonPanel.add(removeButton);
3609
+        buttonPanel.add(editButton);
3610
+        c.weighty = 0.0;
3611
+        c.fill = GridBagConstraints.HORIZONTAL;
3612
+        inputPanel.add(buttonPanel, c);
3613
+
3614
+        // Wire the list events to enable the buttons as appropriate.
3615
+        TreeChangeListener treeChangeListener = new TreeChangeListener();
3616
+        caseContentTreeModel.addTreeModelListener(treeChangeListener);
3617
+        caseContentTree.getSelectionModel().addTreeSelectionListener(treeChangeListener);
3618
+
3619
+        return inputPanel;
3620
+    }
3621
+
3622
+    /**
3623
+     * Requests that the initial value be selected, which will set
3624
+     * focus to the initial value. This method
3625
+     * should be invoked after the window containing the option pane
3626
+     * is made visible.
3627
+     */
3628
+    public void selectInitialValue()
3629
+    {
3630
+        addButton.requestFocusInWindow();
3631
+    }
3632
+
3633
+    /**
3634
+     * Validates the input and performs the result of the dialog.
3635
+     *
3636
+     * @return <code>true</code> on success.
3637
+     */
3638
+    protected boolean validateAndPerform()
3639
+    {
3640
+        // We know the evidence sets themselves are valid, beacuse we've
3641
+        // checked them on creation.
3642
+        if (caseContentTreeModel.getChildCount(CaseContentTreeModel.ROOT_NODE) == 0)
3643
+        {
3644
+            new DialogBuilder(getRootPane(), resources).error("MustAddContent");
3645
+            return false;
3646
+        }
3647
+        else
3648
+        {
3649
+            // We already know it's a simple case.
3650
+            CaseEvidence evidence = currentCase.getEvidenceSet().get(0);
3651
+
3652
+            File persistentDir = new File(evidence.getLocation(), "Stores/PersistentQueue");
3653
+            try
3654
+            {
3655
+                // Initialise the queue first.  The factory here doesn't matter because we're
3656
+                // just using this to serialise the queue to disk.
3657
+                PersistentProcessingQueue queue = new PersistentProcessingQueue(
3658
+                        persistentDir, new DefaultDataFactory(new Environment()));
3659
+
3660
+                for (EvidenceInfo evidenceInfo : caseContentTreeModel.getEvidence())
3661
+                {
3662
+                    // Don't add it to the queue if the file is already saved.
3663
+                    if (!evidenceInfo.isSaved())
3664
+                    {
3665
+                        queue.addDataRoot(evidenceInfo.saveToFile(evidence));
3666
+                    }
3667
+                }
3668
+
3669
+                // Saves state as a side-effect.
3670
+                queue.cleanup();
3671
+                return true;
3672
+            }
3673
+            catch (IOException e)
3674
+            {
3675
+                // Not expected to ever happen, show generic error message.
3676
+                ExpandableErrorPane.showDialog(getRootPane(), e);
3677
+                return false;
3678
+            }
3679
+        }
3680
+    }
3681
+
3682
+    /**
3683
+     * To be performed after the Add and Edit actions.
3684
+     */
3685
+    private void doPostAction()
3686
+    {
3687
+        // Select the last modified EvidenceInfo instance.
3688
+        if (lastEvidence != null)
3689
+        {
3690
+            TreePath lastEvidencePath =
3691
+                new TreePath(new Object[] {CaseContentTreeModel.ROOT_NODE, lastEvidence});
3692
+            caseContentTree.expandPath(lastEvidencePath);
3693
+        }
3694
+    }
3695
+
3696
+    /**
3697
+     * Counts the number of items already added.
3698
+     *
3699
+     * @return the number of items already added.
3700
+     */
3701
+    private int countAddedItems()
3702
+    {
3703
+        int count = 0;
3704
+        for (EvidenceInfo info : caseContentTreeModel.getEvidence())
3705
+        {
3706
+            count += info.getContents().size();
3707
+        }
3708
+        return count;
3709
+    }
3710
+
3711
+    //////////////////////////////////////////////////////////////////////////////////////
3712
+    // Inner Classes
3713
+
3714
+    /**
3715
+     * Action on the Add button, which just pops up the real menu.
3716
+     */
3717
+    private class AddAction extends BaseAction
3718
+    {
3719
+        public AddAction()
3720
+        {
3721
+            super(AddLoadableEvidencePane.this, resources.getString("Add"));
3722
+        }
3723
+
3724
+        public void execute()
3725
+        {
3726
+            EvidenceInfo defaultData = new EvidenceInfo();
3727
+            defaultData.setName(generateDefaultName());
3728
+            EvidenceInputPane pane = new EvidenceInputPane(defaultData, limit, countAddedItems());
3729
+            if (pane.showDialog(getRootPane()))
3730
+            {
3731
+                EvidenceInfo choice = pane.getEvidenceInfo();
3732
+
3733
+                // Set this choice as the default.
3734
+                lastEvidence = choice;
3735
+                while (choice != null && caseContentTreeModel.containsEvidence(choice))
3736
+                {
3737
+                    // We need to prompt them to enter in another name.
3738
+                    new DialogBuilder(AddLoadableEvidencePane.this, resources).error("MustSpecifyUniqueName");
3739
+
3740
+                    // Send them back.
3741
+                    choice = null;
3742
+                    if (pane.showDialog(getRootPane()))
3743
+                    {
3744
+                        choice = pane.getEvidenceInfo();
3745
+                    }
3746
+                }
3747
+
3748
+                if (choice != null)
3749
+                {
3750
+                    caseContentTreeModel.addEvidence(choice);
3751
+                }
3752
+
3753
+                doPostAction();
3754
+            }
3755
+        }
3756
+
3757
+        /**
3758
+         * Generates a sensible default name for the evidence.
3759
+         *
3760
+         * @return the name.
3761
+         */
3762
+        private String generateDefaultName()
3763
+        {
3764
+            int counter = 1;
3765
+            boolean clash = true;
3766
+            String name = null;
3767
+            while (clash)
3768
+            {
3769
+                name = resources.getString("EvidencePrefix", counter++);
3770
+
3771
+                clash = false;
3772
+                for (EvidenceInfo info : caseContentTreeModel.getEvidence())
3773
+                {
3774
+                    if (name.equals(info.getName()))
3775
+                    {
3776
+                        clash = true;
3777
+                    }
3778
+                }
3779
+            }
3780
+            return name;
3781
+        }
3782
+    }
3783
+
3784
+    /**
3785
+     * Action on the Add button, which just pops up the real menu.
3786
+     */
3787
+    private class EditAction extends BaseAction
3788
+    {
3789
+        public EditAction()
3790
+        {
3791
+            super(AddLoadableEvidencePane.this, resources.getString("Edit"));
3792
+        }
3793
+
3794
+        public void execute()
3795
+        {
3796
+            // Get the EvidenceInfo instance selected.
3797
+            TreePath selectedPath = caseContentTree.getSelectionPath();
3798
+            // The EvidenceInfo instance is always the 2nd element.
3799
+            if (selectedPath != null)
3800
+            {
3801
+                EvidenceInfo evidenceToEdit =
3802
+                    (EvidenceInfo) selectedPath.getPath()[1];
3803
+
3804
+                // The folder we're editing isn't included in the count.
3805
+                int alreadyAdded = countAddedItems() - evidenceToEdit.getContents().size();
3806
+                EvidenceInputPane pane = new EvidenceInputPane(evidenceToEdit, limit, alreadyAdded);
3807
+                if (pane.showDialog(getRootPane()))
3808
+                {
3809
+                    // Set this choice as the default.
3810
+                    lastEvidence = pane.getEvidenceInfo();
3811
+
3812
+                    caseContentTreeModel.fireTreeStructureChanged();
3813
+                    doPostAction();
3814
+                }
3815
+            }
3816
+        }
3817
+    }
3818
+
3819
+    /**
3820
+     * Action to remove an item or items from the list.
3821
+     */
3822
+    private class RemoveAction extends BaseAction
3823
+    {
3824
+        public RemoveAction()
3825
+        {
3826
+            super(AddLoadableEvidencePane.this, resources.getString("Remove"));
3827
+        }
3828
+
3829
+        public void execute()
3830
+        {
3831
+            TreePath[] selectedPaths = caseContentTree.getSelectionPaths();
3832
+            if (selectedPaths == null)
3833
+            {
3834
+                return;
3835
+            }
3836
+
3837
+            for (TreePath selectedPath : selectedPaths)
3838
+            {
3839
+                // Get the EvidenceInfo object.
3840
+                Object[] path = selectedPath.getPath();
3841
+                // Object 0 is always CaseContentTreeModel.ROOT_NODE.
3842
+                Object evidenceItem = path[1];
3843
+                if (evidenceItem instanceof EvidenceInfo)
3844
+                {
3845
+                    // Now check if we are removing the whole EvidenceInfo
3846
+                    // or just a child.
3847
+                    if (path.length > 2)
3848
+                    {
3849
+                        // Remove the item.
3850
+                        Object item = path[2];
3851
+                        ((EvidenceInfo) evidenceItem).removeURI((URI) item);
3852
+                    }
3853
+                    else
3854
+                    {
3855
+                        // Remove the whole evidence group.
3856
+                        caseContentTreeModel.removeEvidence((EvidenceInfo) evidenceItem);
3857
+                    }
3858
+                }
3859
+            }
3860
+        }
3861
+    }
3862
+
3863
+    /**
3864
+     * A custom tree cell renderer which renders the name of the evidence items
3865
+     * instead of using <code>toString()</code>.
3866
+     */
3867
+    private class EvidenceNameRenderer extends DefaultTreeCellRenderer
3868
+    {
3869
+        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel,
3870
+                                                      boolean expanded, boolean leaf,
3871
+                                                      int row, boolean hasFocus)
3872
+        {
3873
+            super.getTreeCellRendererComponent(tree, value, sel, expanded,
3874
+                                               leaf, row, hasFocus);
3875
+
3876
+            if (value != CaseContentTreeModel.ROOT_NODE)
3877
+            {
3878
+                if (value instanceof EvidenceInfo)
3879
+                {
3880
+                    EvidenceInfo evidence = (EvidenceInfo) value;
3881
+                    if (StringUtils.isEmpty(evidence.getDescription()))
3882
+                    {
3883
+                        setText(resources.getString("EvidenceNameFormatNoDescription",
3884
+                                                    evidence.getName()));
3885
+                    }
3886
+                    else
3887
+                    {
3888
+                        setText(resources.getString("EvidenceNameFormat",
3889
+                                                    evidence.getName(),
3890
+                                                    evidence.getDescription()));
3891
+                    }
3892
+
3893
+                    if (evidence.isSaved())
3894
+                    {
3895
+                        setForeground(SystemColor.textInactiveText);
3896
+                    }
3897
+                }
3898
+                else
3899
+                {
3900
+                    setIcon(null);
3901
+
3902
+                    // Disable if the path contains a saved EvidenceInfo somewhere in it.
3903
+                    TreePath path = tree.getPathForRow(row);
3904
+                    while (path != null)
3905
+                    {
3906
+                        Object element = path.getLastPathComponent();
3907
+                        if (element instanceof EvidenceInfo && ((EvidenceInfo) element).isSaved())
3908
+                        {
3909
+                            setForeground(SystemColor.textInactiveText);
3910
+                            break;
3911
+                        }
3912
+                        path = path.getParentPath();
3913
+                    }
3914
+                }
3915
+            }
3916
+
3917
+            return this;
3918
+        }
3919
+    }
3920
+
3921
+
3922
+    /**
3923
+     * Updates the state of the buttons when the contents or the selections on the tree change.
3924
+     */
3925
+    private class TreeChangeListener implements TreeModelListener, TreeSelectionListener
3926
+    {
3927
+        private TreeChangeListener()
3928
+        {
3929
+            updateButtons();
3930
+        }
3931
+
3932
+        public void treeNodesChanged(TreeModelEvent event)
3933
+        {
3934
+            updateButtons();
3935
+        }
3936
+
3937
+        public void treeNodesInserted(TreeModelEvent event)
3938
+        {
3939
+            updateButtons();
3940
+        }
3941
+
3942
+        public void treeNodesRemoved(TreeModelEvent event)
3943
+        {
3944
+            updateButtons();
3945
+        }
3946
+
3947
+        public void treeStructureChanged(TreeModelEvent event)
3948
+        {
3949
+            updateButtons();
3950
+        }
3951
+
3952
+        public void valueChanged(TreeSelectionEvent event)
3953
+        {
3954
+            updateButtons();
3955
+        }
3956
+
3957
+        private void updateButtons()
3958
+        {
3959
+            boolean atLimit = limit > 0 && countAddedItems() >= limit;
3960
+
3961
+            int selectedEvidenceCount = 0;
3962
+            TreePath[] paths = caseContentTree.getSelectionPaths();
3963
+            if (paths != null)
3964
+            {
3965
+                for (TreePath path : paths)
3966
+                {
3967
+                    Object last = path.getLastPathComponent();
3968
+                    if (last instanceof EvidenceInfo && !((EvidenceInfo) last).isSaved())
3969
+                    {
3970
+                        selectedEvidenceCount++;
3971
+                    }
3972
+                    else
3973
+                    {
3974
+                        // Not evidence, treat this as having selected nothing.
3975
+                        selectedEvidenceCount = 0;
3976
+                        break;
3977
+                    }
3978
+                }
3979
+            }
3980
+
3981
+            // The old code used to check that there was at least one evidence present, but actually
3982
+            // it's impossible for there to be selected evidence without there being evidence to select.
3983
+            addButton.setEnabled(!atLimit);
3984
+            removeButton.setEnabled(selectedEvidenceCount > 0);
3985
+            editButton.setEnabled(selectedEvidenceCount == 1);
3986
+        }
3987
+    }
3988
+}
3989
Index: data/src/java/com/nuix/investigator/cases/creation/MailStoreInputPane.java
3990
===================================================================
3991
--- data/src/java/com/nuix/investigator/cases/creation/MailStoreInputPane.java	(revision 0)
3992
+++ data/src/java/com/nuix/investigator/cases/creation/MailStoreInputPane.java	(working copy)
3993
@@ -1,4 +1,4 @@
3994
-package com.nuix.investigator.wizard.dialogs;
3995
+package com.nuix.investigator.cases.creation;
3996
 
3997
 import java.awt.GridBagConstraints;
3998
 import java.awt.GridBagLayout;
3999
@@ -52,11 +52,7 @@
4000
      * Resources for the pane.
4001
      */
4002
     private static ResourceGroup resources =
4003
-            ResourceFactory.get("/com/nuix/investigator/wizard/wizard.xml")
4004
-                    .getSubgroup("NewCaseWizard")
4005
-                    .getSubgroup("AddCaseContent")
4006
-                    .getSubgroup("EvidenceInputPane")
4007
-                    .getSubgroup("MailStoreInputPane");
4008
+            ResourceFactory.get("/com/nuix/investigator/cases/cases.xml").getSubgroup("MailStoreInputPane");
4009
 
4010
     /**
4011
      * The combo box for choosing the type of mail store.
4012
@@ -195,7 +191,7 @@
4013
         }
4014
 
4015
         // POP3 requires a password.
4016
-        if ("pop3".equals(protocol) && StringUtils.isEmpty(password))
4017
+        if ("pop3".equals(protocol.protocolName) && StringUtils.isEmpty(password))
4018
         {
4019
             // USABILITY: Different error message for this?
4020
             new DialogBuilder(this, resources).error("FieldsNotComplete");
4021
 
4022
Property changes on: data/src/java/com/nuix/investigator/cases/creation/MailStoreInputPane.java
4023
___________________________________________________________________
4024
Name: svn:executable
4025
   + *
4026
Name: svn:keywords
4027
   + Author Date Id Revision
4028
Name: svn:eol-style
4029
   + native
4030
 
4031
Index: data/src/java/com/nuix/investigator/cases/creation/EvidenceInputPane.java
4032
===================================================================
4033
--- data/src/java/com/nuix/investigator/cases/creation/EvidenceInputPane.java	(revision 0)
4034
+++ data/src/java/com/nuix/investigator/cases/creation/EvidenceInputPane.java	(working copy)
4035
@@ -1,4 +1,4 @@
4036
-package com.nuix.investigator.wizard.dialogs;
4037
+package com.nuix.investigator.cases.creation;
4038
 
4039
 import java.awt.Dimension;
4040
 import java.awt.FlowLayout;
4041
@@ -11,6 +11,7 @@
4042
 
4043
 import javax.swing.DefaultListModel;
4044
 import javax.swing.JButton;
4045
+import javax.swing.JComponent;
4046
 import javax.swing.JFileChooser;
4047
 import javax.swing.JLabel;
4048
 import javax.swing.JList;
4049
@@ -20,30 +21,29 @@
4050
 import javax.swing.JTextArea;
4051
 import javax.swing.JTextField;
4052
 import javax.swing.JToggleButton;
4053
-import javax.swing.JComponent;
4054
 import javax.swing.SwingUtilities;
4055
+import javax.swing.event.ListDataEvent;
4056
+import javax.swing.event.ListDataListener;
4057
 import javax.swing.event.ListSelectionEvent;
4058
 import javax.swing.event.ListSelectionListener;
4059
 import javax.swing.event.PopupMenuEvent;
4060
 import javax.swing.event.PopupMenuListener;
4061
-import javax.swing.event.ListDataListener;
4062
-import javax.swing.event.ListDataEvent;
4063
 
4064
 import com.nuix.data.EvidenceInfo;
4065
 import com.nuix.data.email.DefaultImapPopDataFactory;
4066
+import com.nuix.investigator.options.global.GlobalPreferences;
4067
+import com.nuix.log.Channel;
4068
+import com.nuix.log.ChannelManager;
4069
 import com.nuix.product.Licence;
4070
 import com.nuix.product.LicencingException;
4071
-import com.nuix.resources.ResourceGroup;
4072
 import com.nuix.resources.ResourceFactory;
4073
+import com.nuix.resources.ResourceGroup;
4074
 import com.nuix.swing.actions.BaseAction;
4075
-import com.nuix.swing.builders.JPopupMenuBuilder;
4076
 import com.nuix.swing.builders.DialogBuilder;
4077
+import com.nuix.swing.builders.JPopupMenuBuilder;
4078
 import com.nuix.swing.filechooser.JFileChooserFactory;
4079
 import com.nuix.swing.widgets.ValidatingOptionPane;
4080
 import com.nuix.util.StringUtils;
4081
-import com.nuix.investigator.options.global.GlobalPreferences;
4082
-import com.nuix.log.Channel;
4083
-import com.nuix.log.ChannelManager;
4084
 
4085
 /**
4086
  * {@link JPanel} that shows a dialog box for the selection 
4087
@@ -72,9 +72,7 @@
4088
      * Resources for the pane.
4089
      */
4090
     private static ResourceGroup resources =
4091
-            ResourceFactory.get("/com/nuix/investigator/wizard/wizard.xml")
4092
-                    .getSubgroup("NewCaseWizard")
4093
-                    .getSubgroup("AddCaseContent")
4094
+            ResourceFactory.get("/com/nuix/investigator/cases/cases.xml")
4095
                     .getSubgroup("EvidenceInputPane");
4096
 
4097
     /**
4098
 
4099
Property changes on: data/src/java/com/nuix/investigator/cases/creation/EvidenceInputPane.java
4100
___________________________________________________________________
4101
Name: svn:executable
4102
   + *
4103
Name: svn:keywords
4104
   + Author Date Id Revision
4105
Name: svn:eol-style
4106
   + native
4107
 
4108
Index: data/src/java/com/nuix/investigator/cases/creation/NewCaseModel.java
4109
===================================================================
4110
--- data/src/java/com/nuix/investigator/cases/creation/NewCaseModel.java	(revision 2511)
4111
+++ data/src/java/com/nuix/investigator/cases/creation/NewCaseModel.java	(working copy)
4112
@@ -1,23 +1,17 @@
4113
-package com.nuix.investigator.wizard;
4114
+package com.nuix.investigator.cases.creation;
4115
 
4116
 import java.io.File;
4117
 import java.util.prefs.Preferences;
4118
-import java.util.List;
4119
 
4120
-import com.nuix.swing.wizard.AbstractWizardModel;
4121
-import com.nuix.data.EvidenceInfo;
4122
 import com.nuix.data.DataProcessingSettings;
4123
 import com.nuix.investigator.cases.CaseEvidenceSettings;
4124
 
4125
 /**
4126
- * A model for the New Case wizard.
4127
+ * A model for creating a new case, created by a {@link NewCasePane}.
4128
  */
4129
-public class NewCaseWizardModel extends AbstractWizardModel
4130
+public class NewCaseModel
4131
 {
4132
     //////////////////////////////////////////////////////////////////////////////////////
4133
-    // Constants
4134
-
4135
-    //////////////////////////////////////////////////////////////////////////////////////
4136
     // Fields
4137
 
4138
     /**
4139
@@ -46,11 +40,6 @@
4140
     private String caseInvestigator;
4141
 
4142
     /**
4143
-     * The content which will be added to the case.
4144
-     */
4145
-    private List<EvidenceInfo> caseContents;
4146
-
4147
-    /**
4148
      * Settings for creating the case evidence.
4149
      */
4150
     private CaseEvidenceSettings caseEvidenceSettings;
4151
@@ -71,7 +60,7 @@
4152
     /**
4153
      * Creates the wizard model.
4154
      */
4155
-    public NewCaseWizardModel()
4156
+    public NewCaseModel()
4157
     {
4158
         // Set from preferences.
4159
         prefs = Preferences.userRoot().node("/com/nuix/investigator/wizard");
4160
@@ -179,24 +168,6 @@
4161
     }
4162
 
4163
     /**
4164
-     * Gets the content which will be added to the case.
4165
-     * @return the content which will be added to the case.
4166
-     */
4167
-    public List<EvidenceInfo> getCaseContents()
4168
-    {
4169
-        return caseContents;
4170
-    }
4171
-
4172
-    /**
4173
-     * Sets the content which will be added to the case.
4174
-     * @param caseContents the content which will be added to the case.
4175
-     */
4176
-    public void setCaseContents(List<EvidenceInfo> caseContents)
4177
-    {
4178
-        this.caseContents = caseContents;
4179
-    }
4180
-
4181
-    /**
4182
      * Gets the case evidence settings.
4183
      *
4184
      * @return the case evidence settings.
4185
@@ -217,14 +188,11 @@
4186
     }
4187
 
4188
     /**
4189
-     * Sets if the wizard was completed.
4190
-     *
4191
-     * @param completed <code>true</code> if the wizard was completed, <code>false</code> otherwise.
4192
+     * Saves the preferences in the model which are useful for the next time the user
4193
+     * creates a case.
4194
      */
4195
-    public void setCompleted(boolean completed)
4196
+    public void savePrefs()
4197
     {
4198
-        super.setCompleted(completed);
4199
-
4200
         caseEvidenceSettings.storeToPreferences(prefs.node("caseEvidenceSettings"));
4201
         processingSettings.storeToPreferences(prefs.node("processingSettings"));
4202
     }
4203
 
4204
Property changes on: data/src/java/com/nuix/investigator/cases/creation/NewCaseModel.java
4205
___________________________________________________________________
4206
Name: svn:executable
4207
   + *
4208
Name: svn:keywords
4209
   + Author Date Id Revision
4210
Name: svn:eol-style
4211
   + native
4212
 
4213
Index: data/src/java/com/nuix/investigator/cases/creation/NewCasePane.java
4214
===================================================================
4215
--- data/src/java/com/nuix/investigator/cases/creation/NewCasePane.java	(revision 0)
4216
+++ data/src/java/com/nuix/investigator/cases/creation/NewCasePane.java	(revision 0)
4217
@@ -0,0 +1,145 @@
4218
+package com.nuix.investigator.cases.creation;
4219
+
4220
+import java.awt.GridBagConstraints;
4221
+import java.awt.GridBagLayout;
4222
+import java.beans.PropertyChangeListener;
4223
+import java.beans.PropertyChangeEvent;
4224
+
4225
+import javax.swing.BorderFactory;
4226
+import javax.swing.JComponent;
4227
+import javax.swing.JPanel;
4228
+
4229
+import com.nuix.resources.ResourceFactory;
4230
+import com.nuix.resources.ResourceGroup;
4231
+import com.nuix.swing.widgets.ValidatingOptionPane;
4232
+
4233
+/**
4234
+ * Pane for creating a new case.
4235
+ */
4236
+public class NewCasePane extends ValidatingOptionPane
4237
+{
4238
+    //////////////////////////////////////////////////////////////////////////////////////
4239
+    // Fields
4240
+
4241
+    /**
4242
+     * The resources for the panel.
4243
+     */
4244
+    private ResourceGroup resources =
4245
+        ResourceFactory.get("/com/nuix/investigator/cases/cases.xml").
4246
+                getSubgroup("NewCasePane");
4247
+
4248
+    /**
4249
+     * Panel for entering settings for the case itself.
4250
+     */
4251
+    private CaseSettingsPanel caseSettingsPanel;
4252
+
4253
+    /**
4254
+     * Panel for entering text processing settings.
4255
+     */
4256
+    private TextProcessingSettingsPanel textProcessingSettingsPanel;
4257
+
4258
+    /**
4259
+     * Panel for entering other processing settings.
4260
+     */
4261
+    private OtherProcessingSettingsPanel otherProcessingSettingsPanel;
4262
+
4263
+    //////////////////////////////////////////////////////////////////////////////////////
4264
+    // Methods
4265
+
4266
+    /**
4267
+     * Gets the title of the dialog which will be displayed.
4268
+     *
4269
+     * @return the title.
4270
+     */
4271
+    protected String getTitle()
4272
+    {
4273
+        return resources.getString("Title");
4274
+    }
4275
+
4276
+    /**
4277
+     * Builds the components where the user can input data.
4278
+     *
4279
+     * @return the input panel.
4280
+     */
4281
+    protected JComponent buildInputPanel()
4282
+    {
4283
+        JPanel inputPanel = new JPanel(new GridBagLayout());
4284
+
4285
+        caseSettingsPanel = new CaseSettingsPanel();
4286
+        caseSettingsPanel.setBorder(
4287
+                BorderFactory.createTitledBorder(resources.getString("CaseSettings")));
4288
+
4289
+        textProcessingSettingsPanel = new TextProcessingSettingsPanel();
4290
+        textProcessingSettingsPanel.setBorder(
4291
+                BorderFactory.createTitledBorder(resources.getString("TextProcessingSettings")));
4292
+
4293
+        otherProcessingSettingsPanel = new OtherProcessingSettingsPanel();
4294
+        otherProcessingSettingsPanel.setBorder(
4295
+                BorderFactory.createTitledBorder(resources.getString("OtherProcessingSettings")));
4296
+
4297
+        // Disable the processing settings panels if the case is not a simple case.
4298
+        caseSettingsPanel.addPropertyChangeListener(
4299
+                CaseSettingsPanel.COMPOUND_PROPERTY,
4300
+                new PropertyChangeListener()
4301
+                {
4302
+                    public void propertyChange(PropertyChangeEvent event)
4303
+                    {
4304
+                        boolean simpleCase = !((Boolean) event.getNewValue());
4305
+                        textProcessingSettingsPanel.setEnabled(simpleCase);
4306
+                        otherProcessingSettingsPanel.setEnabled(simpleCase);
4307
+                    }
4308
+                });
4309
+
4310
+        GridBagConstraints c = new GridBagConstraints();
4311
+        c.anchor = GridBagConstraints.PAGE_START;
4312
+        c.weightx = 1.0;
4313
+        c.fill = GridBagConstraints.BOTH;
4314
+        c.gridheight = 2;
4315
+        inputPanel.add(caseSettingsPanel, c);
4316
+        c.gridheight = 1;
4317
+        c.gridwidth = GridBagConstraints.REMAINDER;
4318
+        inputPanel.add(textProcessingSettingsPanel, c);
4319
+        inputPanel.add(otherProcessingSettingsPanel, c);
4320
+        return inputPanel;
4321
+    }
4322
+
4323
+
4324
+    /**
4325
+     * Requests that the initial value be selected, which will set
4326
+     * focus to the initial value.
4327
+     */
4328
+    public void selectInitialValue()
4329
+    {
4330
+        caseSettingsPanel.selectInitialValue();
4331
+    }
4332
+
4333
+    /**
4334
+     * Validates the input and performs the result of the dialog.
4335
+     *
4336
+     * @return <code>true</code> on success.
4337
+     */
4338
+    protected boolean validateAndPerform()
4339
+    {
4340
+        return caseSettingsPanel.validateInput();
4341
+    }
4342
+
4343
+    /**
4344
+     * Creates a model holding the settings in the pane.  The result of calling
4345
+     * this method will only be defined if the user has confirmed the dialog and their
4346
+     * input was determined to be valid.
4347
+     *
4348
+     * @return the new case model.
4349
+     */
4350
+    public NewCaseModel createModel()
4351
+    {
4352
+        NewCaseModel model = new NewCaseModel();
4353
+        caseSettingsPanel.exportModel(model);
4354
+        textProcessingSettingsPanel.exportModel(model);
4355
+        otherProcessingSettingsPanel.exportModel(model);
4356
+
4357
+        // Safe to save the preferences at this point.
4358
+        model.savePrefs();
4359
+
4360
+        return model;
4361
+    }
4362
+}
4363
Index: data/src/java/com/nuix/investigator/cases/creation/CaseSettingsPanel.java
4364
===================================================================
4365
--- data/src/java/com/nuix/investigator/cases/creation/CaseSettingsPanel.java	(revision 0)
4366
+++ data/src/java/com/nuix/investigator/cases/creation/CaseSettingsPanel.java	(revision 0)
4367
@@ -0,0 +1,291 @@
4368
+package com.nuix.investigator.cases.creation;
4369
+
4370
+import java.awt.GridBagConstraints;
4371
+import java.awt.GridBagLayout;
4372
+import java.awt.GridLayout;
4373
+import java.awt.Insets;
4374
+import java.awt.event.ItemListener;
4375
+import java.awt.event.ItemEvent;
4376
+import java.io.File;
4377
+import java.text.MessageFormat;
4378
+
4379
+import javax.swing.ButtonGroup;
4380
+import javax.swing.JLabel;
4381
+import javax.swing.JPanel;
4382
+import javax.swing.JRadioButton;
4383
+import javax.swing.JTextField;
4384
+import javax.swing.event.DocumentEvent;
4385
+import javax.swing.event.DocumentListener;
4386
+import javax.swing.text.JTextComponent;
4387
+
4388
+import com.nuix.investigator.cases.CaseFileView;
4389
+import com.nuix.investigator.options.global.GlobalPreferences;
4390
+import com.nuix.os.user.NativeUserUtils;
4391
+import com.nuix.product.Licence;
4392
+import com.nuix.resources.ResourceFactory;
4393
+import com.nuix.resources.ResourceGroup;
4394
+import com.nuix.swing.builders.DialogBuilder;
4395
+import com.nuix.swing.widgets.FileChooserField;
4396
+import com.nuix.util.FileUtils;
4397
+import com.nuix.util.StringUtils;
4398
+
4399
+/**
4400
+ * Panel for entering the case settings.
4401
+ */
4402
+public class CaseSettingsPanel extends JPanel
4403
+{
4404
+    //////////////////////////////////////////////////////////////////////////////////////
4405
+    // Constants
4406
+
4407
+    /**
4408
+     * The property to listen for changes in, to track the compound case checkbox.
4409
+     */
4410
+    static final String COMPOUND_PROPERTY = "compound";
4411
+
4412
+    //////////////////////////////////////////////////////////////////////////////////////
4413
+    // Fields
4414
+
4415
+    /**
4416
+     * The resources for the panel.
4417
+     */
4418
+    private ResourceGroup resources =
4419
+        ResourceFactory.get("/com/nuix/investigator/cases/cases.xml").
4420
+                getSubgroup("CaseSettingsPanel");
4421
+
4422
+    /**
4423
+     * The field which will contain the selected directory.
4424
+     */
4425
+    private FileChooserField directoryField;
4426
+
4427
+    /**
4428
+     * The field containing the case name.
4429
+     */
4430
+    private JTextComponent nameField;
4431
+
4432
+    /**
4433
+     * The field containing the case investigator.
4434
+     */
4435
+    private JTextComponent investigatorField;
4436
+
4437
+    /**
4438
+     * The field containing the case description.
4439
+     */
4440
+    private JTextComponent descriptionField;
4441
+
4442
+    /**
4443
+     * Radio button indicating that the case will be compound.
4444
+     */
4445
+    private JRadioButton compoundButton;
4446
+
4447
+    //////////////////////////////////////////////////////////////////////////////////////
4448
+    // Constructors
4449
+
4450
+    /**
4451
+     * Constructs the panel.
4452
+     */
4453
+    public CaseSettingsPanel()
4454
+    {
4455
+        JPanel panel = new JPanel(new GridBagLayout());
4456
+
4457
+        GridBagConstraints c1 = new GridBagConstraints();
4458
+        c1.insets = new Insets(4, 4, 4, 4);
4459
+        c1.anchor = GridBagConstraints.LINE_START;
4460
+        GridBagConstraints c2 = (GridBagConstraints) c1.clone();
4461
+        c2.weightx = 1.0;
4462
+        c2.fill = GridBagConstraints.HORIZONTAL;
4463
+        c2.gridwidth = GridBagConstraints.REMAINDER;
4464
+
4465
+        // Case name
4466
+        panel.add(new JLabel(resources.getString("Name")), c1);
4467
+        nameField = new JTextField(20);
4468
+        panel.add(nameField, c2);
4469
+
4470
+        // Case directory
4471
+        panel.add(new JLabel(resources.getString("Directory")), c1);
4472
+        directoryField = new FileChooserField(GlobalPreferences.CASE_DIRECTORY_KEY,
4473
+                                              FileChooserField.FILES_ONLY);
4474
+        //directoryField.setFileChecker(new NewDirectoryChecker(false));
4475
+        directoryField.setFileView(new CaseFileView());
4476
+        panel.add(directoryField, c2);
4477
+        syncDirectoryFromName();
4478
+
4479
+        // Case investigator
4480
+        panel.add(new JLabel(resources.getString("Investigator")), c1);
4481
+        investigatorField = new JTextField();
4482
+        panel.add(investigatorField, c2);
4483
+
4484
+        // Set the investigator's name automatically.
4485
+        // XXX: Later, get this from the user manager in the case?
4486
+        String investigator = NativeUserUtils.getInstance().getLongUserName();
4487
+        if (StringUtils.isEmpty(investigator))
4488
+        {
4489
+            investigator = NativeUserUtils.getInstance().getShortUserName();
4490
+        }
4491
+        investigatorField.setText(investigator);
4492
+
4493
+        // Case description
4494
+        panel.add(new JLabel(resources.getString("Description")), c1);
4495
+        descriptionField = new JTextField();
4496
+        panel.add(descriptionField, c2);
4497
+
4498
+        // Case type.  Disable compound case creation if the licence says so.
4499
+        if (Licence.getInstance().isEnabled("compound-cases"))
4500
+        {
4501
+            panel.add(new JLabel(resources.getString("Type")), c1);
4502
+            JRadioButton simpleButton = new JRadioButton(resources.getString("SimpleCase"), true);
4503
+            compoundButton = new JRadioButton(resources.getString("CompoundCase"));
4504
+            JPanel typeButtonPanel = new JPanel(new GridLayout(2, 1));
4505
+            ButtonGroup typeButtonGroup = new ButtonGroup();
4506
+            typeButtonPanel.add(simpleButton);
4507
+            typeButtonGroup.add(simpleButton);
4508
+            typeButtonPanel.add(compoundButton);
4509
+            typeButtonGroup.add(compoundButton);
4510
+            panel.add(typeButtonPanel, c2);
4511
+
4512
+            // Changes to the compound button get exposed as a property change event for the
4513
+            // property "compound".
4514
+            compoundButton.addItemListener(new ItemListener()
4515
+            {
4516
+                public void itemStateChanged(ItemEvent event)
4517
+                {
4518
+                    boolean newValue = event.getStateChange() == ItemEvent.SELECTED;
4519
+                    firePropertyChange(COMPOUND_PROPERTY, !newValue, newValue);
4520
+                }
4521
+            });
4522
+        }
4523
+
4524
+        // Auto update the name when the user specifies the directory.
4525
+        nameField.getDocument().addDocumentListener(new DocumentListener()
4526
+        {
4527
+            public void insertUpdate(DocumentEvent event)
4528
+            {
4529
+                syncDirectoryFromName();
4530
+            }
4531
+
4532
+            public void removeUpdate(DocumentEvent event)
4533
+            {
4534
+                syncDirectoryFromName();
4535
+            }
4536
+
4537
+            public void changedUpdate(DocumentEvent event)
4538
+            {
4539
+                syncDirectoryFromName();
4540
+            }
4541
+        });
4542
+
4543
+        // Set the default name.
4544
+        nameField.setText(createDefaultName());
4545
+
4546
+        // XXX: Turn off the automatic name updating if the user changes the file themselves?
4547
+        //      But how do we know it was the user?
4548
+
4549
+        // I know there is only one component here, but this helps it keep the same
4550
+        // proportions as the ProcessingSettingsPanel, which does the same layout.
4551
+        c2.fill = GridBagConstraints.BOTH;
4552
+        add(panel, c2);
4553
+        c2.weighty = 1.0;
4554
+        add(new JPanel(), c2); // Filler
4555
+    }
4556
+
4557
+    //////////////////////////////////////////////////////////////////////////////////////
4558
+    // Methods
4559
+
4560
+    /**
4561
+     * Copies data from the user interface into the model.
4562
+     *
4563
+     * @param model the model.
4564
+     */
4565
+    public void exportModel(NewCaseModel model)
4566
+    {
4567
+        model.setCaseDirectory(directoryField.getFile());
4568
+        model.setCaseName(nameField.getText());
4569
+        model.setCaseInvestigator(investigatorField.getText());
4570
+        model.setCaseDescription(descriptionField.getText());
4571
+        model.setCompound(compoundButton != null && compoundButton.isSelected());
4572
+    }
4573
+
4574
+    /**
4575
+     * Creates the default name to use for the case.  Will increment until it finds
4576
+     * a name which isn't already in the case directory.
4577
+     *
4578
+     * @return the default name.
4579
+     */
4580
+    private String createDefaultName()
4581
+    {
4582
+        MessageFormat format = new MessageFormat(resources.getString("DefaultNameFormat"));
4583
+        for (int i = 1; ; i++)
4584
+        {
4585
+            String name = format.format(new Object[] { i });
4586
+            if (!new File(directoryField.getInitialDirectory(), name).exists())
4587
+            {
4588
+                return name;
4589
+            }
4590
+        }
4591
+    }
4592
+
4593
+    /**
4594
+     * Copies the name into the directory field, with the appropriate parent directory.
4595
+     */
4596
+    private void syncDirectoryFromName()
4597
+    {
4598
+        directoryField.setFile(new File(directoryField.getInitialDirectory(),
4599
+                                        FileUtils.safeFileName(nameField.getText())));
4600
+    }
4601
+
4602
+    /**
4603
+     * Requests that the initial value be selected, which will set
4604
+     * focus to the initial value.
4605
+     */
4606
+    public void selectInitialValue()
4607
+    {
4608
+        nameField.requestFocusInWindow();
4609
+        nameField.selectAll();
4610
+    }
4611
+
4612
+    /**
4613
+     * Validates the input.
4614
+     *
4615
+     * @return <code>true</code> on success.
4616
+     */
4617
+    protected boolean validateInput()
4618
+    {
4619
+        if (directoryField.getFile() == null)
4620
+        {
4621
+            new DialogBuilder(getRootPane(), resources).error("MustEnterDirectory");
4622
+            return false;
4623
+        }
4624
+        else if (directoryField.getFile().getParentFile() == null)
4625
+        {
4626
+            new DialogBuilder(getRootPane(), resources).error("RootNotPossible");
4627
+            return false;
4628
+        }
4629
+        else if (!directoryField.getFile().getParentFile().exists())
4630
+        {
4631
+            new DialogBuilder(getRootPane(), resources).error("NoParentDirectory");
4632
+            return false;
4633
+        }
4634
+        else if (!directoryField.getFile().exists())
4635
+        {
4636
+            return true;
4637
+        }
4638
+        else if (!directoryField.getFile().isDirectory())
4639
+        {
4640
+            new DialogBuilder(getRootPane(), resources).error("NotADirectory");
4641
+            return false;
4642
+        }
4643
+        else if (directoryField.getFile().list().length > 0)
4644
+        {
4645
+            new DialogBuilder(getRootPane(), resources).error("DirectoryNotEmpty");
4646
+            return false;
4647
+        }
4648
+
4649
+        if (StringUtils.isEmpty(nameField.getText()) ||
4650
+            StringUtils.isEmpty(investigatorField.getText()))
4651
+        {
4652
+            new DialogBuilder(getRootPane(), resources).error("FieldsNotComplete");
4653
+            return false;
4654
+        }
4655
+
4656
+        return true;
4657
+    }
4658
+}
4659
Index: data/src/java/com/nuix/investigator/actions/actions.xml
4660
===================================================================
4661
--- data/src/java/com/nuix/investigator/actions/actions.xml	(revision 2561)
4662
+++ data/src/java/com/nuix/investigator/actions/actions.xml	(working copy)
4663
@@ -111,6 +111,13 @@
4664
         <Group name="AddCaseEvidence">
4665
             <String name="name" value="Add Case Evidence..."/>
4666
             <String name="mnemonic" value="a"/>
4667
+
4668
+            <String name="TabsWillBeClosed.Title" value="Tabs will be closed"/>
4669
+            <String name="TabsWillBeClosed.Text" value="&lt;html&gt;
4670
+                Before adding new evidence, all open tabs need to be closed.
4671
+                &lt;br&gt;
4672
+                Is it okay to proceed?
4673
+                &lt;/html&gt;"/>
4674
         </Group>
4675
 
4676
         <Group name="ClearRecentCases">
4677
Index: data/src/java/com/nuix/investigator/actions/file/NewCaseAction.java
4678
===================================================================
4679
--- data/src/java/com/nuix/investigator/actions/file/NewCaseAction.java	(revision 2561)
4680
+++ data/src/java/com/nuix/investigator/actions/file/NewCaseAction.java	(working copy)
4681
@@ -2,29 +2,24 @@
4682
 
4683
 import java.io.File;
4684
 import java.io.IOException;
4685
-import java.util.List;
4686
 
4687
 import javax.swing.JOptionPane;
4688
 
4689
 import com.nuix.investigator.MainWindow;
4690
-import com.nuix.investigator.images.ImageFactory;
4691
 import com.nuix.investigator.actions.MainWindowAction;
4692
-import com.nuix.investigator.cases.RecentCaseModel;
4693
 import com.nuix.investigator.cases.Case;
4694
-import com.nuix.investigator.cases.CaseFactory;
4695
 import com.nuix.investigator.cases.CaseEvidence;
4696
-import com.nuix.investigator.wizard.NewCaseWizard;
4697
-import com.nuix.investigator.wizard.NewCaseWizardModel;
4698
+import com.nuix.investigator.cases.CaseFactory;
4699
+import com.nuix.investigator.cases.RecentCaseModel;
4700
+import com.nuix.investigator.images.ImageFactory;
4701
+import com.nuix.investigator.cases.creation.NewCaseModel;
4702
+import com.nuix.investigator.cases.creation.NewCasePane;
4703
+import com.nuix.log.Channel;
4704
+import com.nuix.log.ChannelManager;
4705
 import com.nuix.resources.ResourceGroup;
4706
-import com.nuix.processor.PersistentProcessingQueue;
4707
-import com.nuix.data.EvidenceInfo;
4708
-import com.nuix.data.DefaultDataFactory;
4709
-import com.nuix.data.Environment;
4710
 import com.nuix.swing.actions.BaseRunnable;
4711
 import com.nuix.swing.actions.ExecutionStrategy;
4712
 import com.nuix.swing.builders.DialogBuilder;
4713
-import com.nuix.log.Channel;
4714
-import com.nuix.log.ChannelManager;
4715
 
4716
 /**
4717
  * Action to create a new case.
4718
@@ -96,16 +91,10 @@
4719
             }
4720
         }
4721
 
4722
-        NewCaseWizard wizard = new NewCaseWizard(mainWindow);
4723
-        wizard.pack();
4724
-        wizard.setLocationRelativeTo(mainWindow);
4725
-
4726
-        // This will block until the wizard is completed or cancelled.
4727
-        wizard.setVisible(true);
4728
-
4729
-        NewCaseWizardModel model = (NewCaseWizardModel) wizard.getModel();
4730
-        if (model.isCompleted())
4731
+        NewCasePane newCasePane = new NewCasePane();
4732
+        if (newCasePane.showDialog(mainWindow))
4733
         {
4734
+            NewCaseModel model = newCasePane.createModel();
4735
             new CaseCreatingRunner(model).run();
4736
         }
4737
     }
4738
@@ -121,14 +110,14 @@
4739
         /**
4740
          * The new case wizard model.
4741
          */
4742
-        private NewCaseWizardModel model;
4743
+        private NewCaseModel model;
4744
 
4745
         /**
4746
          * Constructs the runner.
4747
          *
4748
          * @param model the new case wizard model.
4749
          */
4750
-        private CaseCreatingRunner(NewCaseWizardModel model)
4751
+        private CaseCreatingRunner(NewCaseModel model)
4752
         {
4753
             super(NewCaseAction.this.getOwner());
4754
             setExecutionStrategy(ExecutionStrategy.NEW_THREAD_ASYNCHRONOUS);
4755
@@ -153,30 +142,18 @@
4756
                 newCase.getMetadata().setDescription(model.getCaseDescription());
4757
                 newCase.getMetadata().setInvestigator(model.getCaseInvestigator());
4758
 
4759
-                // If this is a simple case we have to set up the queue which will
4760
-                // load evidence in the same directory as the case.
4761
+                // If this is a simple case we have to set up the processing settings and also
4762
+                // create the empty evidence.
4763
                 if (!model.isCompound())
4764
                 {
4765
                     CaseEvidence evidence = CaseFactory.getInstance()
4766
                         .createEvidence(newCase.getLocation(), model.getCaseEvidenceSettings());
4767
                     newCase.addEvidence(evidence);
4768
 
4769
-                    String persistentDirName = "Stores/PersistentQueue";
4770
-                    File persistentDir = new File(evidence.getLocation(), persistentDirName);
4771
+                    File persistentDir = new File(evidence.getLocation(), "Stores/PersistentQueue");
4772
+
4773
                     // Initialise the processing settings.
4774
                     model.getProcessingSettings().saveToDirectory(persistentDir);
4775
-
4776
-                    // Initialise the queue first.  The factory here doesn't matter because we're
4777
-                    // just using this to drop the queue to disk.
4778
-                    PersistentProcessingQueue queue =
4779
-                        new PersistentProcessingQueue(persistentDir,
4780
-                                                      new DefaultDataFactory(new Environment()));
4781
-                    List<EvidenceInfo> caseContents = model.getCaseContents();
4782
-                    for (final EvidenceInfo newVar : caseContents)
4783
-                    {
4784
-                        queue.addDataRoot(newVar.saveToFile(evidence));
4785
-                    }
4786
-                    queue.cleanup();
4787
                 }
4788
 
4789
                 // Write the initial case file.
4790
Index: data/src/java/com/nuix/investigator/actions/file/AddCaseEvidenceAction.java
4791
===================================================================
4792
--- data/src/java/com/nuix/investigator/actions/file/AddCaseEvidenceAction.java	(revision 2561)
4793
+++ data/src/java/com/nuix/investigator/actions/file/AddCaseEvidenceAction.java	(working copy)
4794
@@ -1,12 +1,17 @@
4795
 package com.nuix.investigator.actions.file;
4796
 
4797
+import java.beans.PropertyChangeEvent;
4798
 import java.beans.PropertyChangeListener;
4799
-import java.beans.PropertyChangeEvent;
4800
 
4801
+import javax.swing.JOptionPane;
4802
+
4803
+import com.nuix.investigator.MainWindow;
4804
 import com.nuix.investigator.actions.MainWindowAction;
4805
-import com.nuix.investigator.MainWindow;
4806
+import com.nuix.investigator.cases.Case;
4807
 import com.nuix.investigator.cases.ModifyCaseEvidencePane;
4808
-import com.nuix.investigator.cases.Case;
4809
+import com.nuix.investigator.cases.creation.AddLoadableEvidencePane;
4810
+import com.nuix.product.Licence;
4811
+import com.nuix.resources.ResourceGroup;
4812
 
4813
 /**
4814
  * Adds evidence to a case.
4815
@@ -24,6 +29,11 @@
4816
     //////////////////////////////////////////////////////////////////////////////////////
4817
     // Fields
4818
 
4819
+    /**
4820
+     * The resources for the action.
4821
+     */
4822
+    private ResourceGroup resources = getResourceSubgroup("AddCaseEvidence");
4823
+
4824
     //////////////////////////////////////////////////////////////////////////////////////
4825
     // Constructors
4826
 
4827
@@ -57,7 +67,36 @@
4828
     public void execute() throws Exception
4829
     {
4830
         MainWindow mainWindow = getMainWindow();
4831
-        new ModifyCaseEvidencePane(mainWindow.getCurrentCase()).showDialog(mainWindow);
4832
+        Case currentCase = mainWindow.getCurrentCase();
4833
+        if (currentCase.isCompound())
4834
+        {
4835
+            new ModifyCaseEvidencePane(mainWindow.getCurrentCase()).showDialog(mainWindow);
4836
+        }
4837
+        else
4838
+        {
4839
+            boolean ok = true;
4840
+
4841
+            if (mainWindow.getTabPanel().getTabCount() > 0)
4842
+            {
4843
+                if (JOptionPane.showConfirmDialog(mainWindow,
4844
+                                                  resources.getString("TabsWillBeClosed.Text"),
4845
+                                                  resources.getString("TabsWillBeClosed.Title"),
4846
+                                                  JOptionPane.OK_CANCEL_OPTION,
4847
+                                                  JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION)
4848
+                {
4849
+                    mainWindow.getTabPanel().removeAll();
4850
+                }
4851
+                else
4852
+                {
4853
+                    ok = false;
4854
+                }
4855
+            }
4856
+
4857
+            if (ok && new AddLoadableEvidencePane(mainWindow.getCurrentCase()).showDialog(mainWindow))
4858
+            {
4859
+                mainWindow.maybeLoadEvidence();
4860
+            }
4861
+        }
4862
     }
4863
 
4864
     /**
4865
@@ -66,6 +105,10 @@
4866
     private void updateState()
4867
     {
4868
         Case theCase = getMainWindow().getCurrentCase();
4869
-        setEnabled(theCase != null && !theCase.isReadOnly());
4870
+
4871
+        // Enabled if there is a case loaded, it is not read-only, and the case is either simple,
4872
+        // or compound cases are enabled on the user's licence.
4873
+        setEnabled(theCase != null && !theCase.isReadOnly() &&
4874
+                   (!theCase.isCompound() || Licence.getInstance().isEnabled("compound-cases")));
4875
     }
4876
 }
4877
Index: data/src/java/com/nuix/investigator/actions/MainWindowActions.java
4878
===================================================================
4879
--- data/src/java/com/nuix/investigator/actions/MainWindowActions.java	(revision 2561)
4880
+++ data/src/java/com/nuix/investigator/actions/MainWindowActions.java	(working copy)
4881
@@ -197,8 +197,7 @@
4882
         fileMenuBuilder
4883
             .append(new ActionBuilder(actionResources.getSubgroup("OpenCase"), openCaseAction))
4884
             .append(reopenCaseMenu);
4885
-        if (Licence.getInstance().isEnabled("case-creation") &&
4886
-            Licence.getInstance().isEnabled("compound-cases"))
4887
+        if (Licence.getInstance().isEnabled("case-creation"))
4888
         {
4889
             fileMenuBuilder
4890
                 .append(new ActionBuilder(actionResources.getSubgroup("AddCaseEvidence"),