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/AquaFileView.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.io.*;
29
import java.util.*;
30
import java.util.Map.Entry;
31
32
import javax.swing.Icon;
33
import javax.swing.filechooser.FileView;
34
35
import com.apple.laf.AquaUtils.RecyclableSingleton;
36
37
class AquaFileView extends FileView {
38
private static final boolean DEBUG = false;
39
40
private static final int UNINITALIZED_LS_INFO = -1;
41
42
// Constants from LaunchServices.h
43
static final int kLSItemInfoIsPlainFile = 0x00000001; /* Not a directory, volume, or symlink*/
44
static final int kLSItemInfoIsPackage = 0x00000002; /* Packaged directory*/
45
static final int kLSItemInfoIsApplication = 0x00000004; /* Single-file or packaged application*/
46
static final int kLSItemInfoIsContainer = 0x00000008; /* Directory (includes packages) or volume*/
47
static final int kLSItemInfoIsAliasFile = 0x00000010; /* Alias file (includes sym links)*/
48
static final int kLSItemInfoIsSymlink = 0x00000020; /* UNIX sym link*/
49
static final int kLSItemInfoIsInvisible = 0x00000040; /* Invisible by any known mechanism*/
50
static final int kLSItemInfoIsNativeApp = 0x00000080; /* Carbon or Cocoa native app*/
51
static final int kLSItemInfoIsClassicApp = 0x00000100; /* CFM/68K Classic app*/
52
static final int kLSItemInfoAppPrefersNative = 0x00000200; /* Carbon app that prefers to be launched natively*/
53
static final int kLSItemInfoAppPrefersClassic = 0x00000400; /* Carbon app that prefers to be launched in Classic*/
54
static final int kLSItemInfoAppIsScriptable = 0x00000800; /* App can be scripted*/
55
static final int kLSItemInfoIsVolume = 0x00001000; /* Item is a volume*/
56
static final int kLSItemInfoExtensionIsHidden = 0x00100000; /* Item has a hidden extension*/
57
58
static {
59
java.security.AccessController.doPrivileged(
60
new java.security.PrivilegedAction<Void>() {
61
public Void run() {
62
System.loadLibrary("osxui");
63
return null;
64
}
65
});
66
}
67
68
// TODO: Un-comment this out when the native version exists
69
//private static native String getNativePathToRunningJDKBundle();
70
private static native String getNativePathToSharedJDKBundle();
71
72
private static native String getNativeMachineName();
73
private static native String getNativeDisplayName(final byte[] pathBytes, final boolean isDirectory);
74
private static native int getNativeLSInfo(final byte[] pathBytes, final boolean isDirectory);
75
private static native String getNativePathForResolvedAlias(final byte[] absolutePath, final boolean isDirectory);
76
77
static final RecyclableSingleton<String> machineName = new RecyclableSingleton<String>() {
78
@Override
79
protected String getInstance() {
80
return getNativeMachineName();
81
}
82
};
83
private static String getMachineName() {
84
return machineName.get();
85
}
86
87
protected static String getPathToRunningJDKBundle() {
88
// TODO: Return empty string for now
89
return "";//getNativePathToRunningJDKBundle();
90
}
91
92
protected static String getPathToSharedJDKBundle() {
93
return getNativePathToSharedJDKBundle();
94
}
95
96
static class FileInfo {
97
final boolean isDirectory;
98
final String absolutePath;
99
byte[] pathBytes;
100
101
String displayName;
102
Icon icon;
103
int launchServicesInfo = UNINITALIZED_LS_INFO;
104
105
FileInfo(final File file){
106
isDirectory = file.isDirectory();
107
absolutePath = file.getAbsolutePath();
108
try {
109
pathBytes = absolutePath.getBytes("UTF-8");
110
} catch (final UnsupportedEncodingException e) {
111
pathBytes = new byte[0];
112
}
113
}
114
}
115
116
final int MAX_CACHED_ENTRIES = 256;
117
protected final Map<File, FileInfo> cache = new LinkedHashMap<File, FileInfo>(){
118
protected boolean removeEldestEntry(final Entry<File, FileInfo> eldest) {
119
return size() > MAX_CACHED_ENTRIES;
120
}
121
};
122
123
FileInfo getFileInfoFor(final File file) {
124
final FileInfo info = cache.get(file);
125
if (info != null) return info;
126
final FileInfo newInfo = new FileInfo(file);
127
cache.put(file, newInfo);
128
return newInfo;
129
}
130
131
132
final AquaFileChooserUI fFileChooserUI;
133
public AquaFileView(final AquaFileChooserUI fileChooserUI) {
134
fFileChooserUI = fileChooserUI;
135
}
136
137
String _directoryDescriptionText() {
138
return fFileChooserUI.directoryDescriptionText;
139
}
140
141
String _fileDescriptionText() {
142
return fFileChooserUI.fileDescriptionText;
143
}
144
145
boolean _packageIsTraversable() {
146
return fFileChooserUI.fPackageIsTraversable == AquaFileChooserUI.kOpenAlways;
147
}
148
149
boolean _applicationIsTraversable() {
150
return fFileChooserUI.fApplicationIsTraversable == AquaFileChooserUI.kOpenAlways;
151
}
152
153
public String getName(final File f) {
154
final FileInfo info = getFileInfoFor(f);
155
if (info.displayName != null) return info.displayName;
156
157
final String nativeDisplayName = getNativeDisplayName(info.pathBytes, info.isDirectory);
158
if (nativeDisplayName != null) {
159
info.displayName = nativeDisplayName;
160
return nativeDisplayName;
161
}
162
163
final String displayName = f.getName();
164
if (f.isDirectory() && fFileChooserUI.getFileChooser().getFileSystemView().isRoot(f)) {
165
final String localMachineName = getMachineName();
166
info.displayName = localMachineName;
167
return localMachineName;
168
}
169
170
info.displayName = displayName;
171
return displayName;
172
}
173
174
public String getDescription(final File f) {
175
return f.getName();
176
}
177
178
public String getTypeDescription(final File f) {
179
if (f.isDirectory()) return _directoryDescriptionText();
180
return _fileDescriptionText();
181
}
182
183
public Icon getIcon(final File f) {
184
final FileInfo info = getFileInfoFor(f);
185
if (info.icon != null) return info.icon;
186
187
if (f == null) {
188
info.icon = AquaIcon.SystemIcon.getDocumentIconUIResource();
189
} else {
190
// Look for the document's icon
191
final AquaIcon.FileIcon fileIcon = new AquaIcon.FileIcon(f);
192
info.icon = fileIcon;
193
if (!fileIcon.hasIconRef()) {
194
// Fall back on the default icons
195
if (f.isDirectory()) {
196
if (fFileChooserUI.getFileChooser().getFileSystemView().isRoot(f)) {
197
info.icon = AquaIcon.SystemIcon.getComputerIconUIResource();
198
} else if (f.getParent() == null || f.getParent().equals("/")) {
199
info.icon = AquaIcon.SystemIcon.getHardDriveIconUIResource();
200
} else {
201
info.icon = AquaIcon.SystemIcon.getFolderIconUIResource();
202
}
203
} else {
204
info.icon = AquaIcon.SystemIcon.getDocumentIconUIResource();
205
}
206
}
207
}
208
209
return info.icon;
210
}
211
212
// aliases are traversable though they aren't directories
213
public Boolean isTraversable(final File f) {
214
if (f.isDirectory()) {
215
// Doesn't matter if it's a package or app, because they're traversable
216
if (_packageIsTraversable() && _applicationIsTraversable()) {
217
return Boolean.TRUE;
218
} else if (!_packageIsTraversable() && !_applicationIsTraversable()) {
219
if (isPackage(f) || isApplication(f)) return Boolean.FALSE;
220
} else if (!_applicationIsTraversable()) {
221
if (isApplication(f)) return Boolean.FALSE;
222
} else if (!_packageIsTraversable()) {
223
// [3101730] All applications are packages, but not all packages are applications.
224
if (isPackage(f) && !isApplication(f)) return Boolean.FALSE;
225
}
226
227
// We're allowed to traverse it
228
return Boolean.TRUE;
229
}
230
231
if (isAlias(f)) {
232
final File realFile = resolveAlias(f);
233
return realFile.isDirectory() ? Boolean.TRUE : Boolean.FALSE;
234
}
235
236
return Boolean.FALSE;
237
}
238
239
int getLSInfoFor(final File f) {
240
final FileInfo info = getFileInfoFor(f);
241
242
if (info.launchServicesInfo == UNINITALIZED_LS_INFO) {
243
info.launchServicesInfo = getNativeLSInfo(info.pathBytes, info.isDirectory);
244
}
245
246
return info.launchServicesInfo;
247
}
248
249
boolean isAlias(final File f) {
250
final int lsInfo = getLSInfoFor(f);
251
return ((lsInfo & kLSItemInfoIsAliasFile) != 0) && ((lsInfo & kLSItemInfoIsSymlink) == 0);
252
}
253
254
boolean isApplication(final File f) {
255
return (getLSInfoFor(f) & kLSItemInfoIsApplication) != 0;
256
}
257
258
boolean isPackage(final File f) {
259
return (getLSInfoFor(f) & kLSItemInfoIsPackage) != 0;
260
}
261
262
/**
263
* Things that need to be handled:
264
* -Change getFSRef to use CFURLRef instead of FSPathMakeRef
265
* -Use the HFS-style path from CFURLRef in resolveAlias() to avoid
266
* path length limitations
267
* -In resolveAlias(), simply resolve immediately if this is an alias
268
*/
269
270
/**
271
* Returns the actual file represented by this object. This will
272
* resolve any aliases in the path, including this file if it is an
273
* alias. No alias resolution requiring user interaction (e.g.
274
* mounting servers) will occur. Note that aliases to servers may
275
* take a significant amount of time to resolve. This method
276
* currently does not have any provisions for a more fine-grained
277
* timeout for alias resolution beyond that used by the system.
278
*
279
* In the event of a path that does not contain any aliases, or if the file
280
* does not exist, this method will return the file that was passed in.
281
* @return The canonical path to the file
282
* @throws IOException If an I/O error occurs while attempting to
283
* construct the path
284
*/
285
File resolveAlias(final File mFile) {
286
// If the file exists and is not an alias, there aren't
287
// any aliases along its path, so the standard version
288
// of getCanonicalPath() will work.
289
if (mFile.exists() && !isAlias(mFile)) {
290
if (DEBUG) System.out.println("not an alias");
291
return mFile;
292
}
293
294
// If it doesn't exist, either there's an alias in the
295
// path or this is an alias. Traverse the path and
296
// resolve all aliases in it.
297
final LinkedList<String> components = getPathComponents(mFile);
298
if (components == null) {
299
if (DEBUG) System.out.println("getPathComponents is null ");
300
return mFile;
301
}
302
303
File file = new File("/");
304
for (final String nextComponent : components) {
305
file = new File(file, nextComponent);
306
final FileInfo info = getFileInfoFor(file);
307
308
// If any point along the way doesn't exist,
309
// just return the file.
310
if (!file.exists()) { return mFile; }
311
312
if (isAlias(file)) {
313
// Resolve it!
314
final String path = getNativePathForResolvedAlias(info.pathBytes, info.isDirectory);
315
316
// <rdar://problem/3582601> If the alias doesn't resolve (on a non-existent volume, for example)
317
// just return the file.
318
if (path == null) return mFile;
319
320
file = new File(path);
321
}
322
}
323
324
return file;
325
}
326
327
/**
328
* Returns a linked list of Strings consisting of the components of
329
* the path of this file, in order, including the filename as the
330
* last element. The first element in the list will be the first
331
* directory in the path, or "".
332
* @return A linked list of the components of this file's path
333
*/
334
private static LinkedList<String> getPathComponents(final File mFile) {
335
final LinkedList<String> componentList = new LinkedList<String>();
336
String parent;
337
338
File file = new File(mFile.getAbsolutePath());
339
componentList.add(0, file.getName());
340
while ((parent = file.getParent()) != null) {
341
file = new File(parent);
342
componentList.add(0, file.getName());
343
}
344
return componentList;
345
}
346
}
347
348