1 /*
   2  * Copyright (c) 2011, 2020, 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 
  26 package sun.lwawt.macosx;
  27 
  28 import java.awt.AWTEvent;
  29 import java.awt.AWTException;
  30 import java.awt.BufferCapabilities;
  31 import java.awt.BufferCapabilities.FlipContents;
  32 import java.awt.Color;
  33 import java.awt.Component;
  34 import java.awt.Dialog;
  35 import java.awt.Dimension;
  36 import java.awt.FileDialog;
  37 import java.awt.Font;
  38 import java.awt.FontMetrics;
  39 import java.awt.Graphics;
  40 import java.awt.GraphicsConfiguration;
  41 import java.awt.Image;
  42 import java.awt.Insets;
  43 import java.awt.Point;
  44 import java.awt.Window;
  45 import java.awt.event.FocusEvent.Cause;
  46 import java.awt.event.PaintEvent;
  47 import java.awt.image.ColorModel;
  48 import java.awt.image.VolatileImage;
  49 import java.awt.peer.ComponentPeer;
  50 import java.awt.peer.ContainerPeer;
  51 import java.awt.peer.FileDialogPeer;
  52 import java.io.File;
  53 import java.io.FilenameFilter;
  54 import java.security.AccessController;
  55 import java.util.List;
  56 
  57 import sun.awt.AWTAccessor;
  58 import sun.java2d.pipe.Region;
  59 import sun.security.action.GetBooleanAction;
  60 
  61 class CFileDialog implements FileDialogPeer {
  62 
  63     private class Task implements Runnable {
  64 
  65         @Override
  66         public void run() {
  67             try {
  68                 boolean navigateApps = !AccessController.doPrivileged(
  69                         new GetBooleanAction("apple.awt.use-file-dialog-packages"));
  70                 boolean chooseDirectories = AccessController.doPrivileged(
  71                         new GetBooleanAction("apple.awt.fileDialogForDirectories"));
  72 
  73                 int dialogMode = target.getMode();
  74                 String title = target.getTitle();
  75                 if (title == null) {
  76                     title = " ";
  77                 }
  78 
  79                 String[] userFileNames = nativeRunFileDialog(title,
  80                         dialogMode,
  81                         target.isMultipleMode(),
  82                         navigateApps,
  83                         chooseDirectories,
  84                         target.getFilenameFilter() != null,
  85                         target.getDirectory(),
  86                         target.getFile());
  87 
  88                 String directory = null;
  89                 String file = null;
  90                 File[] files = null;
  91 
  92                 if (userFileNames != null) {
  93                     // the dialog wasn't cancelled
  94                     int filesNumber = userFileNames.length;
  95                     files = new File[filesNumber];
  96                     for (int i = 0; i < filesNumber; i++) {
  97                         files[i] = new File(userFileNames[i]);
  98                     }
  99 
 100                     directory = files[0].getParent();
 101                     // make sure directory always ends in '/'
 102                     if (!directory.endsWith(File.separator)) {
 103                         directory = directory + File.separator;
 104                     }
 105 
 106                     file = files[0].getName(); // pick any file
 107                 }
 108 
 109                 // store results back in component
 110                 AWTAccessor.FileDialogAccessor accessor = AWTAccessor.getFileDialogAccessor();
 111                 accessor.setDirectory(target, directory);
 112                 accessor.setFile(target, file);
 113                 accessor.setFiles(target, files);
 114             } finally {
 115                 // Java2 Dialog waits for hide to let show() return
 116                 target.dispose();
 117             }
 118         }
 119     }
 120 
 121     // The target FileDialog
 122     private final FileDialog target;
 123 
 124     CFileDialog(FileDialog target) {
 125         this.target = target;
 126     }
 127 
 128     @Override
 129     public void dispose() {
 130         LWCToolkit.targetDisposedPeer(target, this);
 131         // Unlike other peers, we do not have a native model pointer to
 132         // dispose of because the save and open panels are never released by
 133         // an application.
 134     }
 135 
 136     @Override
 137     public void setVisible(boolean visible) {
 138         if (visible) {
 139             // Java2 Dialog class requires peer to run code in a separate thread
 140             // and handles keeping the call modal
 141             new Thread(null, new Task(), "FileDialog", 0, false).start();
 142         }
 143         // We hide ourself before "show" returns - setVisible(false)
 144         // doesn't apply
 145     }
 146 
 147     /**
 148      * A callback method.
 149      * If the file dialog has a file filter, ask it if inFilename is acceptable.
 150      * If the dialog doesn't have a file filter return true.
 151      */
 152     private boolean queryFilenameFilter(final String inFilename) {
 153         boolean ret = false;
 154 
 155         final FilenameFilter ff = target.getFilenameFilter();
 156         File fileObj = new File(inFilename);
 157 
 158         // Directories are never filtered by the FileDialog.
 159         if (!fileObj.isDirectory()) {
 160             File directoryObj = new File(fileObj.getParent());
 161             String nameOnly = fileObj.getName();
 162             ret = ff.accept(directoryObj, nameOnly);
 163         }
 164         return ret;
 165     }
 166 
 167     private native String[] nativeRunFileDialog(String title, int mode,
 168             boolean multipleMode, boolean shouldNavigateApps,
 169             boolean canChooseDirectories, boolean hasFilenameFilter,
 170             String directory, String file);
 171 
 172     @Override
 173     public void setDirectory(String dir) {
 174     }
 175 
 176     @Override
 177     public void setFile(String file) {
 178     }
 179 
 180     @Override
 181     public void setFilenameFilter(FilenameFilter filter) {
 182     }
 183 
 184     @Override
 185     public void blockWindows(List<Window> windows) {
 186     }
 187 
 188     @Override
 189     public void setResizable(boolean resizeable) {
 190     }
 191 
 192     @Override
 193     public void setTitle(String title) {
 194     }
 195 
 196     @Override
 197     public void repositionSecurityWarning() {
 198     }
 199 
 200     @Override
 201     public void updateAlwaysOnTopState() {
 202     }
 203 
 204     @Override
 205     public void setModalBlocked(Dialog blocker, boolean blocked) {
 206     }
 207 
 208     @Override
 209     public void setOpacity(float opacity) {
 210     }
 211 
 212     @Override
 213     public void setOpaque(boolean isOpaque) {
 214     }
 215 
 216     @Override
 217     public void toBack() {
 218     }
 219 
 220     @Override
 221     public void toFront() {
 222     }
 223 
 224     @Override
 225     public void updateFocusableWindowState() {
 226     }
 227 
 228     @Override
 229     public void updateIconImages() {
 230     }
 231 
 232     @Override
 233     public void updateMinimumSize() {
 234     }
 235 
 236     @Override
 237     public void updateWindow() {
 238     }
 239 
 240     @Override
 241     public void beginLayout() {
 242     }
 243 
 244     @Override
 245     public void beginValidate() {
 246     }
 247 
 248     @Override
 249     public void endLayout() {
 250     }
 251 
 252     @Override
 253     public void endValidate() {
 254     }
 255 
 256     @Override
 257     public Insets getInsets() {
 258         return new Insets(0, 0, 0, 0);
 259     }
 260 
 261     @Override
 262     public void applyShape(Region shape) {
 263     }
 264 
 265     @Override
 266     public boolean canDetermineObscurity() {
 267         return false;
 268     }
 269 
 270     @Override
 271     public void coalescePaintEvent(PaintEvent e) {
 272     }
 273 
 274     @Override
 275     public void createBuffers(int numBuffers, BufferCapabilities caps)
 276             throws AWTException {
 277     }
 278 
 279     @Override
 280     public Image createImage(int width, int height) {
 281         return null;
 282     }
 283 
 284     @Override
 285     public VolatileImage createVolatileImage(int width, int height) {
 286         return null;
 287     }
 288 
 289     @Override
 290     public void destroyBuffers() {
 291     }
 292 
 293     @Override
 294     public void flip(int x1, int y1, int x2, int y2, FlipContents flipAction) {
 295     }
 296 
 297     @Override
 298     public Image getBackBuffer() {
 299         return null;
 300     }
 301 
 302     @Override
 303     public ColorModel getColorModel() {
 304         return null;
 305     }
 306 
 307     @Override
 308     public FontMetrics getFontMetrics(Font font) {
 309         return null;
 310     }
 311 
 312     @Override
 313     public Graphics getGraphics() {
 314         return null;
 315     }
 316 
 317     @Override
 318     public GraphicsConfiguration getGraphicsConfiguration() {
 319         return null;
 320     }
 321 
 322     @Override
 323     public Point getLocationOnScreen() {
 324         return null;
 325     }
 326 
 327     @Override
 328     public Dimension getMinimumSize() {
 329         return target.getSize();
 330     }
 331 
 332     @Override
 333     public Dimension getPreferredSize() {
 334         return getMinimumSize();
 335     }
 336 
 337     @Override
 338     public void handleEvent(AWTEvent e) {
 339     }
 340 
 341     @Override
 342     public boolean handlesWheelScrolling() {
 343         return false;
 344     }
 345 
 346     @Override
 347     public boolean isFocusable() {
 348         return false;
 349     }
 350 
 351     @Override
 352     public boolean isObscured() {
 353         return false;
 354     }
 355 
 356     @Override
 357     public boolean isReparentSupported() {
 358         return false;
 359     }
 360 
 361     @Override
 362     public void layout() {
 363     }
 364 
 365     @Override
 366     public void paint(Graphics g) {
 367     }
 368 
 369     @Override
 370     public void print(Graphics g) {
 371     }
 372 
 373     @Override
 374     public void reparent(ContainerPeer newContainer) {
 375     }
 376 
 377     @Override
 378     public boolean requestFocus(Component lightweightChild, boolean temporary,
 379             boolean focusedWindowChangeAllowed, long time, Cause cause) {
 380         return false;
 381     }
 382 
 383     @Override
 384     public void setBackground(Color c) {
 385     }
 386 
 387     @Override
 388     public void setForeground(Color c) {
 389     }
 390 
 391     @Override
 392     public void setBounds(int x, int y, int width, int height, int op) {
 393     }
 394 
 395     @Override
 396     public void setEnabled(boolean e) {
 397     }
 398 
 399     @Override
 400     public void setFont(Font f) {
 401     }
 402 
 403     @Override
 404     public void setZOrder(ComponentPeer above) {
 405     }
 406 
 407     @Override
 408     public void updateCursorImmediately() {
 409     }
 410 
 411     @Override
 412     public boolean updateGraphicsData(GraphicsConfiguration gc) {
 413         return false;
 414     }
 415 }