Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/classes/com/apple/laf/AquaFileSystemModel.java
38831 views
1
/*
2
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package com.apple.laf;
27
28
import java.beans.*;
29
import java.io.File;
30
import java.util.*;
31
32
import javax.swing.*;
33
import javax.swing.event.ListDataEvent;
34
import javax.swing.filechooser.FileSystemView;
35
import javax.swing.table.AbstractTableModel;
36
37
/**
38
* NavServices-like implementation of a file Table
39
*
40
* Some of it came from BasicDirectoryModel
41
*/
42
class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeListener {
43
private final JTable fFileList;
44
private LoadFilesThread loadThread = null;
45
private Vector<File> files = null;
46
47
JFileChooser filechooser = null;
48
Vector<SortableFile> fileCache = null;
49
Object fileCacheLock;
50
51
Vector<File> directories = null;
52
int fetchID = 0;
53
54
private final boolean fSortAscending[] = {true, true};
55
// private boolean fSortAscending = true;
56
private boolean fSortNames = true;
57
private final String[] fColumnNames;
58
public final static String SORT_BY_CHANGED = "sortByChanged";
59
public final static String SORT_ASCENDING_CHANGED = "sortAscendingChanged";
60
61
public AquaFileSystemModel(final JFileChooser filechooser, final JTable filelist, final String[] colNames) {
62
fileCacheLock = new Object();
63
this.filechooser = filechooser;
64
fFileList = filelist;
65
fColumnNames = colNames;
66
validateFileCache();
67
updateSelectionMode();
68
}
69
70
void updateSelectionMode() {
71
// Save dialog lists can't be multi select, because all we're selecting is the next folder to open
72
final boolean b = filechooser.isMultiSelectionEnabled() && filechooser.getDialogType() != JFileChooser.SAVE_DIALOG;
73
fFileList.setSelectionMode(b ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION : ListSelectionModel.SINGLE_SELECTION);
74
}
75
76
public void propertyChange(final PropertyChangeEvent e) {
77
final String prop = e.getPropertyName();
78
if (prop == JFileChooser.DIRECTORY_CHANGED_PROPERTY || prop == JFileChooser.FILE_VIEW_CHANGED_PROPERTY || prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY || prop == JFileChooser.FILE_HIDING_CHANGED_PROPERTY) {
79
invalidateFileCache();
80
validateFileCache();
81
} else if (prop.equals(JFileChooser.MULTI_SELECTION_ENABLED_CHANGED_PROPERTY)) {
82
updateSelectionMode();
83
} else if (prop == JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY) {
84
invalidateFileCache();
85
validateFileCache();
86
}
87
if (prop == SORT_BY_CHANGED) {// $ Ought to just resort
88
fSortNames = (((Integer)e.getNewValue()).intValue() == 0);
89
invalidateFileCache();
90
validateFileCache();
91
fFileList.repaint();
92
}
93
if (prop == SORT_ASCENDING_CHANGED) {
94
final int sortColumn = (fSortNames ? 0 : 1);
95
fSortAscending[sortColumn] = ((Boolean)e.getNewValue()).booleanValue();
96
invalidateFileCache();
97
validateFileCache();
98
fFileList.repaint();
99
}
100
}
101
102
public void invalidateFileCache() {
103
files = null;
104
directories = null;
105
106
synchronized(fileCacheLock) {
107
if (fileCache != null) {
108
final int lastRow = fileCache.size();
109
fileCache = null;
110
fireTableRowsDeleted(0, lastRow);
111
}
112
}
113
}
114
115
public Vector<File> getDirectories() {
116
if (directories != null) { return directories; }
117
return directories;
118
}
119
120
public Vector<File> getFiles() {
121
if (files != null) { return files; }
122
files = new Vector<File>();
123
directories = new Vector<File>();
124
directories.addElement(filechooser.getFileSystemView().createFileObject(filechooser.getCurrentDirectory(), ".."));
125
126
synchronized(fileCacheLock) {
127
for (int i = 0; i < fileCache.size(); i++) {
128
final SortableFile sf = fileCache.elementAt(i);
129
final File f = sf.fFile;
130
if (filechooser.isTraversable(f)) {
131
directories.addElement(f);
132
} else {
133
files.addElement(f);
134
}
135
}
136
}
137
138
return files;
139
}
140
141
public void runWhenDone(final Runnable runnable){
142
synchronized (fileCacheLock) {
143
if (loadThread != null) {
144
if (loadThread.isAlive()) {
145
loadThread.queuedTasks.add(runnable);
146
return;
147
}
148
}
149
150
SwingUtilities.invokeLater(runnable);
151
}
152
}
153
154
public void validateFileCache() {
155
final File currentDirectory = filechooser.getCurrentDirectory();
156
157
if (currentDirectory == null) {
158
invalidateFileCache();
159
return;
160
}
161
162
if (loadThread != null) {
163
// interrupt
164
loadThread.interrupt();
165
}
166
167
fetchID++;
168
169
// PENDING(jeff) pick the size more sensibly
170
invalidateFileCache();
171
synchronized(fileCacheLock) {
172
fileCache = new Vector<SortableFile>(50);
173
}
174
175
loadThread = new LoadFilesThread(currentDirectory, fetchID);
176
loadThread.start();
177
}
178
179
public int getColumnCount() {
180
return 2;
181
}
182
183
public String getColumnName(final int col) {
184
return fColumnNames[col];
185
}
186
187
public Class<? extends Object> getColumnClass(final int col) {
188
if (col == 0) return File.class;
189
return Date.class;
190
}
191
192
public int getRowCount() {
193
synchronized(fileCacheLock) {
194
if (fileCache != null) {
195
return fileCache.size();
196
}
197
return 0;
198
}
199
}
200
201
// SAK: Part of fix for 3168263. The fileCache contains
202
// SortableFiles, so when finding a file in the list we need to
203
// first create a sortable file.
204
public boolean contains(final File o) {
205
synchronized(fileCacheLock) {
206
if (fileCache != null) {
207
return fileCache.contains(new SortableFile(o));
208
}
209
return false;
210
}
211
}
212
213
public int indexOf(final File o) {
214
synchronized(fileCacheLock) {
215
if (fileCache != null) {
216
final boolean isAscending = fSortNames ? fSortAscending[0] : fSortAscending[1];
217
final int row = fileCache.indexOf(new SortableFile(o));
218
return isAscending ? row : fileCache.size() - row - 1;
219
}
220
return 0;
221
}
222
}
223
224
// AbstractListModel interface
225
public Object getElementAt(final int row) {
226
return getValueAt(row, 0);
227
}
228
229
// AbstractTableModel interface
230
231
public Object getValueAt(int row, final int col) {
232
if (row < 0 || col < 0) return null;
233
final boolean isAscending = fSortNames ? fSortAscending[0] : fSortAscending[1];
234
synchronized(fileCacheLock) {
235
if (fileCache != null) {
236
if (!isAscending) row = fileCache.size() - row - 1;
237
return fileCache.elementAt(row).getValueAt(col);
238
}
239
return null;
240
}
241
}
242
243
// PENDING(jeff) - implement
244
public void intervalAdded(final ListDataEvent e) {
245
}
246
247
// PENDING(jeff) - implement
248
public void intervalRemoved(final ListDataEvent e) {
249
}
250
251
protected void sort(final Vector<Object> v) {
252
if (fSortNames) sSortNames.quickSort(v, 0, v.size() - 1);
253
else sSortDates.quickSort(v, 0, v.size() - 1);
254
}
255
256
// Liberated from the 1.1 SortDemo
257
//
258
// This is a generic version of C.A.R Hoare's Quick Sort
259
// algorithm. This will handle arrays that are already
260
// sorted, and arrays with duplicate keys.<BR>
261
//
262
// If you think of a one dimensional array as going from
263
// the lowest index on the left to the highest index on the right
264
// then the parameters to this function are lowest index or
265
// left and highest index or right. The first time you call
266
// this function it will be with the parameters 0, a.length - 1.
267
//
268
// @param a an integer array
269
// @param lo0 left boundary of array partition
270
// @param hi0 right boundary of array partition
271
abstract class QuickSort {
272
final void quickSort(final Vector<Object> v, final int lo0, final int hi0) {
273
int lo = lo0;
274
int hi = hi0;
275
SortableFile mid;
276
277
if (hi0 > lo0) {
278
// Arbitrarily establishing partition element as the midpoint of
279
// the array.
280
mid = (SortableFile)v.elementAt((lo0 + hi0) / 2);
281
282
// loop through the array until indices cross
283
while (lo <= hi) {
284
// find the first element that is greater than or equal to
285
// the partition element starting from the left Index.
286
//
287
// Nasty to have to cast here. Would it be quicker
288
// to copy the vectors into arrays and sort the arrays?
289
while ((lo < hi0) && lt((SortableFile)v.elementAt(lo), mid)) {
290
++lo;
291
}
292
293
// find an element that is smaller than or equal to
294
// the partition element starting from the right Index.
295
while ((hi > lo0) && lt(mid, (SortableFile)v.elementAt(hi))) {
296
--hi;
297
}
298
299
// if the indexes have not crossed, swap
300
if (lo <= hi) {
301
swap(v, lo, hi);
302
++lo;
303
--hi;
304
}
305
}
306
307
// If the right index has not reached the left side of array
308
// must now sort the left partition.
309
if (lo0 < hi) {
310
quickSort(v, lo0, hi);
311
}
312
313
// If the left index has not reached the right side of array
314
// must now sort the right partition.
315
if (lo < hi0) {
316
quickSort(v, lo, hi0);
317
}
318
319
}
320
}
321
322
private final void swap(final Vector<Object> a, final int i, final int j) {
323
final Object T = a.elementAt(i);
324
a.setElementAt(a.elementAt(j), i);
325
a.setElementAt(T, j);
326
}
327
328
protected abstract boolean lt(SortableFile a, SortableFile b);
329
}
330
331
class QuickSortNames extends QuickSort {
332
protected boolean lt(final SortableFile a, final SortableFile b) {
333
final String aLower = a.fName.toLowerCase();
334
final String bLower = b.fName.toLowerCase();
335
return aLower.compareTo(bLower) < 0;
336
}
337
}
338
339
class QuickSortDates extends QuickSort {
340
protected boolean lt(final SortableFile a, final SortableFile b) {
341
return a.fDateValue < b.fDateValue;
342
}
343
}
344
345
// for speed in sorting, displaying
346
class SortableFile /* extends FileView */{
347
File fFile;
348
String fName;
349
long fDateValue;
350
Date fDate;
351
352
SortableFile(final File f) {
353
fFile = f;
354
fName = fFile.getName();
355
fDateValue = fFile.lastModified();
356
fDate = new Date(fDateValue);
357
}
358
359
public Object getValueAt(final int col) {
360
if (col == 0) return fFile;
361
return fDate;
362
}
363
364
public boolean equals(final Object other) {
365
final SortableFile otherFile = (SortableFile)other;
366
return otherFile.fFile.equals(fFile);
367
}
368
}
369
370
class LoadFilesThread extends Thread {
371
Vector<Runnable> queuedTasks = new Vector<Runnable>();
372
File currentDirectory = null;
373
int fid;
374
375
public LoadFilesThread(final File currentDirectory, final int fid) {
376
super("Aqua L&F File Loading Thread");
377
this.currentDirectory = currentDirectory;
378
this.fid = fid;
379
}
380
381
public void run() {
382
final Vector<DoChangeContents> runnables = new Vector<DoChangeContents>(10);
383
final FileSystemView fileSystem = filechooser.getFileSystemView();
384
385
final File[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled());
386
387
final Vector<Object> acceptsList = new Vector<Object>();
388
389
for (final File element : list) {
390
// Return all files to the file chooser. The UI will disable or enable
391
// the file name if the current filter approves.
392
acceptsList.addElement(new SortableFile(element));
393
}
394
395
// Sort based on settings.
396
sort(acceptsList);
397
398
// Don't separate directories from files
399
Vector<SortableFile> chunk = new Vector<SortableFile>(10);
400
final int listSize = acceptsList.size();
401
// run through list grabbing file/dirs in chunks of ten
402
for (int i = 0; i < listSize;) {
403
SortableFile f;
404
for (int j = 0; j < 10 && i < listSize; j++, i++) {
405
f = (SortableFile)acceptsList.elementAt(i);
406
chunk.addElement(f);
407
}
408
final DoChangeContents runnable = new DoChangeContents(chunk, fid);
409
runnables.addElement(runnable);
410
SwingUtilities.invokeLater(runnable);
411
chunk = new Vector<SortableFile>(10);
412
if (isInterrupted()) {
413
// interrupted, cancel all runnables
414
cancelRunnables(runnables);
415
return;
416
}
417
}
418
419
synchronized (fileCacheLock) {
420
for (final Runnable r : queuedTasks) {
421
SwingUtilities.invokeLater(r);
422
}
423
}
424
}
425
426
public void cancelRunnables(final Vector<DoChangeContents> runnables) {
427
for (int i = 0; i < runnables.size(); i++) {
428
runnables.elementAt(i).cancel();
429
}
430
}
431
}
432
433
class DoChangeContents implements Runnable {
434
private Vector<SortableFile> contentFiles;
435
private boolean doFire = true;
436
private final Object lock = new Object();
437
private final int fid;
438
439
public DoChangeContents(final Vector<SortableFile> files, final int fid) {
440
this.contentFiles = files;
441
this.fid = fid;
442
}
443
444
synchronized void cancel() {
445
synchronized(lock) {
446
doFire = false;
447
}
448
}
449
450
public void run() {
451
if (fetchID == fid) {
452
synchronized(lock) {
453
if (doFire) {
454
synchronized(fileCacheLock) {
455
if (fileCache != null) {
456
for (int i = 0; i < contentFiles.size(); i++) {
457
fileCache.addElement(contentFiles.elementAt(i));
458
fireTableRowsInserted(i, i);
459
}
460
}
461
}
462
}
463
contentFiles = null;
464
directories = null;
465
}
466
}
467
}
468
}
469
470
final QuickSortNames sSortNames = new QuickSortNames();
471
final QuickSortDates sSortDates = new QuickSortDates();
472
}
473
474