001: /*
002: * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.awt.shell;
027:
028: import java.awt.Toolkit;
029:
030: import java.io.File;
031: import java.io.FileNotFoundException;
032: import java.io.IOException;
033: import java.security.AccessController;
034: import java.util.*;
035: import sun.security.action.LoadLibraryAction;
036:
037: import static sun.awt.shell.Win32ShellFolder2.*;
038:
039: // NOTE: This class supersedes Win32ShellFolderManager, which was removed
040: // from distribution after version 1.4.2.
041:
042: /**
043: * @author Michael Martak
044: * @author Leif Samuelsson
045: * @author Kenneth Russell
046: * @since 1.4
047: */
048:
049: public class Win32ShellFolderManager2 extends ShellFolderManager {
050:
051: static {
052: // Load library here
053: AccessController.doPrivileged(new LoadLibraryAction("awt"));
054: }
055:
056: public ShellFolder createShellFolder(File file)
057: throws FileNotFoundException {
058: return createShellFolder(getDesktop(), file);
059: }
060:
061: static Win32ShellFolder2 createShellFolder(
062: Win32ShellFolder2 parent, File file)
063: throws FileNotFoundException {
064: long pIDL = 0;
065: try {
066: pIDL = parent.parseDisplayName(file.getCanonicalPath());
067: } catch (IOException ex) {
068: pIDL = 0;
069: }
070: if (pIDL == 0) {
071: // Shouldn't happen but watch for it anyway
072: throw new FileNotFoundException("File "
073: + file.getAbsolutePath() + " not found");
074: }
075: Win32ShellFolder2 folder = createShellFolderFromRelativePIDL(
076: parent, pIDL);
077: Win32ShellFolder2.releasePIDL(pIDL);
078: return folder;
079: }
080:
081: static Win32ShellFolder2 createShellFolderFromRelativePIDL(
082: Win32ShellFolder2 parent, long pIDL) {
083: // Walk down this relative pIDL, creating new nodes for each of the entries
084: while (pIDL != 0) {
085: long curPIDL = Win32ShellFolder2.copyFirstPIDLEntry(pIDL);
086: if (curPIDL != 0) {
087: parent = new Win32ShellFolder2(parent, curPIDL);
088: pIDL = Win32ShellFolder2.getNextPIDLEntry(pIDL);
089: } else {
090: // The list is empty if the parent is Desktop and pIDL is a shortcut to Desktop
091: break;
092: }
093: }
094: return parent;
095: }
096:
097: // Special folders
098: private static Win32ShellFolder2 desktop;
099: private static Win32ShellFolder2 drives;
100: private static Win32ShellFolder2 recent;
101: private static Win32ShellFolder2 network;
102: private static Win32ShellFolder2 personal;
103:
104: private static String osVersion = System.getProperty("os.version");
105: private static final boolean useShell32Icons = (osVersion != null && osVersion
106: .compareTo("5.1") >= 0);
107:
108: static Win32ShellFolder2 getDesktop() {
109: if (desktop == null) {
110: try {
111: desktop = new Win32ShellFolder2(DESKTOP);
112: } catch (IOException e) {
113: desktop = null;
114: }
115: }
116: return desktop;
117: }
118:
119: static Win32ShellFolder2 getDrives() {
120: if (drives == null) {
121: try {
122: drives = new Win32ShellFolder2(DRIVES);
123: } catch (IOException e) {
124: drives = null;
125: }
126: }
127: return drives;
128: }
129:
130: static Win32ShellFolder2 getRecent() {
131: if (recent == null) {
132: try {
133: String path = Win32ShellFolder2
134: .getFileSystemPath(RECENT);
135: if (path != null) {
136: recent = (Win32ShellFolder2) createShellFolder(
137: getDesktop(), new File(path));
138: }
139: } catch (IOException e) {
140: recent = null;
141: }
142: }
143: return recent;
144: }
145:
146: static Win32ShellFolder2 getNetwork() {
147: if (network == null) {
148: try {
149: network = new Win32ShellFolder2(NETWORK);
150: } catch (IOException e) {
151: network = null;
152: }
153: }
154: return network;
155: }
156:
157: static Win32ShellFolder2 getPersonal() {
158: if (personal == null) {
159: try {
160: String path = Win32ShellFolder2
161: .getFileSystemPath(PERSONAL);
162: if (path != null) {
163: Win32ShellFolder2 desktop = getDesktop();
164: personal = desktop.getChildByPath(path);
165: if (personal == null) {
166: personal = (Win32ShellFolder2) createShellFolder(
167: getDesktop(), new File(path));
168: }
169: if (personal != null) {
170: personal.setIsPersonal();
171: }
172: }
173: } catch (IOException e) {
174: personal = null;
175: }
176: }
177: return personal;
178: }
179:
180: private static File[] roots;
181:
182: /**
183: * @param key a <code>String</code>
184: * "fileChooserDefaultFolder":
185: * Returns a <code>File</code> - the default shellfolder for a new filechooser
186: * "roots":
187: * Returns a <code>File[]</code> - containing the root(s) of the displayable hierarchy
188: * "fileChooserComboBoxFolders":
189: * Returns a <code>File[]</code> - an array of shellfolders representing the list to
190: * show by default in the file chooser's combobox
191: * "fileChooserShortcutPanelFolders":
192: * Returns a <code>File[]</code> - an array of shellfolders representing well-known
193: * folders, such as Desktop, Documents, History, Network, Home, etc.
194: * This is used in the shortcut panel of the filechooser on Windows 2000
195: * and Windows Me.
196: * "fileChooserIcon nn":
197: * Returns an <code>Image</code> - icon nn from resource 216 in shell32.dll,
198: * or if not found there from resource 124 in comctl32.dll (Windows only).
199: * "optionPaneIcon iconName":
200: * Returns an <code>Image</code> - icon from the system icon list
201: *
202: * @return An Object matching the key string.
203: */
204: public Object get(String key) {
205: if (key.equals("fileChooserDefaultFolder")) {
206: File file = getPersonal();
207: if (file == null) {
208: file = getDesktop();
209: }
210: return file;
211: } else if (key.equals("roots")) {
212: // Should be "History" and "Desktop" ?
213: if (roots == null) {
214: File desktop = getDesktop();
215: if (desktop != null) {
216: roots = new File[] { desktop };
217: } else {
218: roots = (File[]) super .get(key);
219: }
220: }
221: return roots;
222: } else if (key.equals("fileChooserComboBoxFolders")) {
223: Win32ShellFolder2 desktop = getDesktop();
224:
225: if (desktop != null) {
226: ArrayList folders = new ArrayList();
227: Win32ShellFolder2 drives = getDrives();
228:
229: folders.add(desktop);
230: // Add all second level folders
231: File[] secondLevelFolders = desktop.listFiles();
232: Arrays.sort(secondLevelFolders);
233: for (int j = 0; j < secondLevelFolders.length; j++) {
234: Win32ShellFolder2 folder = (Win32ShellFolder2) secondLevelFolders[j];
235: if (!folder.isFileSystem() || folder.isDirectory()) {
236: folders.add(folder);
237: // Add third level for "My Computer"
238: if (folder.equals(drives)) {
239: File[] thirdLevelFolders = folder
240: .listFiles();
241: if (thirdLevelFolders != null) {
242: Arrays.sort(thirdLevelFolders,
243: driveComparator);
244: for (int k = 0; k < thirdLevelFolders.length; k++) {
245: folders.add(thirdLevelFolders[k]);
246: }
247: }
248: }
249: }
250: }
251: return folders.toArray(new File[folders.size()]);
252: } else {
253: return super .get(key);
254: }
255: } else if (key.equals("fileChooserShortcutPanelFolders")) {
256: Toolkit toolkit = Toolkit.getDefaultToolkit();
257: ArrayList<File> folders = new ArrayList<File>();
258: int i = 0;
259: Object value;
260: do {
261: value = toolkit
262: .getDesktopProperty("win.comdlg.placesBarPlace"
263: + i++);
264: try {
265: if (value instanceof Integer) {
266: // A CSIDL
267: folders.add(new Win32ShellFolder2(
268: (Integer) value));
269: } else if (value instanceof String) {
270: // A path
271: folders.add(createShellFolder(new File(
272: (String) value)));
273: }
274: } catch (IOException e) {
275: // Skip this value
276: }
277: } while (value != null);
278:
279: if (folders.size() == 0) {
280: // Use default list of places
281: for (File f : new File[] { getRecent(), getDesktop(),
282: getPersonal(), getDrives(), getNetwork() }) {
283: if (f != null) {
284: folders.add(f);
285: }
286: }
287: }
288: return folders.toArray(new File[folders.size()]);
289: } else if (key.startsWith("fileChooserIcon ")) {
290: int i = -1;
291: String name = key.substring(key.indexOf(" ") + 1);
292: try {
293: i = Integer.parseInt(name);
294: } catch (NumberFormatException ex) {
295: if (name.equals("ListView")) {
296: i = (useShell32Icons) ? 21 : 2;
297: } else if (name.equals("DetailsView")) {
298: i = (useShell32Icons) ? 23 : 3;
299: } else if (name.equals("UpFolder")) {
300: i = (useShell32Icons) ? 28 : 8;
301: } else if (name.equals("NewFolder")) {
302: i = (useShell32Icons) ? 31 : 11;
303: } else if (name.equals("ViewMenu")) {
304: i = (useShell32Icons) ? 21 : 2;
305: }
306: }
307: if (i >= 0) {
308: return Win32ShellFolder2.getFileChooserIcon(i);
309: }
310: } else if (key.startsWith("optionPaneIcon ")) {
311: Win32ShellFolder2.SystemIcon iconType;
312: if (key == "optionPaneIcon Error") {
313: iconType = Win32ShellFolder2.SystemIcon.IDI_ERROR;
314: } else if (key == "optionPaneIcon Information") {
315: iconType = Win32ShellFolder2.SystemIcon.IDI_INFORMATION;
316: } else if (key == "optionPaneIcon Question") {
317: iconType = Win32ShellFolder2.SystemIcon.IDI_QUESTION;
318: } else if (key == "optionPaneIcon Warning") {
319: iconType = Win32ShellFolder2.SystemIcon.IDI_EXCLAMATION;
320: } else {
321: return null;
322: }
323: return Win32ShellFolder2.getSystemIcon(iconType);
324: } else if (key.startsWith("shell32Icon ")) {
325: int i = -1;
326: String name = key.substring(key.indexOf(" ") + 1);
327: try {
328: i = Integer.parseInt(name);
329: if (i >= 0) {
330: return Win32ShellFolder2.getShell32Icon(i);
331: }
332: } catch (NumberFormatException ex) {
333: }
334: }
335: return null;
336: }
337:
338: /**
339: * Does <code>dir</code> represent a "computer" such as a node on the network, or
340: * "My Computer" on the desktop.
341: */
342: public boolean isComputerNode(File dir) {
343: if (dir != null && dir == getDrives()) {
344: return true;
345: } else {
346: String path = dir.getAbsolutePath();
347: return (path.startsWith("\\\\") && path.indexOf("\\", 2) < 0); //Network path
348: }
349: }
350:
351: public boolean isFileSystemRoot(File dir) {
352: //Note: Removable drives don't "exist" but are listed in "My Computer"
353: if (dir != null) {
354: Win32ShellFolder2 drives = getDrives();
355: if (dir instanceof Win32ShellFolder2) {
356: Win32ShellFolder2 sf = (Win32ShellFolder2) dir;
357: if (sf.isFileSystem()) {
358: if (sf.parent != null) {
359: return sf.parent.equals(drives);
360: }
361: // else fall through ...
362: } else {
363: return false;
364: }
365: }
366: String path = dir.getPath();
367: return (path.length() == 3 && path.charAt(1) == ':' && Arrays
368: .asList(drives.listFiles()).contains(dir));
369: }
370: return false;
371: }
372:
373: private Comparator driveComparator = new Comparator() {
374: public int compare(Object o1, Object o2) {
375: Win32ShellFolder2 shellFolder1 = (Win32ShellFolder2) o1;
376: Win32ShellFolder2 shellFolder2 = (Win32ShellFolder2) o2;
377:
378: // Put drives at first
379: boolean isDrive1 = shellFolder1.getPath().endsWith(":\\");
380:
381: if (isDrive1 ^ shellFolder2.getPath().endsWith(":\\")) {
382: return isDrive1 ? -1 : 1;
383: } else {
384: return shellFolder1.getPath().compareTo(
385: shellFolder2.getPath());
386: }
387: }
388: };
389:
390: public void sortFiles(List files) {
391: Collections.sort(files, fileComparator);
392: }
393:
394: private static List topFolderList = null;
395:
396: static int compareShellFolders(Win32ShellFolder2 sf1,
397: Win32ShellFolder2 sf2) {
398: boolean special1 = sf1.isSpecial();
399: boolean special2 = sf2.isSpecial();
400:
401: if (special1 || special2) {
402: if (topFolderList == null) {
403: ArrayList tmpTopFolderList = new ArrayList();
404: tmpTopFolderList.add(Win32ShellFolderManager2
405: .getPersonal());
406: tmpTopFolderList.add(Win32ShellFolderManager2
407: .getDesktop());
408: tmpTopFolderList.add(Win32ShellFolderManager2
409: .getDrives());
410: tmpTopFolderList.add(Win32ShellFolderManager2
411: .getNetwork());
412: topFolderList = tmpTopFolderList;
413: }
414: int i1 = topFolderList.indexOf(sf1);
415: int i2 = topFolderList.indexOf(sf2);
416: if (i1 >= 0 && i2 >= 0) {
417: return (i1 - i2);
418: } else if (i1 >= 0) {
419: return -1;
420: } else if (i2 >= 0) {
421: return 1;
422: }
423: }
424:
425: // Non-file shellfolders sort before files
426: if (special1 && !special2) {
427: return -1;
428: } else if (special2 && !special1) {
429: return 1;
430: }
431:
432: return compareNames(sf1.getAbsolutePath(), sf2
433: .getAbsolutePath());
434: }
435:
436: static int compareFiles(File f1, File f2) {
437: if (f1 instanceof Win32ShellFolder2) {
438: return f1.compareTo(f2);
439: }
440: if (f2 instanceof Win32ShellFolder2) {
441: return -1 * f2.compareTo(f1);
442: }
443: return compareNames(f1.getName(), f2.getName());
444: }
445:
446: static int compareNames(String name1, String name2) {
447: // First ignore case when comparing
448: int diff = name1.toLowerCase().compareTo(name2.toLowerCase());
449: if (diff != 0) {
450: return diff;
451: } else {
452: // May differ in case (e.g. "mail" vs. "Mail")
453: // We need this test for consistent sorting
454: return name1.compareTo(name2);
455: }
456: }
457:
458: private Comparator fileComparator = new Comparator() {
459: public int compare(Object a, Object b) {
460: return compare((File) a, (File) b);
461: }
462:
463: public int compare(File f1, File f2) {
464: return compareFiles(f1, f2);
465: }
466: };
467: }
|