added sorting, some fixes
This commit is contained in:
parent
2f87dd0a75
commit
a67b92b015
@ -59,6 +59,11 @@ public class FilePanelTab extends JPanel {
|
||||
private int sortColumn = -1; // 0=name,1=size,2=date
|
||||
private boolean sortAscending = true;
|
||||
private cz.kamma.kfmanager.config.AppConfig persistedConfig;
|
||||
// Sorting buttons for BRIEF mode
|
||||
private JPanel briefSortPanel;
|
||||
private JButton sortByNameButton;
|
||||
private JButton sortByDateButton;
|
||||
private JButton sortBySizeButton;
|
||||
// Track last selection to restore it if focus is requested on empty area
|
||||
private int lastValidRow = 0;
|
||||
private int lastValidBriefColumn = 0;
|
||||
@ -810,6 +815,84 @@ public class FilePanelTab extends JPanel {
|
||||
}
|
||||
});
|
||||
|
||||
// Create sorting buttons panel for BRIEF mode with GridLayout for full width
|
||||
briefSortPanel = new JPanel(new GridLayout(1, 3, 0, 0));
|
||||
briefSortPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
|
||||
|
||||
sortByNameButton = new JButton("Name");
|
||||
sortByDateButton = new JButton("Date");
|
||||
sortBySizeButton = new JButton("Size");
|
||||
|
||||
// Set buttons to minimal height
|
||||
sortByNameButton.setPreferredSize(new Dimension(0, 20));
|
||||
sortByDateButton.setPreferredSize(new Dimension(0, 20));
|
||||
sortBySizeButton.setPreferredSize(new Dimension(0, 20));
|
||||
|
||||
briefSortPanel.add(sortByNameButton);
|
||||
briefSortPanel.add(sortByDateButton);
|
||||
briefSortPanel.add(sortBySizeButton);
|
||||
briefSortPanel.setVisible(false); // Hidden by default, shown only in BRIEF mode
|
||||
briefSortPanel.setPreferredSize(new Dimension(0, 20));
|
||||
|
||||
// Setup sorting button listeners
|
||||
sortByNameButton.addActionListener(e -> {
|
||||
if (sortColumn == 0) {
|
||||
sortAscending = !sortAscending;
|
||||
} else {
|
||||
sortColumn = 0;
|
||||
sortAscending = true;
|
||||
}
|
||||
sortItemsByColumn(sortColumn, sortAscending);
|
||||
tableModel.fireTableDataChanged();
|
||||
updateStatus();
|
||||
updateSortButtonsDisplay();
|
||||
if (persistedConfig != null) {
|
||||
persistedConfig.setDefaultSortColumn(sortColumn);
|
||||
persistedConfig.setDefaultSortAscending(sortAscending);
|
||||
persistedConfig.saveConfig();
|
||||
}
|
||||
fileTable.requestFocus();
|
||||
});
|
||||
|
||||
sortByDateButton.addActionListener(e -> {
|
||||
if (sortColumn == 2) {
|
||||
sortAscending = !sortAscending;
|
||||
} else {
|
||||
sortColumn = 2;
|
||||
sortAscending = false; // Default: newest first
|
||||
}
|
||||
sortItemsByColumn(sortColumn, sortAscending);
|
||||
tableModel.fireTableDataChanged();
|
||||
updateStatus();
|
||||
updateSortButtonsDisplay();
|
||||
if (persistedConfig != null) {
|
||||
persistedConfig.setDefaultSortColumn(sortColumn);
|
||||
persistedConfig.setDefaultSortAscending(sortAscending);
|
||||
persistedConfig.saveConfig();
|
||||
}
|
||||
fileTable.requestFocus();
|
||||
});
|
||||
|
||||
sortBySizeButton.addActionListener(e -> {
|
||||
if (sortColumn == 1) {
|
||||
sortAscending = !sortAscending;
|
||||
} else {
|
||||
sortColumn = 1;
|
||||
sortAscending = false; // Default: largest first
|
||||
}
|
||||
sortItemsByColumn(sortColumn, sortAscending);
|
||||
tableModel.fireTableDataChanged();
|
||||
updateStatus();
|
||||
updateSortButtonsDisplay();
|
||||
if (persistedConfig != null) {
|
||||
persistedConfig.setDefaultSortColumn(sortColumn);
|
||||
persistedConfig.setDefaultSortAscending(sortAscending);
|
||||
persistedConfig.saveConfig();
|
||||
}
|
||||
fileTable.requestFocus();
|
||||
});
|
||||
|
||||
add(briefSortPanel, BorderLayout.NORTH);
|
||||
add(cardPanel, BorderLayout.CENTER);
|
||||
|
||||
// Status bar
|
||||
@ -1222,7 +1305,20 @@ public class FilePanelTab extends JPanel {
|
||||
}
|
||||
|
||||
List<FileItem> items = (preloadedItems != null) ? preloadedItems : createFileItemList(directory);
|
||||
tableModel.setItems(items);
|
||||
|
||||
// Only update the model if items have actually changed
|
||||
boolean itemsChanged = !isSameContent(items, tableModel.items);
|
||||
if (itemsChanged) {
|
||||
tableModel.setItems(items);
|
||||
} else {
|
||||
// Items haven't changed, but we might still need to apply sort or revalidate
|
||||
tableModel.items = items;
|
||||
}
|
||||
|
||||
// Apply saved sort settings to newly loaded items
|
||||
if (sortColumn >= 0) {
|
||||
sortItemsByColumn(sortColumn, sortAscending);
|
||||
}
|
||||
|
||||
if (viewMode == ViewMode.BRIEF) {
|
||||
boolean selectFirst = autoSelectFirst;
|
||||
@ -1346,6 +1442,8 @@ public class FilePanelTab extends JPanel {
|
||||
}
|
||||
|
||||
final List<FileItem> itemsToLoad = newItems;
|
||||
final boolean contentChanged = !isSameContent(newItems, tableModel.items);
|
||||
|
||||
loadDirectory(currentDirectory, itemsToLoad, false, requestFocus, () -> {
|
||||
// Restore marks and set recentlyChanged flag based on active timestamps
|
||||
for (FileItem item : tableModel.items) {
|
||||
@ -1409,7 +1507,9 @@ public class FilePanelTab extends JPanel {
|
||||
}
|
||||
}
|
||||
}
|
||||
fileTable.repaint();
|
||||
if (contentChanged) {
|
||||
fileTable.repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -2633,14 +2733,20 @@ public class FilePanelTab extends JPanel {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
if (mode == ViewMode.INFO) {
|
||||
cardLayout.show(cardPanel, "INFO");
|
||||
if (briefSortPanel != null) briefSortPanel.setVisible(false);
|
||||
} else {
|
||||
cardLayout.show(cardPanel, "TABLE");
|
||||
tableModel.updateViewMode(mode);
|
||||
// Switch auto-resize behavior depending on mode so BRIEF can scroll horizontally
|
||||
if (mode == ViewMode.BRIEF) {
|
||||
fileTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
|
||||
if (briefSortPanel != null) {
|
||||
briefSortPanel.setVisible(true);
|
||||
updateSortButtonsDisplay();
|
||||
}
|
||||
} else {
|
||||
fileTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
|
||||
if (briefSortPanel != null) briefSortPanel.setVisible(false);
|
||||
}
|
||||
// Hide table header in BRIEF mode to save vertical space and match requirements
|
||||
if (fileTable.getTableHeader() != null) {
|
||||
@ -3118,39 +3224,92 @@ public class FilePanelTab extends JPanel {
|
||||
* Sort items in the current table model according to column (FULL mode).
|
||||
* column: 0=name, 1=size, 2=date
|
||||
*/
|
||||
private void updateSortButtonsDisplay() {
|
||||
if (sortByNameButton == null || sortByDateButton == null || sortBySizeButton == null) return;
|
||||
|
||||
String upArrow = "↑";
|
||||
String downArrow = "↓";
|
||||
|
||||
sortByNameButton.setText(sortColumn == 0 ? "Name " + (sortAscending ? upArrow : downArrow) : "Name");
|
||||
sortByDateButton.setText(sortColumn == 2 ? "Date " + (sortAscending ? upArrow : downArrow) : "Date");
|
||||
sortBySizeButton.setText(sortColumn == 1 ? "Size " + (sortAscending ? upArrow : downArrow) : "Size");
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove leading and trailing $ characters for sorting purposes.
|
||||
*/
|
||||
private String getCleanNameForSorting(String name) {
|
||||
if (name == null) return "";
|
||||
return name.replaceAll("^\\$+|\\$+$", "");
|
||||
}
|
||||
|
||||
private void sortItemsByColumn(int column, boolean asc) {
|
||||
if (tableModel == null || tableModel.items == null) return;
|
||||
java.util.List<FileItem> items = tableModel.items;
|
||||
if (items.isEmpty()) return;
|
||||
|
||||
// Remember currently selected item name to restore selection after sort
|
||||
final String selectedItemName;
|
||||
FileItem focused = getFocusedItem();
|
||||
selectedItemName = (focused != null) ? focused.getName() : null;
|
||||
|
||||
// Extract and remember the ".." (parent directory) entry if present
|
||||
FileItem parentDir = null;
|
||||
if (!items.isEmpty() && items.get(0).getName().equals("..")) {
|
||||
parentDir = items.remove(0);
|
||||
}
|
||||
|
||||
// Separate directories and files
|
||||
java.util.List<FileItem> directories = new ArrayList<>();
|
||||
java.util.List<FileItem> files = new ArrayList<>();
|
||||
|
||||
for (FileItem item : items) {
|
||||
if (item.isDirectory()) {
|
||||
directories.add(item);
|
||||
} else {
|
||||
files.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
java.util.Comparator<FileItem> comp;
|
||||
switch (column) {
|
||||
case 1: // size
|
||||
comp = (a, b) -> {
|
||||
boolean da = a.isDirectory(), db = b.isDirectory();
|
||||
if (da != db) return da ? -1 : 1;
|
||||
if (da && db) return a.getName().compareToIgnoreCase(b.getName());
|
||||
int r = Long.compare(a.getSize(), b.getSize());
|
||||
if (r == 0) r = a.getName().compareToIgnoreCase(b.getName());
|
||||
if (r == 0) r = getCleanNameForSorting(a.getName()).compareToIgnoreCase(getCleanNameForSorting(b.getName()));
|
||||
return r;
|
||||
};
|
||||
break;
|
||||
case 2: // date
|
||||
// Sort by modification time regardless of directory flag so "newest first" places the newest item
|
||||
// Sort by modification time
|
||||
comp = (a, b) -> {
|
||||
int r = Long.compare(a.getModified().getTime(), b.getModified().getTime());
|
||||
if (r == 0) r = a.getName().compareToIgnoreCase(b.getName());
|
||||
if (r == 0) r = getCleanNameForSorting(a.getName()).compareToIgnoreCase(getCleanNameForSorting(b.getName()));
|
||||
return r;
|
||||
};
|
||||
break;
|
||||
default: // name
|
||||
comp = (a, b) -> compareFileItemsByName(a, b);
|
||||
comp = (a, b) -> {
|
||||
String s1 = getCleanNameForSorting(a.getName());
|
||||
String s2 = getCleanNameForSorting(b.getName());
|
||||
return s1.compareToIgnoreCase(s2);
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
if (!asc) comp = comp.reversed();
|
||||
|
||||
items.sort(comp);
|
||||
// Sort both lists separately
|
||||
directories.sort(comp);
|
||||
files.sort(comp);
|
||||
|
||||
// Clear and rebuild items list: directories first, then files
|
||||
items.clear();
|
||||
if (parentDir != null) {
|
||||
items.add(parentDir);
|
||||
}
|
||||
items.addAll(directories);
|
||||
items.addAll(files);
|
||||
|
||||
// Refresh table on EDT
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
@ -3163,6 +3322,26 @@ public class FilePanelTab extends JPanel {
|
||||
updateColumnRenderers();
|
||||
updateColumnWidths();
|
||||
if (fileTable.getTableHeader() != null) fileTable.getTableHeader().repaint();
|
||||
|
||||
// Restore selection to the same item (by name) after sorting
|
||||
if (selectedItemName != null) {
|
||||
for (int i = 0; i < tableModel.items.size(); i++) {
|
||||
if (tableModel.items.get(i).getName().equals(selectedItemName)) {
|
||||
if (viewMode == ViewMode.BRIEF) {
|
||||
int selRow = i % tableModel.briefRowsPerColumn;
|
||||
int selCol = i / tableModel.briefRowsPerColumn;
|
||||
briefCurrentColumn = selCol;
|
||||
fileTable.setRowSelectionInterval(selRow, selRow);
|
||||
fileTable.getColumnModel().getSelectionModel().setSelectionInterval(selCol, selCol);
|
||||
fileTable.scrollRectToVisible(fileTable.getCellRect(selRow, selCol, true));
|
||||
} else {
|
||||
fileTable.setRowSelectionInterval(i, i);
|
||||
fileTable.scrollRectToVisible(fileTable.getCellRect(i, 0, true));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -3351,25 +3530,31 @@ public class FilePanelTab extends JPanel {
|
||||
public void setAppConfig(cz.kamma.kfmanager.config.AppConfig cfg) {
|
||||
this.persistedConfig = cfg;
|
||||
iconCache.clear();
|
||||
// Apply persisted sort if present
|
||||
|
||||
// Apply persisted sort if present - try global.sort.column first, then MultipleSortCriteria
|
||||
if (cfg != null) {
|
||||
java.util.List<String> multi = cfg.getMultipleSortCriteria();
|
||||
if (multi != null && !multi.isEmpty()) {
|
||||
applyMultipleSortCriteria(multi);
|
||||
} else {
|
||||
int col = cfg.getDefaultSortColumn();
|
||||
boolean asc = cfg.getDefaultSortAscending();
|
||||
if (col >= 0) {
|
||||
this.sortColumn = col;
|
||||
this.sortAscending = asc;
|
||||
int col = cfg.getDefaultSortColumn();
|
||||
boolean asc = cfg.getDefaultSortAscending();
|
||||
|
||||
if (col >= 0) {
|
||||
// Use global sort column setting
|
||||
this.sortColumn = col;
|
||||
this.sortAscending = asc;
|
||||
// If items are already loaded, sort them
|
||||
if (tableModel != null && tableModel.items != null && !tableModel.items.isEmpty()) {
|
||||
sortItemsByColumn(sortColumn, sortAscending);
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
tableModel.fireTableDataChanged();
|
||||
if (fileTable.getTableHeader() != null) fileTable.getTableHeader().repaint();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// No global sort setting, try multiple criteria
|
||||
java.util.List<String> multi = cfg.getMultipleSortCriteria();
|
||||
if (multi != null && !multi.isEmpty()) {
|
||||
applyMultipleSortCriteria(multi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update button display immediately (not in invokeLater) so ViewMode changes can see updated state
|
||||
updateSortButtonsDisplay();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user