blob: bab97bd83cde1c215404e3ada3401cf19b405b43 [file] [log] [blame]
package org.eclipse.swt.widgets;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved
*/
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.win32.*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
/**
* Instances of this class allow the user to navigate
* the file system and select or enter a file name.
* <dl>
* <dt><b>Styles:</b></dt>
* <dd>SAVE, OPEN, MULTI</dd>
* <dt><b>Events:</b></dt>
* <dd>(none)</dd>
* </dl>
* <p>
* IMPORTANT: This class is intended to be subclassed <em>only</em>
* within the SWT implementation.
* </p>
*/
public class FileDialog extends Dialog {
String [] filterNames = new String [0];
String [] filterExtensions = new String [0];
String [] fileNames = new String [0];
String filterPath = "", fileName = "";
String fullPath = "";
static final String FILTER = "*.*";
static int BUFFER_SIZE = 1024 * 10;
public FileDialog (Shell parent) {
this (parent, SWT.PRIMARY_MODAL);
}
public FileDialog (Shell parent, int style) {
super (parent, style);
}
public String getFileName () {
return fileName;
}
public String [] getFileNames () {
return fileNames;
}
public String [] getFilterNames () {
return filterNames;
}
public String [] getFilterExtensions () {
return filterExtensions;
}
public String getFilterPath () {
return filterPath;
}
public String open () {
int hHeap = OS.GetProcessHeap ();
/* Get the owner HWND for the dialog */
int hwndOwner = 0;
if (parent != null) hwndOwner = parent.handle;
/* Convert the title and copy it into lpstrTitle */
if (title == null) title = "";
byte [] buffer3 = Converter.wcsToMbcs (0, title, true);
int lpstrTitle = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, buffer3.length);
OS.MoveMemory (lpstrTitle, buffer3, buffer3.length);
/* Compute filters and copy into lpstrFilter */
String strFilter = "";
if (filterNames == null) filterNames = new String [0];
if (filterExtensions == null) filterExtensions = new String [0];
for (int i=0; i<filterExtensions.length; i++) {
String filterName = filterExtensions [i];
if (i < filterNames.length) filterName = filterNames [i];
strFilter = strFilter + filterName + '\0' + filterExtensions [i] + '\0';
}
if (filterExtensions.length == 0) {
strFilter = strFilter + FILTER + '\0' + FILTER + '\0';
}
byte [] buffer4 = Converter.wcsToMbcs (0, strFilter, true);
int lpstrFilter = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, buffer4.length);
OS.MoveMemory (lpstrFilter, buffer4, buffer4.length);
/* Convert the fileName and filterName to C strings */
if (fileName == null) fileName = "";
byte [] name = Converter.wcsToMbcs (0, fileName, false);
if (filterPath == null) filterPath = "";
byte [] path = Converter.wcsToMbcs (0, filterPath, false);
/*
* Bug/Feature in Windows. Verify that the file name is valid.
* If an invalid file name is passed to the standard dialog, it
* does not open and returns an error code. The fix is to avoid
* this behavior by verifying the file name before opening the
* dialog. If the file name is not valid, use an empty string.
*/
byte [] buffer2 = new byte [name.length + 1];
System.arraycopy (name, 0, buffer2, 0, name.length);
if (OS.GetFileTitle (buffer2, null, (short) 0) < 0) {
name = new byte [0];
}
/*
* Copy the name into lpstrFile and ensure that the
* last byte is NULL and the buffer does not overrun.
* Note that the longest that a single path name can
* be on Windows is 256.
*/
int bufferSize = 256;
if ((style & SWT.MULTI) != 0) bufferSize = Math.max (256, BUFFER_SIZE);
int lpstrFile = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, bufferSize);
OS.MoveMemory (lpstrFile, name, Math.min (name.length, bufferSize - 1));
/*
* Copy the path into lpstrInitialDir and ensure that
* the last byte is NULL and the buffer does not overrun.
*/
int lpstrInitialDir = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, bufferSize);
OS.MoveMemory (lpstrInitialDir, path, Math.min (path.length, bufferSize - 1));
/* Create the file dialog struct */
OPENFILENAME struct = new OPENFILENAME ();
struct.lStructSize = OPENFILENAME.sizeof;
struct.Flags = OS.OFN_HIDEREADONLY | OS.OFN_NOCHANGEDIR;
if ((style & SWT.MULTI) != 0) {
struct.Flags |= OS.OFN_ALLOWMULTISELECT | OS.OFN_EXPLORER;
}
struct.hwndOwner = hwndOwner;
struct.lpstrTitle = lpstrTitle;
struct.lpstrFile = lpstrFile;
struct.nMaxFile = bufferSize;
struct.lpstrInitialDir = lpstrInitialDir;
struct.lpstrFilter = lpstrFilter;
struct.nFilterIndex = 0;
/*
* Feature in Windows. The focus window is not saved and
* and restored automatically by the call to GetOpenFileName ().
* The fix is to save and restore the focus window.
*/
int hwndFocus = OS.GetFocus ();
/*
* Bug/Feature in Windows. When Windows opens the standard
* file dialog, it changes the cursor to the hourglass and
* does not put it back. The fix is to save the current
* cursor and restore it when the dialog closes.
*/
int hCursor = OS.GetCursor ();
/*
* Open the dialog. If the open fails due to an invalid
* file name, use an empty file name and open it again.
*/
boolean save = (style & SWT.SAVE) != 0;
boolean success = (save) ? OS.GetSaveFileName (struct) : OS.GetOpenFileName (struct);
if (OS.CommDlgExtendedError () == OS.FNERR_INVALIDFILENAME) {
OS.MoveMemory (lpstrFile, new byte [1], 1);
success = (save) ? OS.GetSaveFileName (struct) : OS.GetOpenFileName (struct);
}
/* Set the new path, file name and filter */
fullPath = null;
if (success) {
int count = 0;
fileNames = new String [1];
byte [] buffer = new byte [struct.nMaxFile];
OS.MoveMemory (buffer, lpstrFile, buffer.length);
byte [] prefix = new byte [struct.nFileOffset - 1];
System.arraycopy (buffer, 0, prefix, 0, prefix.length);
filterPath = new String (Converter.mbcsToWcs (0, prefix));
int start = struct.nFileOffset;
do {
int end = start;
while (end < buffer.length && buffer [end] != 0) end++;
byte [] buffer1 = new byte [end - start];
System.arraycopy (buffer, start, buffer1, 0, buffer1.length);
start = end;
String string = new String (Converter.mbcsToWcs (0, buffer1));
if (count == fileNames.length) {
String [] newFileNames = new String [fileNames.length + 4];
System.arraycopy (fileNames, 0, newFileNames, 0, fileNames.length);
fileNames = newFileNames;
}
fileNames [count++] = string;
if ((style & SWT.MULTI) == 0) break;
start++;
} while (start < buffer.length && buffer [start] != 0);
if (fileNames.length > 0) fileName = fileNames [0];
String separator = "";
int length = filterPath.length ();
if (length > 0 && filterPath.charAt (length - 1) != '\\') {
separator = "\\";
}
fullPath = filterPath + separator + fileName;
if (count < fileNames.length) {
String [] newFileNames = new String [count];
System.arraycopy (fileNames, 0, newFileNames, 0, count);
fileNames = newFileNames;
}
}
/* Free the memory that was allocated. */
OS.HeapFree (hHeap, 0, lpstrFile);
OS.HeapFree (hHeap, 0, lpstrFilter);
OS.HeapFree (hHeap, 0, lpstrInitialDir);
OS.HeapFree (hHeap, 0, lpstrTitle);
/* Restore the old cursor */
OS.SetCursor (hCursor);
/* Restore the old focus */
OS.SetFocus (hwndFocus);
/*
* This code is intentionally commented. On some
* platforms, the owner window is repainted right
* away when a dialog window exits. This behavior
* is currently unspecified.
*/
// if (hwndOwner != 0) OS.UpdateWindow (hwndOwner);
/* Answer the full path or null */
return fullPath;
}
public void setFileName (String string) {
fileName = string;
}
public void setFilterExtensions (String [] extensions) {
filterExtensions = extensions;
}
public void setFilterNames (String [] names) {
filterNames = names;
}
public void setFilterPath (String string) {
filterPath = string;
}
}