blob: 88592b3c27bed3217a87fe8fab7a311abf520650 [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.motif.*;
import org.eclipse.swt.*;
/**
* 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 {
int dialog;
String [] filterNames = new String [0];
String [] filterExtensions = new String [0];
String filterPath = "";
String fullPath = "";
String fileName = "";
boolean cancel = false;
static final String FILTER = "*";
/**
* Constructs a new instance of this class given only its
* parent.
* <p>
* Note: Currently, null can be passed in for the parent.
* This has the effect of creating the dialog on the currently active
* display if there is one. If there is no current display, the
* dialog is created on a "default" display. <b>Passing in null as
* the parent is not considered to be good coding style,
* and may not be supported in a future release of SWT.</b>
* </p>
*
* @param parent a shell which will be the parent of the new instance
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
* <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
* </ul>
*/
public FileDialog (Shell parent) {
this (parent, SWT.PRIMARY_MODAL);
}
/**
* Constructs a new instance of this class given its parent
* and a style value describing its behavior and appearance.
* <p>
* The style value is either one of the style constants defined in
* class <code>SWT</code> which is applicable to instances of this
* class, or must be built by <em>bitwise OR</em>'ing together
* (that is, using the <code>int</code> "|" operator) two or more
* of those <code>SWT</code> style constants. The class description
* for all SWT dialog classes should include a comment which
* describes the style constants which are applicable to the class.
* </p>
* Note: Currently, null can be passed in for the parent.
* This has the effect of creating the dialog on the currently active
* display if there is one. If there is no current display, the
* dialog is created on a "default" display. <b>Passing in null as
* the parent is not considered to be good coding style,
* and may not be supported in a future release of SWT.</b>
* </p>
*
* @param parent a shell which will be the parent of the new instance
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
* <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
* </ul>
*/
public FileDialog (Shell parent, int style) {
super (parent, style);
checkSubclass ();
}
int cancelPressed (int widget, int client, int call) {
cancel = true;
OS.XtUnmanageChild (widget);
return 0;
}
void extractValues() {
filterPath = fullPath = "";
int [] argList2 = {OS.XmNdirectory, 0, OS.XmNdirSpec, 0};
OS.XtGetValues (dialog, argList2, argList2.length / 2);
int xmString3 = argList2 [1];
int ptr = OS.XmStringUnparse (
xmString3,
null,
OS.XmCHARSET_TEXT,
OS.XmCHARSET_TEXT,
null,
0,
OS.XmOUTPUT_ALL);
if (ptr != 0) {
int length = OS.strlen (ptr);
byte [] buffer = new byte [length];
OS.memmove (buffer, ptr, length);
OS.XtFree (ptr);
/* Use the character encoding for the default locale */
filterPath = new String (Converter.mbcsToWcs (null, buffer));
}
OS.XmStringFree (xmString3);
int xmString4 = argList2 [3];
ptr = OS.XmStringUnparse (
xmString4,
null,
OS.XmCHARSET_TEXT,
OS.XmCHARSET_TEXT,
null,
0,
OS.XmOUTPUT_ALL);
if (ptr != 0) {
int length = OS.strlen (ptr);
byte [] buffer = new byte [length];
OS.memmove (buffer, ptr, length);
OS.XtFree (ptr);
/* Use the character encoding for the default locale */
fullPath = new String (Converter.mbcsToWcs (null, buffer));
}
OS.XmStringFree (xmString4);
int length = filterPath.length ();
if (length != 0 && filterPath.charAt (length - 1) == '/') {
filterPath = filterPath.substring (0, length - 1);
int index = fullPath.lastIndexOf ('/');
fileName = fullPath.substring (index + 1, fullPath.length ());
}
}
/**
* Returns the path of the first file that was
* selected in the dialog relative to the filter path,
* or null if none is available.
*
* @return the relative path of the file
*/
public String getFileName () {
return fileName;
}
/**
* Returns the paths of all files that were selected
* in the dialog relative to the filter path, or null
* if none are available.
*
* @return the relative paths of the files
*/
public String [] getFileNames () {
return new String [] {fileName};
}
/**
* Returns the file extensions which the dialog will
* use to filter the files it shows.
*
* @return the file extensions filter
*/
public String [] getFilterExtensions () {
return filterExtensions;
}
/**
* Returns the file names which the dialog will
* use to filter the files it shows.
*
* @return the file name filter
*/
public String [] getFilterNames () {
return filterNames;
}
/**
* Returns the path which the dialog will use to filter
* the files it shows.
*
* @return the filter path
*/
public String getFilterPath () {
return filterPath;
}
int okPressed (int widget, int client, int call) {
extractValues();
// preferred case, a file is selected
if (!fileName.equals("")) {
OS.XtUnmanageChild (widget);
return 0;
}
// no file selected, so go into the current directory
int [] argList1 = {OS.XmNdirMask, 0};
OS.XtGetValues (dialog, argList1, argList1.length / 2);
int directoryHandle = argList1[1];
int [] argList2 = {OS.XmNpattern,directoryHandle};
OS.XtSetValues (dialog, argList2, argList2.length / 2);
OS.XmStringFree (directoryHandle);
return 0;
}
/**
* Makes the dialog visible and brings it to the front
* of the display.
*
* @return a string describing the absolute path of the first selected file,
* or null if the dialog was cancelled or an error occurred
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the dialog has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the dialog</li>
* </ul>
*/
public String open () {
/* Get the parent */
boolean destroyContext;
Display appContext = Display.getCurrent ();
if (destroyContext = (appContext == null)) appContext = new Display ();
int display = appContext.xDisplay;
int parentHandle = appContext.shellHandle;
if ((parent != null) && (parent.getDisplay () == appContext))
parentHandle = parent.shellHandle;
/* Compute the dialog title */
/*
* Feature in Motif. It is not possible to set a shell
* title to an empty string. The fix is to set the title
* to be a single space.
*/
String string = title;
if (string.length () == 0) string = " ";
/* Use the character encoding for the default locale */
byte [] buffer1 = Converter.wcsToMbcs (null, string, true);
int xmStringPtr1 = OS.XmStringParseText (
buffer1,
0,
OS.XmFONTLIST_DEFAULT_TAG,
OS.XmCHARSET_TEXT,
null,
0,
0);
/* Compute the filter */
String mask = FILTER;
if (filterExtensions == null) filterExtensions = new String [0];
if (filterNames == null) filterNames = new String [0];
if (filterExtensions.length != 0) {
/* Motif does not support multiple filters, so ignore them
* if there are more than one, or if there is a ; separator.
*/
if (filterExtensions.length == 1) {
String filter = filterExtensions [0];
if (filter.indexOf (';', 0) == -1) mask = filter;
}
}
/* Use the character encoding for the default locale */
byte [] buffer2 = Converter.wcsToMbcs (null, mask, true);
int xmStringPtr2 = OS.XmStringParseText (
buffer2,
0,
OS.XmFONTLIST_DEFAULT_TAG,
OS.XmCHARSET_TEXT,
null,
0,
0);
/* Compute the filter path */
if (filterPath == null) filterPath = "";
/* Use the character encoding for the default locale */
byte [] buffer3 = Converter.wcsToMbcs (null, filterPath, true);
int xmStringPtr3 = OS.XmStringParseText (
buffer3,
0,
OS.XmFONTLIST_DEFAULT_TAG,
OS.XmCHARSET_TEXT,
null,
0,
0);
/* Create the dialog */
int [] argList1 = {
OS.XmNresizePolicy, OS.XmRESIZE_NONE,
OS.XmNdialogStyle, OS.XmDIALOG_PRIMARY_APPLICATION_MODAL,
OS.XmNwidth, OS.XDisplayWidth (display, OS.XDefaultScreen (display)) * 4 / 9,
OS.XmNdialogTitle, xmStringPtr1,
OS.XmNpattern, xmStringPtr2,
OS.XmNdirectory, xmStringPtr3,
};
/*
* Feature in Linux. For some reason, the XmCreateFileSelectionDialog()
* will not accept NULL for the widget name. This works fine on the other
* Motif platforms and in the other XmCreate calls on Linux. The fix is
* to pass in a NULL terminated string, not a NULL pointer.
*/
byte [] name = new byte [] {0};
dialog = OS.XmCreateFileSelectionDialog (parentHandle, name, argList1, argList1.length / 2);
int child = OS.XmFileSelectionBoxGetChild (dialog, OS.XmDIALOG_HELP_BUTTON);
if (child != 0) OS.XtUnmanageChild (child);
OS.XmStringFree (xmStringPtr1);
OS.XmStringFree (xmStringPtr2);
OS.XmStringFree (xmStringPtr3);
/*
string := OSWidget xmStringAt: XmNdirectory handle: dialog.
OSWidget xmStringAt: XmNdirSpec put: string, fileName handle: dialog.
"Select the matching file in the list and scroll to show it."
child := dialog xmFileSelectionBoxGetChild: XmDIALOGLIST.
child isNull ifFalse: [
string := OSWidget xmStringAt: XmNdirSpec handle: dialog.
string := PlatformConverter wcsToMbcs: 0 buffer: string.
xmString := OSXmString xmStringCreateLocalized: string asPSZ.
child
xmListSelectItem: xmString notify: false;
xmListSetItem: xmString.
xmString xmStringFree.
"Bug in Solaris. For some reason, the horizontal scroll bar in the dialog
list refuses to be displayed. This stops the dialog list from scrolling
horizontally and displaying the file names. This does not happen on other
Motif platforms. The fix is to force the horizontal scroll bar to be displayed
by explicitly setting the scroll bar display policy."
OSWidget resourceAt: XmNscrollBarDisplayPolicy put: XmSTATIC handle: child].
*/
/* Hook the callbacks. */
Callback cancelCallback = new Callback (this, "cancelPressed", 3);
int cancelAddress = cancelCallback.getAddress ();
OS.XtAddCallback (dialog, OS.XmNcancelCallback, cancelAddress, 0);
Callback okCallback = new Callback (this, "okPressed", 3);
int okAddress = okCallback.getAddress ();
OS.XtAddCallback (dialog, OS.XmNokCallback, okAddress, 0);
/*
shell == nil ifFalse: [
shell minimized ifTrue: [shell minimized: false]].
*/
OS.XtManageChild (dialog);
//BOGUS - should be a pure OS message loop (no SWT AppContext)
while (OS.XtIsRealized (dialog) && OS.XtIsManaged (dialog))
if (!appContext.readAndDispatch ()) appContext.sleep ();
/* Destroy the dialog and update the display. */
if (OS.XtIsRealized (dialog)) OS.XtDestroyWidget (dialog);
if (destroyContext) appContext.dispose ();
okCallback.dispose ();
cancelCallback.dispose ();
// (shell == nil or: [shell isDestroyed not]) ifTrue: [dialog xtDestroyWidget].
// OSWidget updateDisplay.
// entryPoint unbind.
if (cancel) return null;
return fullPath;
}
/**
* Set the initial filename which the dialog will
* select by default when opened to the argument,
* which may be null. The name will be prefixed with
* the filter path when one is supplied.
*
* @param string the file name
*/
public void setFileName (String string) {
fileName = string;
}
/**
* Set the file extensions which the dialog will
* use to filter the files it shows to the argument,
* which may be null.
*
* @param extensions the file extension filter
*/
public void setFilterExtensions (String [] extensions) {
filterExtensions = extensions;
}
/**
* Sets the file names which the dialog will
* use to filter the files it shows to the argument,
* which may be null.
*
* @param names the file name filter
*/
public void setFilterNames (String [] names) {
filterNames = names;
}
/**
* Sets the path which the dialog will use to filter
* the files it shows to the argument, which may be
* null.
*
* @param string the filter path
*/
public void setFilterPath (String string) {
filterPath = string;
}
}