Skip to content

Commit 1099c97

Browse files
macata#7: Added "open in finder" right-click menu to tables
2 parents 7e0aaf2 + dc186a9 commit 1099c97

File tree

3 files changed

+110
-12
lines changed

3 files changed

+110
-12
lines changed

src/main/java/com/dazednconfused/catalauncher/gui/MainWindow.form

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,9 @@
246246
<children>
247247
<component id="dd00a" class="javax.swing.JTable" binding="saveBackupTable">
248248
<constraints/>
249-
<properties/>
249+
<properties>
250+
<enabled value="false"/>
251+
</properties>
250252
</component>
251253
</children>
252254
</scrollpane>
@@ -269,7 +271,9 @@
269271
<children>
270272
<component id="38613" class="javax.swing.JTable" binding="soundpacksTable">
271273
<constraints/>
272-
<properties/>
274+
<properties>
275+
<enabled value="false"/>
276+
</properties>
273277
</component>
274278
</children>
275279
</scrollpane>

src/main/java/com/dazednconfused/catalauncher/gui/MainWindow.java

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import com.dazednconfused.catalauncher.backup.SaveManager;
99
import com.dazednconfused.catalauncher.configuration.ConfigurationManager;
10+
import com.dazednconfused.catalauncher.helper.FileExplorerManager;
1011
import com.dazednconfused.catalauncher.helper.GitInfoManager;
1112
import com.dazednconfused.catalauncher.helper.LogLevelManager;
1213
import com.dazednconfused.catalauncher.launcher.CDDALauncherManager;
@@ -19,11 +20,14 @@
1920
import java.awt.Component;
2021
import java.awt.event.InputEvent;
2122
import java.awt.event.KeyEvent;
23+
import java.awt.event.MouseAdapter;
24+
import java.awt.event.MouseEvent;
2225
import java.io.File;
2326
import java.util.ArrayList;
2427
import java.util.Comparator;
2528
import java.util.Date;
2629
import java.util.List;
30+
import java.util.function.BiConsumer;
2731

2832
import javax.swing.JButton;
2933
import javax.swing.JCheckBox;
@@ -35,6 +39,7 @@
3539
import javax.swing.JMenuBar;
3640
import javax.swing.JMenuItem;
3741
import javax.swing.JPanel;
42+
import javax.swing.JPopupMenu;
3843
import javax.swing.JProgressBar;
3944
import javax.swing.JTable;
4045
import javax.swing.KeyStroke;
@@ -171,7 +176,7 @@ public MainWindow() {
171176

172177
// BACKUP NOW BUTTON LISTENER ---
173178
this.backupNowButton.addActionListener(e -> {
174-
LOGGER.trace("Backup button clicked");
179+
LOGGER.trace("Save backup button clicked");
175180

176181
// enable backup progressbar
177182
this.globalProgressBar.setEnabled(true);
@@ -184,10 +189,10 @@ public MainWindow() {
184189

185190
// BACKUP RESTORE BUTTON LISTENER ---
186191
backupRestoreButton.addActionListener(e -> {
187-
LOGGER.trace("Backup restore button clicked");
192+
LOGGER.trace("Save backup restore button clicked");
188193

189-
File selectedBackup = (File) this.saveBackupTable.getValueAt(this.saveBackupTable.getSelectedRow(), 0);
190-
LOGGER.trace("Backup currently on selection: [{}]", selectedBackup);
194+
File selectedBackup = (File) this.saveBackupTable.getValueAt(this.saveBackupTable.getSelectedRow(), 1);
195+
LOGGER.trace("Save backup currently on selection: [{}]", selectedBackup);
191196

192197
ConfirmDialog confirmDialog = new ConfirmDialog(
193198
String.format("Are you sure you want to restore the backup [%s]? Current save will be moved to trash folder [%s]", selectedBackup.getName(), CUSTOM_TRASHED_SAVE_PATH),
@@ -219,8 +224,8 @@ public MainWindow() {
219224
this.backupDeleteButton.addActionListener(e -> {
220225
LOGGER.trace("Delete backup button clicked");
221226

222-
File selectedBackup = (File) this.saveBackupTable.getValueAt(this.saveBackupTable.getSelectedRow(), 0);
223-
LOGGER.trace("Backup currently on selection: [{}]", selectedBackup);
227+
File selectedBackup = (File) this.saveBackupTable.getValueAt(this.saveBackupTable.getSelectedRow(), 1);
228+
LOGGER.trace("Save backup currently on selection: [{}]", selectedBackup);
224229

225230
ConfirmDialog confirmDialog = new ConfirmDialog(
226231
String.format("Are you sure you want to delete the backup [%s]? This action is irreversible!", selectedBackup.getName()),
@@ -239,16 +244,28 @@ public MainWindow() {
239244
confirmDialog.packCenterAndShow(this.mainPanel);
240245
});
241246

242-
// BACKUP TABLE LISTENER ---
247+
// BACKUP TABLE LISTENER(S) ---
248+
this.saveBackupTable.setName("Save backups table"); // needed in order to recognize component in generic methods
249+
243250
this.saveBackupTable.getSelectionModel().addListSelectionListener(event -> {
244-
LOGGER.trace("Backup table row selected");
251+
LOGGER.trace("Save backups table row selected");
245252

246253
if (saveBackupTable.getSelectedRow() > -1) {
247254
this.backupDeleteButton.setEnabled(true);
248255
this.backupRestoreButton.setEnabled(true);
249256
}
250257
});
251258

259+
this.saveBackupTable.addMouseListener(new MouseAdapter() {
260+
public void mousePressed(MouseEvent e) { // mousedPressed event needed for macOS - https://stackoverflow.com/a/3558324
261+
genericTableOnClickEventListener().accept(e, (JTable) e.getComponent());
262+
}
263+
264+
public void mouseReleased(MouseEvent e) { // mouseReleased event needed for other OSes
265+
genericTableOnClickEventListener().accept(e, (JTable) e.getComponent());
266+
}
267+
});
268+
252269
// SOUNDPACK INSTALL BUTTON LISTENER ---
253270
this.installSoundpackButton.addActionListener(e -> {
254271
LOGGER.trace("Install soundpack button clicked");
@@ -302,14 +319,26 @@ public MainWindow() {
302319
confirmDialog.packCenterAndShow(this.mainPanel);
303320
});
304321

305-
// SOUNDPACKS TABLE LISTENER ---
322+
// SOUNDPACKS TABLE LISTENER(S) ---
323+
this.soundpacksTable.setName("Soundpacks table"); // needed in order to recognize component in generic methods
324+
306325
this.soundpacksTable.getSelectionModel().addListSelectionListener(event -> {
307326
LOGGER.trace("Soundpacks table row selected");
308327

309328
if (soundpacksTable.getSelectedRow() > -1) {
310329
this.uninstallSoundpackButton.setEnabled(true);
311330
}
312331
});
332+
333+
this.soundpacksTable.addMouseListener(new MouseAdapter() {
334+
public void mousePressed(MouseEvent e) { // mousedPressed event needed for macOS - https://stackoverflow.com/a/3558324
335+
genericTableOnClickEventListener().accept(e, (JTable) e.getComponent());
336+
}
337+
338+
public void mouseReleased(MouseEvent e) { // mouseReleased event needed for other OSes
339+
genericTableOnClickEventListener().accept(e, (JTable) e.getComponent());
340+
}
341+
});
313342
}
314343

315344
/**
@@ -482,11 +511,12 @@ private void openFinder(Component parent) {
482511
private void refreshSaveBackupsTable() {
483512
LOGGER.trace("Refreshing save backups table...");
484513

485-
String[] columns = new String[]{"Backup", "Size", "Date"};
514+
String[] columns = new String[]{"Name", "Path", "Size", "Date"};
486515

487516
List<Object[]> values = new ArrayList<>();
488517
SaveManager.listAllBackups().stream().sorted(Comparator.comparing(File::lastModified).reversed()).forEach(backup ->
489518
values.add(new Object[]{
519+
backup.getName(),
490520
backup,
491521
backup.length() / (1024 * 1024) + " MB",
492522
new Date(backup.lastModified())
@@ -518,4 +548,40 @@ private void refreshSoundpacksTable() {
518548
TableModel tableModel = new DefaultTableModel(values.toArray(new Object[][]{}), columns);
519549
this.soundpacksTable.setModel(tableModel);
520550
}
551+
552+
/**
553+
* Returns a generic right-click "open in files" context popup for usage in {@link JTable}s.
554+
* */
555+
private BiConsumer<MouseEvent, JTable> genericTableOnClickEventListener() {
556+
return (e, table) -> {
557+
LOGGER.trace("[{}] clicked", table.getName());
558+
559+
int r = table.rowAtPoint(e.getPoint());
560+
if (r >= 0 && r < table.getRowCount()) {
561+
table.setRowSelectionInterval(r, r);
562+
} else {
563+
table.clearSelection();
564+
}
565+
566+
int rowindex = table.getSelectedRow();
567+
if (rowindex < 0) {
568+
return;
569+
}
570+
571+
if (e.isPopupTrigger() && e.getComponent() instanceof JTable) {
572+
LOGGER.trace("Opening right-click popup for [{}]", table.getName());
573+
574+
JPopupMenu popup = new JPopupMenu();
575+
576+
JMenuItem openInFinder = new JMenuItem("Open folder in file explorer");
577+
openInFinder.addActionListener(e1 -> {
578+
File targetPath = (File) table.getValueAt(table.getSelectedRow(), 1);
579+
FileExplorerManager.openFileInFileExplorer(targetPath);
580+
});
581+
popup.add(openInFinder);
582+
583+
popup.show(e.getComponent(), e.getX(), e.getY());
584+
}
585+
};
586+
}
521587
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.dazednconfused.catalauncher.helper;
2+
3+
import io.vavr.control.Try;
4+
5+
import java.awt.Desktop;
6+
import java.io.File;
7+
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
10+
11+
public class FileExplorerManager {
12+
13+
private static final Logger LOGGER = LoggerFactory.getLogger(FileExplorerManager.class);
14+
15+
/**
16+
* Opens given {@link File} path in the underlying {@link Desktop}'s file explorer.
17+
* */
18+
public static void openFileInFileExplorer(File file) {
19+
LOGGER.debug("Opening [{}] in file explorer...", file);
20+
21+
if (Desktop.isDesktopSupported()) {
22+
Try.run(() -> Desktop.getDesktop().open(file)).onFailure(t -> LOGGER.error("There was an error while opening file [{}]", file, t));
23+
} else {
24+
LOGGER.error("Desktop is not supported! Cannot open [{}]", file);
25+
}
26+
}
27+
28+
}

0 commit comments

Comments
 (0)