Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update multi selection #23

Merged
merged 1 commit into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions api/src/main/java/jnafilechooser/api/JnaFileChooser.java
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,11 @@ private boolean showDialog(Window parent, Action action) {
// CDN_SELCHANGE: http://msdn.microsoft.com/en-us/library/ms646865.aspx
// SendMessage: http://msdn.microsoft.com/en-us/library/ms644950.aspx
}
else if (!multiSelectionEnabled) {
if (mode == Mode.Files) {
return showWindowsFileChooser(parent, action);
}
else if (mode == Mode.Directories) {
return showWindowsFolderBrowser(parent);
}
if (mode == Mode.Files) {
return showWindowsFileChooser(parent, action);
}
else if (mode == Mode.Directories) {
return showWindowsFolderBrowser(parent);
}
}

Expand Down Expand Up @@ -223,7 +221,7 @@ private boolean showSwingFileChooser(Window parent, Action action) {
private boolean showWindowsFileChooser(Window parent, Action action) {
final WindowsFileChooser fc = new WindowsFileChooser(currentDirectory);
fc.setFilters(filters);

fc.setMultiSelectionEnabled(multiSelectionEnabled);
if (!defaultFile.isEmpty())
fc.setDefaultFilename(defaultFile);

Expand All @@ -233,7 +231,7 @@ private boolean showWindowsFileChooser(Window parent, Action action) {

final boolean result = fc.showDialog(parent, action == Action.Open);
if (result) {
selectedFiles = new File[] { fc.getSelectedFile() };
selectedFiles = multiSelectionEnabled ? fc.getSelectedFiles() : new File[]{fc.getSelectedFile()};
currentDirectory = fc.getCurrentDirectory();
}
return result;
Expand Down Expand Up @@ -310,7 +308,7 @@ public void setDefaultFileName(String dfile) {
* set a title name
*
* @param Title of dialog
*
*
*/
public void setTitle(String title) {
this.dialogTitle = title;
Expand All @@ -320,7 +318,7 @@ public void setTitle(String title) {
* set a open button name
*
* @param open button text
*
*
*/
public void setOpenButtonText(String buttonText) {
this.openButtonText = buttonText;
Expand All @@ -330,7 +328,7 @@ public void setOpenButtonText(String buttonText) {
* set a save button name
*
* @param save button text
*
*
*/
public void setSaveButtonText(String buttonText) {
this.saveButtonText = buttonText;
Expand Down
126 changes: 117 additions & 9 deletions api/src/main/java/jnafilechooser/api/WindowsFileChooser.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@

import java.awt.Window;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import jnafilechooser.win32.Comdlg32;

Expand Down Expand Up @@ -77,13 +80,20 @@
*/
public class WindowsFileChooser
{
public static final int MAX_PATH = 260;
protected File selectedFile;
protected File currentDirectory;
protected ArrayList<String[]> filters;

protected String defaultFilename = "";
protected String dialogTitle = "";

private int filterIndex = 1;
private boolean addToRecent = false;
private boolean multipleSelection = false;
private int maxNumberOfFiles = 10000;
private File[] selectedFiles = null;

/**
* creates a new file chooser
*/
Expand Down Expand Up @@ -195,16 +205,25 @@ boolean showDialog(Window parent, boolean open) {

params.hwndOwner = parent == null ? null : Native.getWindowPointer(parent);

if (!addToRecent) {
params.Flags = params.Flags | Comdlg32.OFN_DONTADDTORECENT;
}

if (multipleSelection) {
params.Flags = params.Flags | Comdlg32.OFN_ALLOWMULTISELECT;
}

// lpstrFile contains the selection path after the dialog
// returns. It must be big enough for the path to fit or
// GetOpenFileName returns an error (FNERR_BUFFERTOOSMALL).
// MAX_PATH is 260 so 4*260+1 bytes should be big enough (I hope...)
// http://msdn.microsoft.com/en-us/library/aa365247.aspx#maxpath
final int bufferLength = 260;
final int bufferLength = multipleSelection ? maxNumberOfFiles * MAX_PATH : MAX_PATH;
// 4 bytes per char + 1 null byte
final int bufferSize = 4 * bufferLength + 1;
params.lpstrFile = new Memory(bufferSize);
if (!defaultFilename.isEmpty()) {

if (open & !defaultFilename.isEmpty()) {
params.lpstrFile.setWideString(0, defaultFilename);
} else {
params.lpstrFile.clear(bufferSize);
Expand Down Expand Up @@ -232,19 +251,55 @@ boolean showDialog(Window parent, boolean open) {
// build filter string if filters were specified
if (filters.size() > 0) {
params.lpstrFilter = new WString(buildFilterString());
params.nFilterIndex = 1; // TODO don't hardcode here
params.nFilterIndex = filterIndex;
}

final boolean approved = open ?
Comdlg32.GetOpenFileNameW(params) :
Comdlg32.GetSaveFileNameW(params);

if (approved) {
final String filePath = params.lpstrFile.getWideString(0);
selectedFile = new File(filePath);
final File dir = selectedFile.getParentFile();
currentDirectory = dir;
}
// clear selection
selectedFiles = null;

if (approved) {
// nFilterIndex is updated if user changed the selected filter
filterIndex = params.nFilterIndex;

if (multipleSelection) {
final byte[] bytes = params.lpstrFile.getByteArray(0, bufferSize);

final List<String> filePaths = bytesToFilePaths(bytes);
if (filePaths.size() == 1) {

selectedFile = new File(filePaths.get(0));
final File dir = selectedFile.getParentFile();
currentDirectory = dir;

selectedFiles = new File[1];
selectedFiles[0] = selectedFile;

} else if (filePaths.size() > 1) {

selectedFiles = new File[filePaths.size() - 1];

currentDirectory = new File(filePaths.get(0));

for (int i = 1; i < filePaths.size(); i++) {
selectedFiles[i - 1] = new File(currentDirectory, filePaths.get(i));
}
selectedFile = selectedFiles[0];
}
} else {
final String filePath = params.lpstrFile.getWideString(0);

selectedFile = new File(filePath);
final File dir = selectedFile.getParentFile();
currentDirectory = dir;

selectedFiles = new File[1];
selectedFiles[0] = selectedFile;
}
}
else {
final int errCode = Comdlg32.CommDlgExtendedError();
// if the code is 0 the user clicked cancel
Expand Down Expand Up @@ -319,4 +374,57 @@ public File getCurrentDirectory() {
public void setDefaultFilename(String defaultFilename) {
this.defaultFilename = defaultFilename;
}

public int getFilterIndex() {
return filterIndex;
}

public void setFilterIndex(int filterIndex) {
this.filterIndex = filterIndex;
}

public boolean isAddToRecent() {
return addToRecent;
}

public void setAddToRecent(boolean addToRecent) {
this.addToRecent = addToRecent;
}

public boolean isMultipleSelection() {
return multipleSelection;
}

public void setMultiSelectionEnabled(boolean multipleSelection) {
this.multipleSelection = multipleSelection;
}

public int getMaxNumberOfFiles() {
return maxNumberOfFiles;
}

public void setMaxNumberOfFiles(int maxNumberOfFiles) {
this.maxNumberOfFiles = maxNumberOfFiles;
}

public File[] getSelectedFiles() {
return selectedFiles;
}

public static List<String> bytesToFilePaths(byte[] bytes) {
final List<String> filePaths = new ArrayList<>();
int from = 0;
for (int i = 0; i < bytes.length - 1; i += 2) {
if (bytes[i] == 0 && bytes[i + 1] == 0) {
if (i > from) {
filePaths.add(new String(Arrays.copyOfRange(bytes, from, i),
StandardCharsets.UTF_16LE)); //UTF 2-bytes little-endian CharSet seems to work...
from = i + 2;
} else {
break;
}
}
}
return filePaths;
}
}