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