33
33
package org .scijava .ui .swing .widget ;
34
34
35
35
import java .awt .Dimension ;
36
+ import java .awt .dnd .DnDConstants ;
37
+ import java .awt .dnd .DropTarget ;
38
+ import java .awt .dnd .DropTargetAdapter ;
39
+ import java .awt .dnd .DropTargetDragEvent ;
40
+ import java .awt .dnd .DropTargetDropEvent ;
41
+ import java .awt .dnd .DropTargetEvent ;
36
42
import java .awt .event .ActionEvent ;
37
43
import java .awt .event .ActionListener ;
38
44
import java .awt .event .MouseEvent ;
39
45
import java .awt .event .MouseListener ;
40
46
import java .io .File ;
41
47
import java .io .FileFilter ;
48
+ import java .io .IOException ;
49
+ import java .nio .file .Files ;
50
+ import java .util .ArrayList ;
51
+ import java .util .Arrays ;
42
52
import java .util .Collections ;
43
53
import java .util .List ;
54
+ import java .util .TooManyListenersException ;
44
55
45
56
import javax .swing .Box ;
46
57
import javax .swing .DefaultListModel ;
53
64
import net .miginfocom .swing .MigLayout ;
54
65
55
66
import org .scijava .log .LogService ;
67
+ import org .scijava .module .ModuleService ;
56
68
import org .scijava .plugin .Parameter ;
57
69
import org .scijava .plugin .Plugin ;
70
+ import org .scijava .thread .ThreadService ;
58
71
import org .scijava .ui .UIService ;
59
72
import org .scijava .widget .FileListWidget ;
73
+ import org .scijava .widget .FileWidget ;
60
74
import org .scijava .widget .InputWidget ;
61
75
import org .scijava .widget .WidgetModel ;
62
76
@@ -70,13 +84,17 @@ public class SwingFileListWidget extends SwingInputWidget<File[]> implements
70
84
FileListWidget <JPanel >, ActionListener , MouseListener {
71
85
72
86
@ Parameter
73
- private UIService uiService ;
87
+ private LogService logService ;
74
88
75
89
@ Parameter
76
- private LogService logService ;
90
+ private ModuleService moduleService ;
91
+
92
+ @ Parameter
93
+ private ThreadService threadService ;
77
94
78
95
private JList <File > paths ;
79
96
private JButton addFilesButton ;
97
+ private JButton addFolderButton ;
80
98
private JButton removeFilesButton ;
81
99
private JButton clearButton ;
82
100
@@ -107,14 +125,34 @@ public void set(final WidgetModel model) {
107
125
108
126
getComponent ().add (Box .createHorizontalStrut (3 ));
109
127
110
- // GroupLayout buttonLayout = new GroupLayout(getComponent());
111
128
JPanel buttonPanel = new JPanel (new MigLayout ());
112
129
113
- addFilesButton = new JButton ("Add files..." );
130
+ // Set button label dependent on widget style
131
+ String filesLabel = model .isStyle (DIRECTORIES_ONLY ) ? "Add folders..."
132
+ : "Add files..." ;
133
+ addFilesButton = new JButton (filesLabel );
114
134
setToolTip (addFilesButton );
115
135
buttonPanel .add (addFilesButton , "wrap, grow" );
116
136
addFilesButton .addActionListener (this );
117
137
138
+ // Only show folder button if style allows files
139
+ if (!model .isStyle (DIRECTORIES_ONLY )) {
140
+ addFolderButton = new JButton ("Add folder content..." );
141
+ setToolTip (addFolderButton );
142
+ // add TransferHandler to accept dropped folders
143
+ addFolderButton .setTransferHandler (new FolderTransferHandler ());
144
+
145
+ DropTarget dropTarget = addFolderButton .getDropTarget ();
146
+ try {
147
+ dropTarget .addDropTargetListener (new ButtonDropTargetListener ());
148
+ } catch (TooManyListenersException exc ) {
149
+ logService .error ("Error with setting up drop support" , exc );
150
+ }
151
+
152
+ buttonPanel .add (addFolderButton , "wrap, grow" );
153
+ addFolderButton .addActionListener (this );
154
+ }
155
+
118
156
removeFilesButton = new JButton ("Remove selected" );
119
157
setToolTip (removeFilesButton );
120
158
buttonPanel .add (removeFilesButton , "wrap, grow" );
@@ -127,14 +165,6 @@ public void set(final WidgetModel model) {
127
165
128
166
getComponent ().add (buttonPanel );
129
167
130
- /*
131
- getComponent().setLayout(buttonLayout);
132
- buttonLayout.setVerticalGroup(buttonLayout.createSequentialGroup()
133
- .addComponent(addFilesButton)
134
- .addComponent(removeFilesButton)
135
- .addComponent(clearButton));
136
- */
137
-
138
168
refreshWidget ();
139
169
}
140
170
@@ -151,12 +181,12 @@ public boolean supports(final WidgetModel model) {
151
181
public void actionPerformed (final ActionEvent e ) {
152
182
DefaultListModel <File > listModel = //
153
183
(DefaultListModel <File >) paths .getModel ();
154
- List <File > fileList = Collections .list (listModel .elements ());
155
184
156
185
if (e .getSource () == addFilesButton ) {
157
186
// Add new files
158
187
// parse style attribute to allow choosing
159
188
// files and/or directories, and filter files
189
+ List <File > fileList = Collections .list (listModel .elements ());
160
190
final WidgetModel widgetModel = get ();
161
191
final String widgetStyle = widgetModel .getItem ().getWidgetStyle ();
162
192
FileFilter filter = SwingFileWidget .createFileFilter (widgetStyle );
@@ -170,12 +200,16 @@ public void actionPerformed(final ActionEvent e) {
170
200
style = FileListWidget .FILES_ONLY ; // default
171
201
}
172
202
173
- fileList = uiService .chooseFiles (null , fileList , filter , style );
203
+ fileList = ui () .chooseFiles (null , fileList , filter , style );
174
204
if (fileList == null )
175
205
return ;
176
- for (File file : fileList ) {
177
- listModel .addElement (file );
178
- }
206
+ fileList .forEach (file -> listModel .addElement (file ));
207
+ } else if (e .getSource () == addFolderButton ) {
208
+ File folder = ui ().chooseFile (null , FileWidget .DIRECTORY_STYLE );
209
+ if (folder == null )
210
+ return ;
211
+ List <File > fileList = getFilesFromFolder (folder );
212
+ fileList .forEach (file -> listModel .addElement (file ));
179
213
} else if (e .getSource () == removeFilesButton ) {
180
214
// Remove selected files
181
215
List <File > selected = paths .getSelectedValuesList ();
@@ -240,6 +274,27 @@ public void mouseExited(MouseEvent e) {
240
274
// Nothing to do
241
275
}
242
276
277
+ // -- Helper methods --
278
+
279
+ private List <File > getFilesFromFolder (File inputFolder ) {
280
+ // get files in folder and add to listModel
281
+ List <File > fileList = new ArrayList <>();
282
+ final WidgetModel widgetModel = get ();
283
+ final String widgetStyle = widgetModel .getItem ().getWidgetStyle ();
284
+ FileFilter filter = SwingFileWidget .createFileFilter (widgetStyle );
285
+ try {
286
+ fileList = Arrays
287
+ .asList ((Files .walk (inputFolder .toPath ())
288
+ .filter (path -> filter .accept (path .toFile ())))
289
+ .map (path -> path .toFile ())
290
+ .toArray (File []::new ));
291
+ } catch (IOException exc ) {
292
+ logService
293
+ .error ("Error when trying to retrieve file list" , exc );
294
+ }
295
+ return fileList ;
296
+ }
297
+
243
298
// -- Helper classes --
244
299
245
300
private class FileListTransferHandler extends TransferHandler {
@@ -275,4 +330,60 @@ public boolean importData(final TransferHandler.TransferSupport support) {
275
330
return true ;
276
331
}
277
332
}
333
+
334
+ private class FolderTransferHandler extends TransferHandler {
335
+ @ Override
336
+ public boolean canImport (final TransferHandler .TransferSupport support ) {
337
+ return SwingFileWidget .hasFiles (support );
338
+ }
339
+
340
+ @ Override
341
+ public boolean importData (final TransferHandler .TransferSupport support ) {
342
+ // getFiles from support
343
+ final List <File > files = SwingFileWidget .getFiles (support );
344
+ if (files == null || files .size () != 1 )
345
+ return false ;
346
+
347
+ // check if it's a folder
348
+ final File folder = files .get (0 );
349
+ if (!folder .isDirectory ())
350
+ return false ;
351
+
352
+ // get all files matching filter from folder and subfolders
353
+ List <File > fileList = getFilesFromFolder (folder );
354
+
355
+ // add files to model
356
+ DefaultListModel <File > model = //
357
+ (DefaultListModel <File >) paths .getModel ();
358
+ fileList .forEach (file -> model .addElement (file ));
359
+ paths .setModel (model );
360
+ updateModel ();
361
+ return true ;
362
+ }
363
+ }
364
+
365
+ private class ButtonDropTargetListener extends DropTargetAdapter {
366
+
367
+ @ Override
368
+ public void drop (DropTargetDropEvent dtde ) {
369
+ JButton button = (JButton ) dtde .getDropTargetContext ()
370
+ .getComponent ();
371
+ button .getModel ().setPressed (false );
372
+ dtde .acceptDrop (DnDConstants .ACTION_COPY_OR_MOVE );
373
+ }
374
+
375
+ @ Override
376
+ public void dragEnter (DropTargetDragEvent dtde ) {
377
+ JButton button = (JButton ) dtde .getDropTargetContext ()
378
+ .getComponent ();
379
+ button .getModel ().setPressed (true );
380
+ }
381
+
382
+ @ Override
383
+ public void dragExit (DropTargetEvent dte ) {
384
+ JButton button = (JButton ) dte .getDropTargetContext ()
385
+ .getComponent ();
386
+ button .getModel ().setPressed (false );
387
+ }
388
+ }
278
389
}
0 commit comments