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