1 /*
2  * Copyright (c) 1996, 2016, 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 package sun.awt.windows;
26 
27 import java.awt.*;
28 import java.awt.event.FocusEvent.Cause;
29 import java.awt.dnd.DropTarget;
30 import java.awt.peer.*;
31 import java.io.File;
32 import java.io.FilenameFilter;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35 import java.util.ResourceBundle;
36 import java.util.MissingResourceException;
37 import java.util.Vector;
38 import sun.awt.AWTAccessor;
39 
40 final class WFileDialogPeer extends WWindowPeer implements FileDialogPeer {
41 
42     static {
initIDs()43         initIDs();
44     }
45 
46     private WComponentPeer parent;
47     private FilenameFilter fileFilter;
48 
49     private Vector<WWindowPeer> blockedWindows = new Vector<>();
50 
51     //Needed to fix 4152317
setFilterString(String allFilter)52     private static native void setFilterString(String allFilter);
53 
54     @Override
setFilenameFilter(FilenameFilter filter)55     public void setFilenameFilter(FilenameFilter filter) {
56         this.fileFilter = filter;
57     }
58 
checkFilenameFilter(String filename)59     boolean checkFilenameFilter(String filename) {
60         FileDialog fileDialog = (FileDialog)target;
61         if (fileFilter == null) {
62             return true;
63         }
64         File file = new File(filename);
65         return fileFilter.accept(new File(file.getParent()), file.getName());
66     }
67 
68     // Toolkit & peer internals
WFileDialogPeer(FileDialog target)69     WFileDialogPeer(FileDialog target) {
70         super(target);
71     }
72 
73     @Override
create(WComponentPeer parent)74     void create(WComponentPeer parent) {
75         this.parent = parent;
76     }
77 
78     // don't use checkCreation() from WComponentPeer to avoid hwnd check
79     @Override
checkCreation()80     protected void checkCreation() {
81     }
82 
83     @Override
initialize()84     void initialize() {
85         setFilenameFilter(((FileDialog) target).getFilenameFilter());
86     }
87 
_dispose()88     private native void _dispose();
89     @Override
disposeImpl()90     protected void disposeImpl() {
91         WToolkit.targetDisposedPeer(target, this);
92         _dispose();
93     }
94 
_show()95     private native void _show();
_hide()96     private native void _hide();
97 
98     @Override
show()99     public void show() {
100         new Thread(null, this::_show, "FileDialog", 0, false).start();
101     }
102 
103     @Override
hide()104     void hide() {
105         _hide();
106     }
107 
108     // called from native code when the dialog is shown or hidden
setHWnd(long hwnd)109     void setHWnd(long hwnd) {
110         if (this.hwnd == hwnd) {
111             return;
112         }
113         this.hwnd = hwnd;
114         for (WWindowPeer window : blockedWindows) {
115             if (hwnd != 0) {
116                 window.modalDisable((Dialog)target, hwnd);
117             } else {
118                 window.modalEnable((Dialog)target);
119             }
120         }
121     }
122 
123     /*
124      * The function converts the file names (the buffer parameter)
125      * in the Windows format into the Java format and saves the results
126      * into the FileDialog instance.
127      *
128      * If it's the multi-select mode, the buffer contains the current
129      * directory followed by the short names of the files.
130      * The directory and file name strings are NULL separated.
131      * If it's the single-select mode, the buffer doesn't have the NULL
132      * separator between the path and the file name.
133      *
134      * NOTE: This method is called by privileged threads.
135      *       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
136      */
handleSelected(final char[] buffer)137     void handleSelected(final char[] buffer)
138     {
139         String[] wFiles = (new String(buffer)).split("\0"); // NULL is the delimiter
140         boolean multiple = (wFiles.length > 1);
141 
142         String jDirectory = null;
143         String jFile = null;
144         File[] jFiles = null;
145 
146         if (multiple) {
147             jDirectory = wFiles[0];
148             int filesNumber = wFiles.length - 1;
149             jFiles = new File[filesNumber];
150             for (int i = 0; i < filesNumber; i++) {
151                 jFiles[i] = new File(jDirectory, wFiles[i + 1]);
152         }
153             jFile = wFiles[1]; // choose any file
154         } else {
155             int index = wFiles[0].lastIndexOf(java.io.File.separatorChar);
156             if (index == -1) {
157                 jDirectory = "."+java.io.File.separator;
158                 jFile = wFiles[0];
159             } else {
160                 jDirectory = wFiles[0].substring(0, index + 1);
161                 jFile = wFiles[0].substring(index + 1);
162             }
163             jFiles = new File[] { new File(jDirectory, jFile) };
164         }
165 
166         final FileDialog fileDialog = (FileDialog)target;
167         AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor();
168 
169         fileDialogAccessor.setDirectory(fileDialog, jDirectory);
170         fileDialogAccessor.setFile(fileDialog, jFile);
171         fileDialogAccessor.setFiles(fileDialog, jFiles);
172 
173         WToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() {
174              @Override
175              public void run() {
176                  fileDialog.setVisible(false);
177              }
178         });
179     } // handleSelected()
180 
181     // NOTE: This method is called by privileged threads.
182     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
handleCancel()183     void handleCancel() {
184         final FileDialog fileDialog = (FileDialog)target;
185 
186         AWTAccessor.getFileDialogAccessor().setFile(fileDialog, null);
187         AWTAccessor.getFileDialogAccessor().setFiles(fileDialog, null);
188         AWTAccessor.getFileDialogAccessor().setDirectory(fileDialog, null);
189 
190         WToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() {
191              @Override
192              public void run() {
193                  fileDialog.setVisible(false);
194              }
195         });
196     } // handleCancel()
197 
198     //This whole static block is a part of 4152317 fix
199     static {
200         String filterString = AccessController.doPrivileged(
201             new PrivilegedAction<String>() {
202                 @Override
203                 public String run() {
204                     try {
205                         ResourceBundle rb = ResourceBundle.getBundle("sun.awt.windows.awtLocalization");
206                         return rb.getString("allFiles");
207                     } catch (MissingResourceException e) {
208                         return "All Files";
209                     }
210                 }
211             });
212         setFilterString(filterString);
213     }
214 
blockWindow(WWindowPeer window)215     void blockWindow(WWindowPeer window) {
216         blockedWindows.add(window);
217         // if this dialog hasn't got an HWND, notification is
218         // postponed until setHWnd() is called
219         if (hwnd != 0) {
220             window.modalDisable((Dialog)target, hwnd);
221         }
222     }
unblockWindow(WWindowPeer window)223     void unblockWindow(WWindowPeer window) {
224         blockedWindows.remove(window);
225         // if this dialog hasn't got an HWND or has been already
226         // closed, don't send notification
227         if (hwnd != 0) {
228             window.modalEnable((Dialog)target);
229         }
230     }
231 
232     @Override
blockWindows(java.util.List<Window> toBlock)233     public void blockWindows(java.util.List<Window> toBlock) {
234         for (Window w : toBlock) {
235             WWindowPeer wp = AWTAccessor.getComponentAccessor().getPeer(w);
236             if (wp != null) {
237                 blockWindow(wp);
238             }
239         }
240     }
241 
242     @Override
toFront()243     public native void toFront();
244     @Override
toBack()245     public native void toBack();
246 
247     // unused methods.  Overridden to disable this functionality as
248     // it requires HWND which is not available for FileDialog
249     @Override
updateAlwaysOnTopState()250     public void updateAlwaysOnTopState() {}
251     @Override
setDirectory(String dir)252     public void setDirectory(String dir) {}
253     @Override
setFile(String file)254     public void setFile(String file) {}
255     @Override
setTitle(String title)256     public void setTitle(String title) {}
257 
258     @Override
setResizable(boolean resizable)259     public void setResizable(boolean resizable) {}
260     @Override
enable()261     void enable() {}
262     @Override
disable()263     void disable() {}
264     @Override
reshape(int x, int y, int width, int height)265     public void reshape(int x, int y, int width, int height) {}
266     @SuppressWarnings("deprecation")
handleEvent(Event e)267     public boolean handleEvent(Event e) { return false; }
268     @Override
setForeground(Color c)269     public void setForeground(Color c) {}
270     @Override
setBackground(Color c)271     public void setBackground(Color c) {}
272     @Override
setFont(Font f)273     public void setFont(Font f) {}
274     @Override
updateMinimumSize()275     public void updateMinimumSize() {}
276     @Override
updateIconImages()277     public void updateIconImages() {}
requestFocus(boolean temporary, boolean focusedWindowChangeAllowed)278     public boolean requestFocus(boolean temporary,
279                                 boolean focusedWindowChangeAllowed) {
280         return false;
281     }
282 
283     @Override
requestFocus(Component lightweightChild, boolean temporary, boolean focusedWindowChangeAllowed, long time, Cause cause)284     public boolean requestFocus
285          (Component lightweightChild, boolean temporary,
286           boolean focusedWindowChangeAllowed, long time, Cause cause)
287     {
288         return false;
289     }
290 
291     @Override
start()292     void start() {}
293     @Override
beginValidate()294     public void beginValidate() {}
295     @Override
endValidate()296     public void endValidate() {}
invalidate(int x, int y, int width, int height)297     void invalidate(int x, int y, int width, int height) {}
298     @Override
addDropTarget(DropTarget dt)299     public void addDropTarget(DropTarget dt) {}
300     @Override
removeDropTarget(DropTarget dt)301     public void removeDropTarget(DropTarget dt) {}
302     @Override
updateFocusableWindowState()303     public void updateFocusableWindowState() {}
304     @Override
setZOrder(ComponentPeer above)305     public void setZOrder(ComponentPeer above) {}
306 
307     /**
308      * Initialize JNI field and method ids
309      */
initIDs()310     private static native void initIDs();
311 
312     // The effects are not supported for system dialogs.
313     @Override
applyShape(sun.java2d.pipe.Region shape)314     public void applyShape(sun.java2d.pipe.Region shape) {}
315     @Override
setOpacity(float opacity)316     public void setOpacity(float opacity) {}
317     @Override
setOpaque(boolean isOpaque)318     public void setOpaque(boolean isOpaque) {}
updateWindow(java.awt.image.BufferedImage backBuffer)319     public void updateWindow(java.awt.image.BufferedImage backBuffer) {}
320 
321     // the file/print dialogs are native dialogs and
322     // the native system does their own rendering
323     @Override
createScreenSurface(boolean isResize)324     public void createScreenSurface(boolean isResize) {}
325     @Override
replaceSurfaceData()326     public void replaceSurfaceData() {}
327 
isMultipleMode()328     public boolean isMultipleMode() {
329         FileDialog fileDialog = (FileDialog)target;
330         return AWTAccessor.getFileDialogAccessor().isMultipleMode(fileDialog);
331     }
332 
333     @Override
getLocationOnScreen()334     public native Point getLocationOnScreen();
335 }
336