Start building file finder

This commit is contained in:
Melon 2022-05-10 01:10:20 +01:00
parent efa05579c1
commit ee3bc43fb4
Signed by: melon
GPG Key ID: B0ADD5395BCDAAB6
12 changed files with 427 additions and 23 deletions

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -3,6 +3,7 @@ package xyz.mrmelon54.codesize;
import xyz.mrmelon54.codesize.components.InfoPanel;
import xyz.mrmelon54.codesize.enums.Theme;
import xyz.mrmelon54.codesize.ex.CannotCreateConfigFolderException;
import xyz.mrmelon54.codesize.process.FileFinder;
import xyz.mrmelon54.codesize.ui.PresetSelector;
import xyz.mrmelon54.codesize.utils.AboutDialog;
import xyz.mrmelon54.codesize.utils.ComponentUtils;
@ -15,6 +16,7 @@ import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.regex.Pattern;
public class CodeSize extends JFrame {
public final Settings settings;
@ -141,11 +143,26 @@ public class CodeSize extends JFrame {
}
private void presetForRegex() {
PresetSelector presetSelector = new PresetSelector(this);
presetSelector.run();
new PresetSelector(this, preset -> regexField.setText(preset.regex)).run();
}
private void searchCodeFiles() {
System.out.println("Search code files");
File mainFile = new File(pathField.getText());
if (!mainFile.exists()) {
JOptionPane.showMessageDialog(this, "Path does not exist", "Code Size", JOptionPane.ERROR_MESSAGE);
return;
}
if (!mainFile.isDirectory()) {
JOptionPane.showMessageDialog(this, "Path is not a directory", "Code Size", JOptionPane.ERROR_MESSAGE);
return;
}
Pattern pattern;
try {
pattern = Pattern.compile(regexField.getText());
} catch (Exception ex) {
JOptionPane.showMessageDialog(this, "Failed to parse regex pattern", "Code Size", JOptionPane.ERROR_MESSAGE);
return;
}
new Thread(() -> FileFinder.search(mainFile, pattern, infoPanel)).start();
}
}

View File

@ -1,26 +1,37 @@
package xyz.mrmelon54.codesize.components;
import xyz.mrmelon54.codesize.utils.ByteUtils;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
public class InfoPanel extends Box {
public InfoPanelItem totalFiles = new InfoPanelItem("Total Files");
public InfoPanelItem totalSize = new InfoPanelItem("Total Size");
public InfoPanelItem averageSize = new InfoPanelItem("Average Size");
public InfoPanelItem maxSize = new InfoPanelItem("Max Size");
public InfoPanelItem totalLines = new InfoPanelItem("Total Lines");
public InfoPanelItem averageLines = new InfoPanelItem("Average Lines");
public InfoPanelItem maxLines = new InfoPanelItem("Max Lines");
public InfoPanelItem minLines = new InfoPanelItem("Min Lines");
private final DefaultListModel<String> fileListModel = new DefaultListModel<>();
public InfoPanelItem totalFiles = new InfoPanelItem("Total Files", false);
public InfoPanelItem totalSize = new InfoPanelItem("Total Size", true);
public InfoPanelItem averageSize = new InfoPanelItem("Average Size", true);
public InfoPanelItem maxSize = new InfoPanelItem("Max Size", true);
public InfoPanelItem minSize = new InfoPanelItem("Min Size", true);
public InfoPanelItem totalLines = new InfoPanelItem("Total Lines", false);
public InfoPanelItem averageLines = new InfoPanelItem("Average Lines", false);
public InfoPanelItem maxLines = new InfoPanelItem("Max Lines", false);
public InfoPanelItem minLines = new InfoPanelItem("Min Lines", false);
private final List<InfoPanelItem> values = new ArrayList<>();
public InfoPanel() {
super(BoxLayout.Y_AXIS);
JList<String> fileListInfo = new JList<>();
fileListInfo.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
fileListInfo.setModel(fileListModel);
add(fileListInfo);
values.add(totalFiles);
values.add(totalSize);
values.add(averageSize);
values.add(maxSize);
values.add(minSize);
values.add(totalLines);
values.add(averageLines);
values.add(maxLines);
@ -32,19 +43,27 @@ public class InfoPanel extends Box {
values.forEach(InfoPanelItem::updateValue);
}
public void addFileOutput(String s) {
fileListModel.addElement(s);
}
public static class InfoPanelItem {
private final String label;
private final boolean byteUnits;
private float value;
private final JLabel component;
public InfoPanelItem(String label) {
public InfoPanelItem(String label, boolean byteUnits) {
this.label = label;
this.byteUnits = byteUnits;
component = new JLabel();
updateValue();
}
private void updateValue() {
component.setText(label + ": " + value);
String v = byteUnits ? ByteUtils.ToBytesCount((long) value) : String.valueOf(value);
SwingUtilities.invokeLater(() -> component.setText(label + ": " + v));
}
public void setValue(float v) {

View File

@ -0,0 +1,28 @@
package xyz.mrmelon54.codesize.components;
import jiconfont.IconCode;
import jiconfont.swing.IconFontSwing;
import javax.swing.*;
import java.awt.*;
public class JIconButton extends JButton {
public JIconButton(IconCode iconCode, float iconSize, Dimension buttonSize, Color color) {
super(IconFontSwing.buildIcon(iconCode, iconSize, color));
setBorderPainted(false);
setOpaque(true);
setBackground(UIManager.getDefaults().getColor("Panel.background"));
setSize(buttonSize.getSize());
setPreferredSize(buttonSize.getSize());
setMinimumSize(buttonSize.getSize());
setMaximumSize(buttonSize.getSize());
}
public JIconButton(IconCode iconCode, float iconSize, Dimension buttonSize) {
this(iconCode, iconSize, buttonSize, UIManager.getDefaults().getColor("textText"));
}
public JIconButton(IconCode iconCode, float iconSize, int buttonSize) {
this(iconCode, iconSize, new Dimension(buttonSize, buttonSize));
}
}

View File

@ -0,0 +1,22 @@
package xyz.mrmelon54.codesize.process;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.stream.Stream;
public class CountFileLines {
public static long CountLines(File file) {
long count = 0;
if (file.canRead()) {
try (Stream<String> lines = Files.lines(file.toPath(), Charset.defaultCharset())) {
count += lines.count();
} catch (IOException e) {
System.out.println("Failed to read file: " + file.getAbsolutePath());
e.printStackTrace();
}
}
return count;
}
}

View File

@ -0,0 +1,62 @@
package xyz.mrmelon54.codesize.process;
import xyz.mrmelon54.codesize.components.InfoPanel;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import static xyz.mrmelon54.codesize.utils.ByteUtils.ToBytesCount;
public class FileFinder {
public static void search(File mainFile, Pattern pattern, InfoPanel infoPanel) {
List<File> searchable = new ArrayList<>();
searchable.add(mainFile);
long totalFiles = 0;
long totalSize = 0;
long maxSize = 0;
long minSize = 0;
long totalLines = 0;
long maxLines = 0;
long minLines = 0;
for (int i = 0; i < searchable.size(); i++) {
File path1 = searchable.get(i);
File[] files1 = path1.listFiles(File::isDirectory);
if (files1 == null) continue;
Collections.addAll(searchable, files1);
File[] files2 = path1.listFiles((dir, name) -> {
return pattern.matcher(name).find();
});
if (files2 == null) return;
for (File file : files2) {
long len = file.length();
totalFiles++;
totalSize += len;
if (len > maxSize) maxSize = len;
if (len < minSize || minSize == 0) minSize = len;
long lineCount = CountFileLines.CountLines(file);
totalLines += lineCount;
if (lineCount > maxLines) maxLines = lineCount;
if (lineCount < minLines || minLines == 0) minLines = lineCount;
infoPanel.addFileOutput(ToBytesCount(len) + " -- " + lineCount + " -- " + file.getName());
}
infoPanel.totalFiles.setValue(totalFiles);
infoPanel.totalSize.setValue(totalSize);
infoPanel.averageSize.setValue(totalSize / (float) totalFiles);
infoPanel.maxSize.setValue(maxSize);
infoPanel.minSize.setValue(minSize);
infoPanel.totalLines.setValue(totalLines);
infoPanel.averageLines.setValue(totalLines / (float) totalFiles);
infoPanel.maxLines.setValue(maxLines);
infoPanel.minLines.setValue(minLines);
}
infoPanel.updateValues();
}
}

View File

@ -0,0 +1,85 @@
package xyz.mrmelon54.codesize.ui;
import xyz.mrmelon54.codesize.CodeSize;
import xyz.mrmelon54.codesize.utils.ComponentUtils;
import xyz.mrmelon54.codesize.utils.Preset;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.WindowEvent;
public class PresetEditor extends JDialog {
private final Preset preset;
private final boolean isEditing;
private JTextField nameField;
private JTextField regexField;
private boolean saveOption;
public PresetEditor(CodeSize codeSize, Preset preset, boolean isEditing) {
super(codeSize, (isEditing ? "Edit" : "Add") + " Preset", true);
this.preset = preset;
this.isEditing = isEditing;
setResizable(false);
Dimension d = new Dimension(400, 200);
setSize(d);
setPreferredSize(d);
setMinimumSize(d);
setMaximumSize(d);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setContentPane(createMainPanel());
setLocationRelativeTo(null);
}
private JPanel createMainPanel() {
nameField = ComponentUtils.fixedTextFieldHeight(new JTextField());
regexField = ComponentUtils.fixedTextFieldHeight(new JTextField());
nameField.setText(preset.name);
regexField.setText(preset.regex);
JButton saveButton = new JButton(isEditing ? "Edit" : "Add");
saveButton.addActionListener(this::saveAction);
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(this::cancelAction);
Box box = Box.createVerticalBox();
box.add(nameField);
box.add(Box.createVerticalStrut(8));
box.add(regexField);
Box hBox = Box.createHorizontalBox();
hBox.add(Box.createHorizontalGlue());
hBox.add(saveButton);
hBox.add(Box.createHorizontalStrut(8));
hBox.add(cancelButton);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
mainPanel.setBorder(new EmptyBorder(8, 8, 8, 8));
mainPanel.add(box, BorderLayout.CENTER);
mainPanel.add(hBox, BorderLayout.SOUTH);
return mainPanel;
}
public void run() {
setVisible(true);
}
public boolean isSaveOption() {
return saveOption;
}
private void saveAction(ActionEvent actionEvent) {
saveOption = true;
preset.name = nameField.getText();
preset.regex = regexField.getText();
cancelAction(actionEvent);
}
private void cancelAction(ActionEvent actionEvent) {
dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
}
}

View File

@ -1,17 +1,30 @@
package xyz.mrmelon54.codesize.ui;
import jiconfont.icons.google_material_design_icons.GoogleMaterialDesignIcons;
import xyz.mrmelon54.codesize.CodeSize;
import xyz.mrmelon54.codesize.callback.PresetCallback;
import xyz.mrmelon54.codesize.components.JIconButton;
import xyz.mrmelon54.codesize.utils.Pair;
import xyz.mrmelon54.codesize.utils.Preset;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.WindowEvent;
import java.util.UUID;
public class PresetSelector extends JDialog {
private final CodeSize codeSize;
private final PresetCallback presetCallback;
private final DefaultListModel<Preset> presetListModel;
private JList<Preset> presetList;
public PresetSelector(CodeSize codeSize) {
public PresetSelector(CodeSize codeSize, PresetCallback presetCallback) {
super(codeSize, "Choose Preset", true);
this.codeSize = codeSize;
this.presetCallback = presetCallback;
presetListModel = new DefaultListModel<>();
setResizable(false);
Dimension d = new Dimension(400, 400);
setSize(d);
@ -24,13 +37,37 @@ public class PresetSelector extends JDialog {
}
private JPanel createMainPanel() {
JList<Preset> presetList = new JList<>();
DefaultListModel<Preset> presetListModel = new DefaultListModel<>();
JIconButton addButton = new JIconButton(GoogleMaterialDesignIcons.ADD, 16, 24);
addButton.addActionListener(this::addAction);
JIconButton removeButton = new JIconButton(GoogleMaterialDesignIcons.REMOVE, 16, 24);
removeButton.addActionListener(this::removeAction);
JIconButton copyButton = new JIconButton(GoogleMaterialDesignIcons.CONTENT_COPY, 16, 24);
copyButton.addActionListener(this::copyAction);
JIconButton editButton = new JIconButton(GoogleMaterialDesignIcons.EDIT, 16, 24);
editButton.addActionListener(this::editAction);
JButton chooseButton = new JButton("Choose");
chooseButton.addActionListener(this::selectAction);
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(this::cancelAction);
Box hBox = Box.createHorizontalBox();
hBox.add(addButton);
hBox.add(removeButton);
hBox.add(editButton);
hBox.add(copyButton);
hBox.add(Box.createHorizontalGlue());
hBox.add(chooseButton);
hBox.add(cancelButton);
presetList = new JList<>();
presetList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
presetList.setModel(presetListModel);
for (Preset preset : codeSize.settings.presets) presetListModel.addElement(preset);
reload();
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
mainPanel.add(hBox, BorderLayout.NORTH);
mainPanel.add(presetList, BorderLayout.CENTER);
return mainPanel;
}
@ -38,4 +75,76 @@ public class PresetSelector extends JDialog {
public void run() {
setVisible(true);
}
public void reload() {
presetListModel.clear();
for (Preset preset : codeSize.settings.presets) presetListModel.addElement(preset);
}
public Pair<Integer, Preset> getSelectedPreset() {
int idx = presetList.getSelectedIndex();
if (idx == -1) return new Pair<>(-1, null);
Preset item = presetListModel.getElementAt(idx);
return new Pair<>(idx, item);
}
private void addAction(ActionEvent actionEvent) {
Pair<Integer, Preset> selectedPreset = getSelectedPreset();
Preset preset = new Preset();
PresetEditor presetEditor = new PresetEditor(codeSize, preset, false);
presetEditor.run();
if (presetEditor.isSaveOption()) {
int idx = selectedPreset.t() + 1;
codeSize.settings.presets.insertElementAt(preset, idx);
reload();
presetList.setSelectedIndex(idx);
}
}
private void removeAction(ActionEvent actionEvent) {
Pair<Integer, Preset> selectedPreset = getSelectedPreset();
if (selectedPreset.t() == -1) return;
codeSize.settings.presets.removeElementAt(selectedPreset.t());
reload();
}
private void copyAction(ActionEvent actionEvent) {
Pair<Integer, Preset> selectedPreset = getSelectedPreset();
if (selectedPreset.t() == -1) return;
Preset u = selectedPreset.u();
Preset item = new Preset();
item.name = Preset.generatePresetName(u.getRawName(), codeSize.settings.presets);
item.regex = u.regex;
item.builtin = false;
item.uuid = UUID.randomUUID();
int idx = selectedPreset.t() + 1;
codeSize.settings.presets.insertElementAt(item, idx);
reload();
presetList.setSelectedIndex(idx);
}
private void editAction(ActionEvent actionEvent) {
Pair<Integer, Preset> selectedPreset = getSelectedPreset();
if (selectedPreset.t() == -1) return;
Preset preset = selectedPreset.u();
PresetEditor presetEditor = new PresetEditor(codeSize, preset, true);
presetEditor.run();
if (presetEditor.isSaveOption()) {
reload();
presetList.setSelectedIndex(selectedPreset.t());
}
}
private void selectAction(ActionEvent actionEvent) {
Pair<Integer, Preset> selectedPreset = getSelectedPreset();
if (selectedPreset.t() == -1) return;
presetCallback.changePreset(selectedPreset.u());
cancelAction(actionEvent);
}
private void cancelAction(ActionEvent actionEvent) {
dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
}
}

View File

@ -2,6 +2,7 @@ package xyz.mrmelon54.codesize.utils;
import java.lang.reflect.Array;
import java.util.Collections;
import java.util.function.IntFunction;
public record ArrayUtils<T>(IntFunction<T[]> generator) {
@ -19,4 +20,17 @@ public record ArrayUtils<T>(IntFunction<T[]> generator) {
System.arraycopy(b, 0, result, aLen, bLen);
return result;
}
public T[] append(T[] a, T b) {
if (a == null) {
T[] result = generator.apply(1);
result[0] = b;
return result;
}
final int aLen = Array.getLength(a);
T[] result = generator.apply(aLen + 1);
System.arraycopy(a, 0, result, 0, aLen);
result[aLen] = b;
return result;
}
}

View File

@ -0,0 +1,14 @@
package xyz.mrmelon54.codesize.utils;
public class ByteUtils {
public static String ToBytesCount(long len) {
int unit = 1024;
String unitStr = "b";
if ((len < unit)) return String.format("%d %s", len, unitStr);
else unitStr = unitStr.toUpperCase();
byte[] a = "KMGTPEZY".getBytes();
int exp = ((int) ((Math.log(len) / Math.log(unit))));
return String.format("%.2f %s%s", (len / Math.pow(unit, exp)), a[(exp - 1)], unitStr);
}
}

View File

@ -1,6 +1,10 @@
package xyz.mrmelon54.codesize.utils;
import java.util.Objects;
import java.util.UUID;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Preset {
public UUID uuid;
@ -8,8 +12,29 @@ public class Preset {
public String regex;
public boolean builtin;
private static final Pattern rawNamePattern = Pattern.compile("(.+) \\(Copy \\d+\\)"); // TODO
@Override
public String toString() {
return name;
}
private static boolean generatedPresetNameValid(String name, Vector<Preset> presets) {
for (Preset preset : presets) if (Objects.equals(preset.name, name)) return false;
return true;
}
public static String generatePresetName(String prefix, Vector<Preset> presets) {
if (generatedPresetNameValid(prefix, presets)) return prefix;
int i = 0;
while (true)
if (generatedPresetNameValid(prefix + " (Copy " + (++i) + ")", presets))
return prefix + " (Copy " + i + ")";
}
public String getRawName() {
Matcher matcher = rawNamePattern.matcher(name);
if (!matcher.matches()) return name;
return matcher.group(1);
}
}

View File

@ -6,18 +6,19 @@ import xyz.mrmelon54.codesize.enums.Theme;
import xyz.mrmelon54.codesize.ex.CannotCreateConfigFolderException;
import java.io.*;
import java.util.Arrays;
import java.util.*;
import java.util.stream.Stream;
public class Settings {
private static final File settingsFile = new File(DirUtils.getConfigDir(), "settings.json");
private static final BuiltinPresets builtinPresets = new BuiltinPresets();
public Theme theme;
public Preset[] presets;
public Vector<Preset> presets;
public Settings() {
this.theme = Theme.System;
this.presets = new Preset[0];
this.presets = new Vector<>();
}
private static boolean assureAppDirExists() {
@ -27,11 +28,13 @@ public class Settings {
private void assureBuiltinPresetsExist() {
Preset[] pre1 = builtinPresets.getBuiltinPresets();
Preset[] pre2 = Arrays.stream(presets).filter(preset -> {
Stream<Preset> pre2 = presets.stream().filter(preset -> {
for (Preset p : pre1) if (preset.uuid.equals(p.uuid)) return false;
return true;
}).toArray(Preset[]::new);
presets = new ArrayUtils<>(Preset[]::new).concat(pre1, pre2);
});
List<Preset> pre3 = new ArrayList<>(List.of(pre1));
pre3.addAll(pre2.toList());
presets = new Vector<>(pre3);
}
public static Settings load() {