提交 b5478b37 编写于 作者: D dcherepanov

6705345: Enable multiple file selection in AWT FileDialog

Reviewed-by: art, anthony, alexp
上级 8145b67f
......@@ -28,6 +28,8 @@ import java.awt.peer.FileDialogPeer;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.File;
import sun.awt.AWTAccessor;
/**
* The <code>FileDialog</code> class displays a dialog window
......@@ -93,6 +95,25 @@ public class FileDialog extends Dialog {
*/
String file;
/**
* Contains the File instances for all the files that the user selects.
*
* @serial
* @see getFiles
* @since 1.7
*/
private File[] files;
/**
* Represents whether the file dialog allows the multiple file selection.
*
* @serial
* @see #setMultipleMode
* @see #isMultipleMode
* @since 1.7
*/
private boolean multipleMode = false;
/*
* The filter used as the file dialog's filename filter.
* The file dialog will only be displaying files whose
......@@ -123,6 +144,26 @@ public class FileDialog extends Dialog {
}
}
static {
AWTAccessor.setFileDialogAccessor(
new AWTAccessor.FileDialogAccessor() {
public void setFiles(FileDialog fileDialog, String directory, String files[]) {
fileDialog.setFiles(directory, files);
}
public void setFile(FileDialog fileDialog, String file) {
fileDialog.file = ("".equals(file)) ? null : file;
}
public void setDirectory(FileDialog fileDialog, String directory) {
fileDialog.dir = ("".equals(directory)) ? null : directory;
}
public boolean isMultipleMode(FileDialog fileDialog) {
synchronized (fileDialog.getObjectLock()) {
return fileDialog.multipleMode;
}
}
});
}
/**
* Initialize JNI field and method IDs for fields that may be
accessed from C.
......@@ -370,6 +411,51 @@ public class FileDialog extends Dialog {
return file;
}
/**
* Returns files that the user selects.
* <p>
* If the user cancels the file dialog,
* then the method returns an empty array.
*
* @return files that the user selects or an empty array
* if the user cancels the file dialog.
* @see #setFile(String)
* @see #getFile
* @since 1.7
*/
public File[] getFiles() {
synchronized (getObjectLock()) {
if (files != null) {
return files.clone();
} else {
return new File[0];
}
}
}
/**
* Stores the names of all the files that the user selects.
*
* Note that the method is private and it's intended to be used
* by the peers through the AWTAccessor API.
*
* @param directory the current directory
* @param files the array that contains the short names of
* all the files that the user selects.
*
* @see #getFiles
* @since 1.7
*/
private void setFiles(String directory, String files[]) {
synchronized (getObjectLock()) {
int filesNumber = (files != null) ? files.length : 0;
this.files = new File[filesNumber];
for (int i = 0; i < filesNumber; i++) {
this.files[i] = new File(directory, files[i]);
}
}
}
/**
* Sets the selected file for this file dialog window to be the
* specified file. This file becomes the default file if it is set
......@@ -380,7 +466,8 @@ public class FileDialog extends Dialog {
* as the file.
*
* @param file the file being set
* @see java.awt.FileDialog#getFile
* @see #getFile
* @see #getFiles
*/
public void setFile(String file) {
this.file = (file != null && file.equals("")) ? null : file;
......@@ -390,6 +477,34 @@ public class FileDialog extends Dialog {
}
}
/**
* Enables or disables multiple file selection for the file dialog.
*
* @param enable if {@code true}, multiple file selection is enabled;
* {@code false} - disabled.
* @see #isMultipleMode
* @since 1.7
*/
public void setMultipleMode(boolean enable) {
synchronized (getObjectLock()) {
this.multipleMode = enable;
}
}
/**
* Returns whether the file dialog allows the multiple file selection.
*
* @return {@code true} if the file dialog allows the multiple
* file selection; {@code false} otherwise.
* @see #setMultipleMode
* @since 1.7
*/
public boolean isMultipleMode() {
synchronized (getObjectLock()) {
return multipleMode;
}
}
/**
* Determines this file dialog's filename filter. A filename filter
* allows the user to specify which files appear in the file dialog
......
......@@ -390,6 +390,30 @@ public final class AWTAccessor {
boolean isTrayIconPopup(PopupMenu popupMenu);
}
/*
* An accessor for the FileDialog class
*/
public interface FileDialogAccessor {
/*
* Sets the files the user selects
*/
void setFiles(FileDialog fileDialog, String directory, String files[]);
/*
* Sets the file the user selects
*/
void setFile(FileDialog fileDialog, String file);
/*
* Sets the directory the user selects
*/
void setDirectory(FileDialog fileDialog, String directory);
/*
* Returns whether the file dialog allows the multiple file selection.
*/
boolean isMultipleMode(FileDialog fileDialog);
}
/*
* The java.awt.Component class accessor object.
......@@ -431,6 +455,11 @@ public final class AWTAccessor {
*/
private static PopupMenuAccessor popupMenuAccessor;
/*
* The java.awt.FileDialog class accessor object.
*/
private static FileDialogAccessor fileDialogAccessor;
/*
* Set an accessor object for the java.awt.Component class.
*/
......@@ -567,4 +596,22 @@ public final class AWTAccessor {
}
return popupMenuAccessor;
}
/*
* Set an accessor object for the java.awt.FileDialog class.
*/
public static void setFileDialogAccessor(FileDialogAccessor fda) {
fileDialogAccessor = fda;
}
/*
* Retrieve the accessor object for the java.awt.FileDialog class.
*/
public static FileDialogAccessor getFileDialogAccessor() {
if (fileDialogAccessor == null) {
unsafe.ensureClassInitialized(FileDialog.class);
}
return fileDialogAccessor;
}
}
......@@ -37,6 +37,7 @@ import javax.swing.plaf.ComponentUI;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.util.logging.PlatformLogger;
import sun.awt.AWTAccessor;
class XFileDialogPeer extends XDialogPeer implements FileDialogPeer, ActionListener, ItemListener, KeyEventDispatcher, XChoicePeerListener {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XFileDialogPeer");
......@@ -171,6 +172,10 @@ class XFileDialogPeer extends XDialogPeer implements FileDialogPeer, ActionListe
filterField = new TextField();
selectionField = new TextField();
boolean isMultipleMode =
AWTAccessor.getFileDialogAccessor().isMultipleMode(target);
fileList.setMultipleMode(isMultipleMode);
// the insets used by the components in the fileDialog
Insets noInset = new Insets(0, 0, 0, 0);
Insets textFieldInset = new Insets(0, 8, 0, 8);
......@@ -380,7 +385,8 @@ class XFileDialogPeer extends XDialogPeer implements FileDialogPeer, ActionListe
* handle the selection event
*/
void handleSelection(String file) {
int index = file.lastIndexOf('/');
int index = file.lastIndexOf(java.io.File.separatorChar);
if (index == -1) {
savedDir = this.dir;
......@@ -389,8 +395,12 @@ class XFileDialogPeer extends XDialogPeer implements FileDialogPeer, ActionListe
savedDir = file.substring(0, index+1);
savedFile = file.substring(index+1);
}
target.setDirectory(savedDir);
target.setFile(savedFile);
AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor();
fileDialogAccessor.setDirectory(target, savedDir);
fileDialogAccessor.setFile(target, savedFile);
fileDialogAccessor.setFiles(target, savedDir, fileList.getSelectedItems());
}
/**
......@@ -404,8 +414,13 @@ class XFileDialogPeer extends XDialogPeer implements FileDialogPeer, ActionListe
setFilterField(null);
directoryList.clear();
fileList.clear();
target.setFile(null);
target.setDirectory(null);
AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor();
fileDialogAccessor.setDirectory(target, null);
fileDialogAccessor.setFile(target, null);
fileDialogAccessor.setFiles(target, null, null);
handleQuitButton();
}
......
......@@ -117,24 +117,55 @@ public class WFileDialogPeer extends WWindowPeer implements FileDialogPeer {
}
}
// NOTE: This method is called by privileged threads.
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
void handleSelected(final String file) {
final FileDialog fileDialog = (FileDialog)target;
WToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() {
public void run() {
int index = file.lastIndexOf(java.io.File.separatorChar);/*2509*//*ibm*/
String dir;
/*
* The function converts the file names (the buffer parameter)
* in the Windows format into the Java format and saves the results
* into the FileDialog instance.
*
* If it's the multi-select mode, the buffer contains the current
* directory followed by the short names of the files.
* The directory and file name strings are NULL separated.
* If it's the single-select mode, the buffer doesn't have the NULL
* separator between the path and the file name.
*
* NOTE: This method is called by privileged threads.
* DO NOT INVOKE CLIENT CODE ON THIS THREAD!
*/
void handleSelected(final char[] buffer)
{
String[] wFiles = (new String(buffer)).split("\0"); // NULL is the delimiter
boolean multiple = (wFiles.length > 1);
String jDirectory = null;
String jFile = null;
String jFiles[] = null;
if (multiple) {
jDirectory = wFiles[0];
jFiles = new String[wFiles.length - 1];
System.arraycopy(wFiles, 1, jFiles, 0, jFiles.length);
jFile = jFiles[1]; // choose any file
} else {
int index = wFiles[0].lastIndexOf(java.io.File.separatorChar);
if (index == -1) {
dir = "."+java.io.File.separator;
fileDialog.setFile(file);
jDirectory = "."+java.io.File.separator;
jFile = wFiles[0];
} else {
jDirectory = wFiles[0].substring(0, index + 1);
jFile = wFiles[0].substring(index + 1);
}
else {
dir = file.substring(0, index + 1);
fileDialog.setFile(file.substring(index + 1));
jFiles = new String[] { jFile };
}
fileDialog.setDirectory(dir);
final FileDialog fileDialog = (FileDialog)target;
AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor();
fileDialogAccessor.setDirectory(fileDialog, jDirectory);
fileDialogAccessor.setFile(fileDialog, jFile);
fileDialogAccessor.setFiles(fileDialog, jDirectory, jFiles);
WToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() {
public void run() {
fileDialog.hide();
}
});
......@@ -144,9 +175,12 @@ public class WFileDialogPeer extends WWindowPeer implements FileDialogPeer {
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
void handleCancel() {
final FileDialog fileDialog = (FileDialog)target;
AWTAccessor.getFileDialogAccessor().setFile(fileDialog, null);
AWTAccessor.getFileDialogAccessor().setFiles(fileDialog, null, null);
WToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() {
public void run() {
fileDialog.setFile(null);
fileDialog.hide();
}
});
......@@ -244,4 +278,9 @@ public class WFileDialogPeer extends WWindowPeer implements FileDialogPeer {
public void createScreenSurface(boolean isResize) {}
@Override
public void replaceSurfaceData() {}
public boolean isMultipleMode() {
FileDialog fileDialog = (FileDialog)target;
return AWTAccessor.getFileDialogAccessor().isMultipleMode(fileDialog);
}
}
......@@ -44,6 +44,7 @@ jmethodID AwtFileDialog::setHWndMID;
jmethodID AwtFileDialog::handleSelectedMID;
jmethodID AwtFileDialog::handleCancelMID;
jmethodID AwtFileDialog::checkFilenameFilterMID;
jmethodID AwtFileDialog::isMultipleModeMID;
/* FileDialog ids */
jfieldID AwtFileDialog::modeID;
......@@ -57,6 +58,13 @@ static TCHAR s_fileFilterString[MAX_FILTER_STRING];
/* Non-localized suffix of the filter string */
static const TCHAR s_additionalString[] = TEXT(" (*.*)\0*.*\0");
// Default limit of the output buffer.
#define SINGLE_MODE_BUFFER_LIMIT MAX_PATH+1
#define MULTIPLE_MODE_BUFFER_LIMIT 32768
// The name of the property holding the pointer to the OPENFILENAME structure.
static LPCTSTR OpenFileNameProp = TEXT("AWT_OFN");
/***********************************************************************/
void
......@@ -140,6 +148,8 @@ FileDialogHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
FileDialogWndProc);
::SetProp(parent, NativeDialogWndProcProp, reinterpret_cast<HANDLE>(lpfnWndProc));
::SetProp(parent, OpenFileNameProp, (void *)lParam);
break;
}
case WM_DESTROY: {
......@@ -149,6 +159,7 @@ FileDialogHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
lpfnWndProc);
::RemoveProp(parent, ModalDialogPeerProp);
::RemoveProp(parent, NativeDialogWndProcProp);
::RemoveProp(parent, OpenFileNameProp);
break;
}
case WM_NOTIFY: {
......@@ -174,6 +185,30 @@ FileDialogHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
// to unblock all the windows blocked by this dialog as it will
// be closed soon
env->CallVoidMethod(peer, AwtFileDialog::setHWndMID, (jlong)0);
} else if (notifyEx->hdr.code == CDN_SELCHANGE) {
// reallocate the buffer if the buffer is too small
LPOPENFILENAME lpofn = (LPOPENFILENAME)GetProp(parent, OpenFileNameProp);
UINT nLength = CommDlg_OpenSave_GetSpec(parent, NULL, 0) +
CommDlg_OpenSave_GetFolderPath(parent, NULL, 0);
if (lpofn->nMaxFile < nLength)
{
// allocate new buffer
LPTSTR newBuffer = new TCHAR[nLength];
if (newBuffer) {
memset(newBuffer, 0, nLength * sizeof(TCHAR));
LPTSTR oldBuffer = lpofn->lpstrFile;
lpofn->lpstrFile = newBuffer;
lpofn->nMaxFile = nLength;
// free the previously allocated buffer
if (oldBuffer) {
delete[] oldBuffer;
}
}
}
}
}
break;
......@@ -193,7 +228,6 @@ AwtFileDialog::Show(void *p)
WCHAR unicodeChar = L' ';
LPTSTR fileBuffer = NULL;
LPTSTR currentDirectory = NULL;
OPENFILENAME ofn;
jint mode = 0;
BOOL result = FALSE;
DWORD dlgerr;
......@@ -204,6 +238,10 @@ AwtFileDialog::Show(void *p)
jobject target = NULL;
jobject parent = NULL;
AwtComponent* awtParent = NULL;
jboolean multipleMode = JNI_FALSE;
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
/*
* There's a situation (see bug 4906972) when InvokeFunction (by which this method is called)
......@@ -233,7 +271,16 @@ AwtFileDialog::Show(void *p)
(jstring)env->GetObjectField(target, AwtFileDialog::dirID);
JavaStringBuffer directoryBuffer(env, directory);
fileBuffer = new TCHAR[MAX_PATH+1];
multipleMode = env->CallBooleanMethod(peer, AwtFileDialog::isMultipleModeMID);
UINT bufferLimit;
if (multipleMode == JNI_TRUE) {
bufferLimit = MULTIPLE_MODE_BUFFER_LIMIT;
} else {
bufferLimit = SINGLE_MODE_BUFFER_LIMIT;
}
LPTSTR fileBuffer = new TCHAR[bufferLimit];
memset(fileBuffer, 0, bufferLimit * sizeof(TCHAR));
file = (jstring)env->GetObjectField(target, AwtFileDialog::fileID);
if (file != NULL) {
......@@ -244,8 +291,6 @@ AwtFileDialog::Show(void *p)
fileBuffer[0] = _T('\0');
}
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFilter = s_fileFilterString;
ofn.nFilterIndex = 1;
......@@ -265,7 +310,7 @@ AwtFileDialog::Show(void *p)
ofn.hwndOwner = NULL;
}
ofn.lpstrFile = fileBuffer;
ofn.nMaxFile = MAX_PATH;
ofn.nMaxFile = bufferLimit;
ofn.lpstrTitle = titleBuffer;
ofn.lpstrInitialDir = directoryBuffer;
ofn.Flags = OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY |
......@@ -278,6 +323,10 @@ AwtFileDialog::Show(void *p)
ofn.lCustData = (LPARAM)peer;
ofn.lpfnHook = (LPOFNHOOKPROC)FileDialogHookProc;
if (multipleMode == JNI_TRUE) {
ofn.Flags |= OFN_ALLOWMULTISELECT;
}
// Save current directory, so we can reset if it changes.
currentDirectory = new TCHAR[MAX_PATH+1];
......@@ -318,11 +367,12 @@ AwtFileDialog::Show(void *p)
// Report result to peer.
if (result) {
jstring tmpJString = (_tcslen(ofn.lpstrFile) == 0 ?
JNU_NewStringPlatform(env, L"") :
JNU_NewStringPlatform(env, ofn.lpstrFile));
env->CallVoidMethod(peer, AwtFileDialog::handleSelectedMID, tmpJString);
env->DeleteLocalRef(tmpJString);
jint length = (jint)GetBufferLength(ofn.lpstrFile, ofn.nMaxFile);
jcharArray jnames = env->NewCharArray(length);
env->SetCharArrayRegion(jnames, 0, length, (jchar*)ofn.lpstrFile);
env->CallVoidMethod(peer, AwtFileDialog::handleSelectedMID, jnames);
env->DeleteLocalRef(jnames);
} else {
env->CallVoidMethod(peer, AwtFileDialog::handleCancelMID);
}
......@@ -338,7 +388,8 @@ AwtFileDialog::Show(void *p)
env->DeleteGlobalRef(peer);
delete[] currentDirectory;
delete[] fileBuffer;
if (ofn.lpstrFile)
delete[] ofn.lpstrFile;
throw;
}
......@@ -351,7 +402,8 @@ AwtFileDialog::Show(void *p)
env->DeleteGlobalRef(peer);
delete[] currentDirectory;
delete[] fileBuffer;
if (ofn.lpstrFile)
delete[] ofn.lpstrFile;
}
BOOL
......@@ -416,6 +468,18 @@ void AwtFileDialog::_ToBack(void *param)
env->DeleteGlobalRef(self);
}
// Returns the length of the double null terminated output buffer
UINT AwtFileDialog::GetBufferLength(LPTSTR buffer, UINT limit)
{
UINT index = 0;
while ((index < limit) &&
(buffer[index] != NULL || buffer[index+1] != NULL))
{
index++;
}
return index;
}
/************************************************************************
* WFileDialogPeer native methods
*/
......@@ -434,11 +498,12 @@ Java_sun_awt_windows_WFileDialogPeer_initIDs(JNIEnv *env, jclass cls)
AwtFileDialog::setHWndMID =
env->GetMethodID(cls, "setHWnd", "(J)V");
AwtFileDialog::handleSelectedMID =
env->GetMethodID(cls, "handleSelected", "(Ljava/lang/String;)V");
env->GetMethodID(cls, "handleSelected", "([C)V");
AwtFileDialog::handleCancelMID =
env->GetMethodID(cls, "handleCancel", "()V");
AwtFileDialog::checkFilenameFilterMID =
env->GetMethodID(cls, "checkFilenameFilter", "(Ljava/lang/String;)Z");
AwtFileDialog::isMultipleModeMID = env->GetMethodID(cls, "isMultipleMode", "()Z");
/* java.awt.FileDialog fields */
cls = env->FindClass("java/awt/FileDialog");
......@@ -455,6 +520,7 @@ Java_sun_awt_windows_WFileDialogPeer_initIDs(JNIEnv *env, jclass cls)
DASSERT(AwtFileDialog::setHWndMID != NULL);
DASSERT(AwtFileDialog::handleSelectedMID != NULL);
DASSERT(AwtFileDialog::handleCancelMID != NULL);
DASSERT(AwtFileDialog::isMultipleModeMID != NULL);
DASSERT(AwtFileDialog::modeID != NULL);
DASSERT(AwtFileDialog::dirID != NULL);
......
......@@ -49,6 +49,7 @@ public:
static jmethodID handleSelectedMID;
static jmethodID handleCancelMID;
static jmethodID checkFilenameFilterMID;
static jmethodID isMultipleModeMID;
/* java.awt.FileDialog field and method ids */
static jfieldID modeID;
......@@ -68,6 +69,9 @@ public:
static void _DisposeOrHide(void *param);
static void _ToFront(void *param);
static void _ToBack(void *param);
private:
static UINT GetBufferLength(LPTSTR buffer, UINT limit);
};
#endif /* FILE_DIALOG_H */
<html>
<!--
@test
@bug 6467204
@summary Need to implement "extended" native FileDialog for JFileChooser
@author dmitry.cherepanov@sun.com area=awt.filedialog
@run applet/manual=yesno MultipleMode.html
-->
<head>
<title> MultipleMode </title>
</head>
<body>
<h1>MultipleMode<br>Bug ID: 6467204</h1>
<p> See the dialog box (usually in upper left corner) for instructions</p>
<APPLET CODE="MultipleMode.class" WIDTH=200 HEIGHT=200></APPLET>
</body>
</html>
/*
* Copyright 2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
test
@bug 6467204
@summary Need to implement "extended" native FileDialog for JFileChooser
@author dmitry.cherepanov@sun.com area=awt.filedialog
@run applet/manual=yesno MultipleMode.html
*/
// Note there is no @ in front of test above. This is so that the
// harness will not mistake this file as a test file. It should
// only see the html file as a test file. (the harness runs all
// valid test files, so it would run this test twice if this file
// were valid as well as the html file.)
// Also, note the area= after Your Name in the author tag. Here, you
// should put which functional area the test falls in. See the
// AWT-core home page -> test areas and/or -> AWT team for a list of
// areas.
// There are several places where ManualYesNoTest appear. It is
// recommended that these be changed by a global search and replace,
// such as ESC-% in xemacs.
/**
* MultipleMode.java
*
* summary:
*/
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
//Manual tests should run as applet tests if possible because they
// get their environments cleaned up, including AWT threads, any
// test created threads, and any system resources used by the test
// such as file descriptors. (This is normally not a problem as
// main tests usually run in a separate VM, however on some platforms
// such as the Mac, separate VMs are not possible and non-applet
// tests will cause problems). Also, you don't have to worry about
// synchronisation stuff in Applet tests the way you do in main
// tests...
public class MultipleMode extends Applet
{
//Declare things used in the test, like buttons and labels here
public void init()
{
//Create instructions for the user here, as well as set up
// the environment -- set the layout manager, add buttons,
// etc.
this.setLayout (new BorderLayout ());
String[] instructions =
{
" 1. Turn the 'multiple' checkbox off and press the 'open' button ",
" 2. Verify that the file dialog doesn't allow the multiple file selection ",
" 3. Select any file and close the file dialog ",
" 4. The results will be displayed, verify the results ",
" 5. Turn the 'multiple' checkbox on and press the 'open' button ",
" 6. Verify that the file dialog allows the multiple file selection ",
" 7. Select several files and close the file dialog ",
" 8. The results will be displayed, verify the results "
};
Sysout.createDialogWithInstructions( instructions );
}//End init()
public void start ()
{
final Checkbox mode = new Checkbox("multiple", true);
Button open = new Button("open");
open.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
FileDialog d = new FileDialog((Frame)null);
d.setMultipleMode(mode.getState());
d.setVisible(true);
// print the results
Sysout.println("DIR:");
Sysout.println(d.getDirectory());
Sysout.println("FILE:");
Sysout.println(d.getFile());
Sysout.println("FILES:");
File files[] = d.getFiles();
for (File f : files) {
Sysout.println(String.valueOf(f));
}
}
});
setLayout(new FlowLayout());
add(mode);
add(open);
//Get things going. Request focus, set size, et cetera
setSize (200,200);
setVisible(true);
validate();
}// start()
//The rest of this class is the actions which perform the test...
//Use Sysout.println to communicate with the user NOT System.out!!
//Sysout.println ("Something Happened!");
}// class ManualYesNoTest
/* Place other classes related to the test after this line */
/****************************************************
Standard Test Machinery
DO NOT modify anything below -- it's a standard
chunk of code whose purpose is to make user
interaction uniform, and thereby make it simpler
to read and understand someone else's test.
****************************************************/
/**
This is part of the standard test machinery.
It creates a dialog (with the instructions), and is the interface
for sending text messages to the user.
To print the instructions, send an array of strings to Sysout.createDialog
WithInstructions method. Put one line of instructions per array entry.
To display a message for the tester to see, simply call Sysout.println
with the string to be displayed.
This mimics System.out.println but works within the test harness as well
as standalone.
*/
class Sysout
{
private static TestDialog dialog;
private static boolean numbering = false;
private static int messageNumber = 0;
public static void createDialogWithInstructions( String[] instructions )
{
dialog = new TestDialog( new Frame(), "Instructions" );
dialog.printInstructions( instructions );
dialog.setVisible(true);
println( "Any messages for the tester will display here." );
}
public static void createDialog( )
{
dialog = new TestDialog( new Frame(), "Instructions" );
String[] defInstr = { "Instructions will appear here. ", "" } ;
dialog.printInstructions( defInstr );
dialog.setVisible(true);
println( "Any messages for the tester will display here." );
}
/* Enables message counting for the tester. */
public static void enableNumbering(boolean enable){
numbering = enable;
}
public static void printInstructions( String[] instructions )
{
dialog.printInstructions( instructions );
}
public static void println( String messageIn )
{
if (numbering) {
messageIn = "" + messageNumber + " " + messageIn;
messageNumber++;
}
dialog.displayMessage( messageIn );
}
}// Sysout class
/**
This is part of the standard test machinery. It provides a place for the
test instructions to be displayed, and a place for interactive messages
to the user to be displayed.
To have the test instructions displayed, see Sysout.
To have a message to the user be displayed, see Sysout.
Do not call anything in this dialog directly.
*/
class TestDialog extends Dialog
{
TextArea instructionsText;
TextArea messageText;
int maxStringLength = 80;
//DO NOT call this directly, go through Sysout
public TestDialog( Frame frame, String name )
{
super( frame, name );
int scrollBoth = TextArea.SCROLLBARS_BOTH;
instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth );
add( "North", instructionsText );
messageText = new TextArea( "", 5, maxStringLength, scrollBoth );
add("Center", messageText);
pack();
setVisible(true);
}// TestDialog()
//DO NOT call this directly, go through Sysout
public void printInstructions( String[] instructions )
{
//Clear out any current instructions
instructionsText.setText( "" );
//Go down array of instruction strings
String printStr, remainingStr;
for( int i=0; i < instructions.length; i++ )
{
//chop up each into pieces maxSringLength long
remainingStr = instructions[ i ];
while( remainingStr.length() > 0 )
{
//if longer than max then chop off first max chars to print
if( remainingStr.length() >= maxStringLength )
{
//Try to chop on a word boundary
int posOfSpace = remainingStr.
lastIndexOf( ' ', maxStringLength - 1 );
if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1;
printStr = remainingStr.substring( 0, posOfSpace + 1 );
remainingStr = remainingStr.substring( posOfSpace + 1 );
}
//else just print
else
{
printStr = remainingStr;
remainingStr = "";
}
instructionsText.append( printStr + "\n" );
}// while
}// for
}//printInstructions()
//DO NOT call this directly, go through Sysout
public void displayMessage( String messageIn )
{
messageText.append( messageIn + "\n" );
System.out.println(messageIn);
}
}// TestDialog class
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册