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 {
  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
  52     private static native void setFilterString(String allFilter);
  53 
  54     @Override
  55     public void setFilenameFilter(FilenameFilter filter) {
  56         this.fileFilter = filter;
  57     }
  58 
  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
  69     WFileDialogPeer(FileDialog target) {
  70         super(target);
  71     }
  72 
  73     @Override
  74     void create(WComponentPeer parent) {
  75         this.parent = parent;
  76     }
  77 
  78     // don't use checkCreation() from WComponentPeer to avoid hwnd check
  79     @Override
  80     protected void checkCreation() {
  81     }
  82 
  83     @Override
  84     void initialize() {
  85         setFilenameFilter(((FileDialog) target).getFilenameFilter());
  86     }
  87 
  88     private native void _dispose();
  89     @Override
  90     protected void disposeImpl() {
  91         WToolkit.targetDisposedPeer(target, this);
  92         _dispose();
  93     }
  94 
  95     private native void _show();
  96     private native void _hide();
  97 
  98     @Override
  99     public void show() {
 100         new Thread(null, this::_show, "FileDialog", 0, false).start();
 101     }
 102 
 103     @Override
 104     void hide() {
 105         _hide();
 106     }
 107 
 108     // called from native code when the dialog is shown or hidden
 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      */
 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!
 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 
 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     }
 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
 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
 243     public native void toFront();
 244     @Override
 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
 250     public void updateAlwaysOnTopState() {}
 251     @Override
 252     public void setDirectory(String dir) {}
 253     @Override
 254     public void setFile(String file) {}
 255     @Override
 256     public void setTitle(String title) {}
 257 
 258     @Override
 259     public void setResizable(boolean resizable) {}
 260     @Override
 261     void enable() {}
 262     @Override
 263     void disable() {}
 264     @Override
 265     public void reshape(int x, int y, int width, int height) {}
 266     public boolean handleEvent(Event e) { return false; }
 267     @Override
 268     public void setForeground(Color c) {}
 269     @Override
 270     public void setBackground(Color c) {}
 271     @Override
 272     public void setFont(Font f) {}
 273     @Override
 274     public void updateMinimumSize() {}
 275     @Override
 276     public void updateIconImages() {}
 277     public boolean requestFocus(boolean temporary,
 278                                 boolean focusedWindowChangeAllowed) {
 279         return false;
 280     }
 281 
 282     @Override
 283     public boolean requestFocus
 284          (Component lightweightChild, boolean temporary,
 285           boolean focusedWindowChangeAllowed, long time, Cause cause)
 286     {
 287         return false;
 288     }
 289 
 290     @Override
 291     void start() {}
 292     @Override
 293     public void beginValidate() {}
 294     @Override
 295     public void endValidate() {}
 296     void invalidate(int x, int y, int width, int height) {}
 297     @Override
 298     public void addDropTarget(DropTarget dt) {}
 299     @Override
 300     public void removeDropTarget(DropTarget dt) {}
 301     @Override
 302     public void updateFocusableWindowState() {}
 303     @Override
 304     public void setZOrder(ComponentPeer above) {}
 305 
 306     /**
 307      * Initialize JNI field and method ids
 308      */
 309     private static native void initIDs();
 310 
 311     // The effects are not supported for system dialogs.
 312     @Override
 313     public void applyShape(sun.java2d.pipe.Region shape) {}
 314     @Override
 315     public void setOpacity(float opacity) {}
 316     @Override
 317     public void setOpaque(boolean isOpaque) {}
 318     public void updateWindow(java.awt.image.BufferedImage backBuffer) {}
 319 
 320     // the file/print dialogs are native dialogs and
 321     // the native system does their own rendering
 322     @Override
 323     public void createScreenSurface(boolean isResize) {}
 324     @Override
 325     public void replaceSurfaceData() {}
 326 
 327     public boolean isMultipleMode() {
 328         FileDialog fileDialog = (FileDialog)target;
 329         return AWTAccessor.getFileDialogAccessor().isMultipleMode(fileDialog);
 330     }
 331 
 332     @Override
 333     public native Point getLocationOnScreen();
 334 }