Skip to content

Commit d26e3f3

Browse files
committed
chore: Refactor with tests and classes
1 parent 663f372 commit d26e3f3

File tree

59 files changed

+12494
-1003
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+12494
-1003
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@ target/
2222
*.war
2323
*.ear
2424
*.class
25+
26+
logs/file-compression.log

README.md

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# File Compression
22

3-
[![CI](https://github.com/ayonious/File-Compression/workflows/CI/badge.svg)](https://github.com/ayonious/File-Compression/actions)
3+
[![Build and Test](https://github.com/ayonious/File-Compression/actions/workflows/build.yml/badge.svg)](https://github.com/ayonious/File-Compression/actions/workflows/build.yml)
4+
[![CircleCI](https://dl.circleci.com/status-badge/img/gh/ayonious/File-Compression/tree/master.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/ayonious/File-Compression/tree/master)
45
[![codecov](https://codecov.io/gh/ayonious/File-Compression/branch/master/graph/badge.svg)](https://codecov.io/gh/ayonious/File-Compression)
56
[![GitHub stars](https://img.shields.io/github/stars/ayonious/File-Compression?style=social)](https://github.com/ayonious/File-Compression/stargazers)
67

@@ -36,12 +37,6 @@ On macOS:
3637
brew install maven
3738
```
3839

39-
On Linux:
40-
```bash
41-
sudo apt-get install maven # For Debian/Ubuntu
42-
sudo dnf install maven # For Fedora
43-
```
44-
4540
Verify installation:
4641
```bash
4742
mvn -version
@@ -53,7 +48,7 @@ mvn -version
5348
### Directly Run the jar file
5449
I have included the already build jar file. You can run it simply if you dont want to build
5550
```bash
56-
java -jar FileCompression.jar
51+
java -jar file-compression-2.0-SNAPSHOT.jar
5752
```
5853

5954

@@ -67,20 +62,12 @@ mvn exec:java
6762
### Using JAR directly
6863
After building with Maven, you can run the JAR:
6964
```bash
70-
java -jar target/file-compression-1.0-SNAPSHOT-jar-with-dependencies.jar
65+
java -jar target/file-compression-2.0-SNAPSHOT-jar-with-dependencies.jar
7166
```
7267

73-
![Outlook](/git_resource/outlook.png?raw=true "File Compression GUI")
74-
75-
## Zip a file
76-
file>open>click zip>the zipped file will be created on the same folder
77-
78-
79-
## Unzip a file
80-
file>open>click unzip>the unzipped file will be created on the same folder
81-
68+
![Outlook](/git_resource/readmeScreenshot.png?raw=true "File Compression GUI")
8269

8370
## Testing environment:
8471

8572
I tested this project in:
86-
Linux Mint, OS X El Capitan (version 10.11.6), macOS Sonoma
73+
MacOS Tahoe (version 26.0.1)

git_resource/readmeScreenshot.png

391 KB
Loading

logs/file-compression.log

Lines changed: 8979 additions & 0 deletions
Large diffs are not rendered by default.

pom.xml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>prog</groupId>
88
<artifactId>file-compression</artifactId>
9-
<version>1.0-SNAPSHOT</version>
9+
<version>2.0-SNAPSHOT</version>
1010

1111
<properties>
1212
<maven.compiler.source>21</maven.compiler.source>
@@ -17,12 +17,27 @@
1717
</properties>
1818

1919
<dependencies>
20+
<!-- JUnit for testing -->
2021
<dependency>
2122
<groupId>org.junit.jupiter</groupId>
2223
<artifactId>junit-jupiter</artifactId>
2324
<version>5.10.2</version>
2425
<scope>test</scope>
2526
</dependency>
27+
28+
<!-- SLF4J API for logging -->
29+
<dependency>
30+
<groupId>org.slf4j</groupId>
31+
<artifactId>slf4j-api</artifactId>
32+
<version>2.0.9</version>
33+
</dependency>
34+
35+
<!-- Logback Classic (includes logback-core) -->
36+
<dependency>
37+
<groupId>ch.qos.logback</groupId>
38+
<artifactId>logback-classic</artifactId>
39+
<version>1.4.14</version>
40+
</dependency>
2641
</dependencies>
2742

2843
<build>

src/main/java/prog/Main.java

Lines changed: 181 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,77 +4,185 @@
44
import java.awt.event.ActionListener;
55
import java.io.File;
66

7-
import javax.swing.JButton;
8-
import javax.swing.JFrame;
9-
import javax.swing.JLabel;
10-
import javax.swing.JOptionPane;
11-
import javax.swing.JPanel;
12-
13-
import prog.huffman.HuffmanCompressor;
14-
import prog.huffman.HuffmanDecompressor;
15-
import prog.lzw.LzwCompressor;
16-
import prog.lzw.LzwDecompressor;
17-
import prog.util.Constants;
18-
19-
public class Main extends JFrame implements ActionListener {
20-
// Definition of global values and items that are part of the GUI.
21-
22-
static public File openedFile, outputFile;
23-
static long originalSize, compressedSize;
24-
static JLabel originalSizeLabel, compressedSizeLabel, originalSizeValue, compressedSizeValue;
25-
static JPanel buttonPanel, titlePanel, scorePanel;
26-
static JButton huffmanCompressButton, huffmanDecompressButton, lzwCompressButton, lzwDecompressButton, exitButton;
7+
import javax.swing.*;
278

9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
12+
import prog.handler.CompressionHandler;
13+
import prog.handler.DecompressionHandler;
14+
import prog.handler.FileOperationHandler;
15+
import prog.ui.FileCompressorUI;
16+
import prog.ui.MainWindow;
17+
18+
/**
19+
* Main application class for the File Compressor.
20+
* Coordinates between UI components and business logic handlers.
21+
*/
22+
public class Main implements ActionListener {
23+
private static final Logger logger = LoggerFactory.getLogger(Main.class);
24+
25+
// Handlers
26+
private final FileOperationHandler fileHandler;
27+
private final CompressionHandler compressionHandler;
28+
private final DecompressionHandler decompressionHandler;
29+
30+
// UI Components
31+
private final FileCompressorUI ui;
32+
private JTextField filePathField;
33+
private JLabel originalSizeValue;
34+
private JLabel compressedSizeValue;
35+
private JLabel statusLabel;
36+
private JButton huffmanCompressButton;
37+
private JButton huffmanDecompressButton;
38+
private JButton lzwCompressButton;
39+
private JButton lzwDecompressButton;
40+
private JButton exitButton;
41+
42+
public Main() {
43+
this.ui = new FileCompressorUI();
44+
this.fileHandler = new FileOperationHandler();
45+
this.compressionHandler = new CompressionHandler();
46+
this.decompressionHandler = new DecompressionHandler();
47+
}
48+
49+
/**
50+
* Creates the content pane and initializes UI components
51+
*/
2852
public JPanel createContentPane() {
29-
return MainPanel.createContentPane(this);
53+
JPanel contentPane = ui.createContentPane(this, this::handleBrowse);
54+
55+
// Get references to UI components
56+
filePathField = ui.getFilePathField();
57+
originalSizeValue = ui.getOriginalSizeValue();
58+
compressedSizeValue = ui.getCompressedSizeValue();
59+
statusLabel = ui.getStatusLabel();
60+
huffmanCompressButton = ui.getHuffmanCompressButton();
61+
huffmanDecompressButton = ui.getHuffmanDecompressButton();
62+
lzwCompressButton = ui.getLzwCompressButton();
63+
lzwDecompressButton = ui.getLzwDecompressButton();
64+
exitButton = ui.getExitButton();
65+
66+
return contentPane;
67+
}
68+
69+
/**
70+
* Handles the browse button action to open file chooser
71+
*/
72+
private void handleBrowse(ActionEvent e) {
73+
File selectedFile = fileHandler.browseForFile();
74+
if (selectedFile != null) {
75+
filePathField.setText(selectedFile.getAbsolutePath());
76+
originalSizeValue.setText(fileHandler.formatFileSize(selectedFile.length()));
77+
compressedSizeValue.setText("—");
78+
statusLabel.setText("File selected: " + selectedFile.getName());
79+
}
80+
}
81+
82+
/**
83+
* Handles the File > Open menu action
84+
*/
85+
private void handleFileOpen() {
86+
handleBrowse(null);
87+
}
88+
89+
/**
90+
* Validates that a file is selected before performing operations
91+
*/
92+
private boolean validateFileSelected() {
93+
if (!fileHandler.isFileSelected()) {
94+
fileHandler.showNoFileSelectedWarning();
95+
statusLabel.setText("⚠️ No file selected");
96+
return false;
97+
}
98+
return true;
3099
}
31100

32101
private void handleHuffmanCompression() {
33-
HuffmanCompressor.beginHuffmanCompression(openedFile.getPath());
34-
showCompressionCompleteDialog("Zipping");
35-
updateFileStats(Constants.HUFFMAN_FILE_EXTENSION);
102+
if (!validateFileSelected()) return;
103+
104+
statusLabel.setText("🗜️ Compressing with Huffman...");
105+
File outputFile = compressionHandler.compressWithHuffman(fileHandler.getSelectedFile());
106+
107+
if (outputFile != null) {
108+
fileHandler.setOutputFile(outputFile);
109+
updateCompressionStats();
110+
statusLabel.setText("✅ Compression complete!");
111+
} else {
112+
statusLabel.setText("❌ Compression failed");
113+
}
36114
}
37115

38116
private void handleHuffmanDecompression() {
39-
HuffmanDecompressor.beginHuffmanDecompression(openedFile.getPath());
40-
showCompressionCompleteDialog("UnZipping");
41-
updateDecompressionStats();
117+
if (!validateFileSelected()) return;
118+
119+
statusLabel.setText("📂 Decompressing Huffman file...");
120+
File outputFile = decompressionHandler.decompressHuffman(fileHandler.getSelectedFile());
121+
122+
if (outputFile != null) {
123+
fileHandler.setOutputFile(outputFile);
124+
updateDecompressionStats();
125+
statusLabel.setText("✅ Decompression complete!");
126+
} else {
127+
statusLabel.setText("❌ Decompression failed");
128+
}
42129
}
43130

44131
private void handleLZWCompression() {
45-
LzwCompressor.beginLzwCompression(openedFile.getPath());
46-
showCompressionCompleteDialog("Zipping");
47-
updateFileStats(Constants.LZW_FILE_EXTENSION);
132+
if (!validateFileSelected()) return;
133+
134+
statusLabel.setText("🗜️ Compressing with LZW...");
135+
File outputFile = compressionHandler.compressWithLZW(fileHandler.getSelectedFile());
136+
137+
if (outputFile != null) {
138+
fileHandler.setOutputFile(outputFile);
139+
updateCompressionStats();
140+
statusLabel.setText("✅ Compression complete!");
141+
} else {
142+
statusLabel.setText("❌ Compression failed");
143+
}
48144
}
49145

50146
private void handleLZWDecompression() {
51-
LzwDecompressor.beginLzwDecompression(openedFile.getPath());
52-
showCompressionCompleteDialog("UnZipping");
53-
updateDecompressionStats();
54-
}
147+
if (!validateFileSelected()) return;
148+
149+
statusLabel.setText("📂 Decompressing LZW file...");
150+
File outputFile = decompressionHandler.decompressLZW(fileHandler.getSelectedFile());
55151

56-
private void showCompressionCompleteDialog(String operation) {
57-
JOptionPane.showMessageDialog(null,
58-
"..........................." + operation + " Finished..........................",
59-
"Status", JOptionPane.PLAIN_MESSAGE);
152+
if (outputFile != null) {
153+
fileHandler.setOutputFile(outputFile);
154+
updateDecompressionStats();
155+
statusLabel.setText("✅ Decompression complete!");
156+
} else {
157+
statusLabel.setText("❌ Decompression failed");
158+
}
60159
}
61160

62-
private void updateFileStats(String extension) {
63-
originalSizeValue.setText(openedFile.length() + "Bytes");
64-
outputFile = new File(openedFile.getPath() + extension);
65-
compressedSize = outputFile.length();
66-
compressedSizeValue.setText(compressedSize + "Bytes");
161+
private void updateCompressionStats() {
162+
File inputFile = fileHandler.getSelectedFile();
163+
File outputFile = fileHandler.getOutputFile();
164+
165+
originalSizeValue.setText(fileHandler.formatFileSize(inputFile.length()));
166+
compressedSizeValue.setText(fileHandler.formatFileSize(outputFile.length()));
167+
168+
// Calculate and show compression ratio
169+
double ratio = compressionHandler.calculateCompressionRatio(
170+
inputFile.length(), outputFile.length());
171+
172+
if (ratio > 0) {
173+
statusLabel.setText(String.format("✅ Compression complete! Saved %.1f%%", ratio));
174+
}
67175
}
68176

69177
private void updateDecompressionStats() {
70-
originalSizeValue.setText(openedFile.length() + "Bytes");
71-
String s = openedFile.getPath();
72-
s = s.substring(0, s.length() - 6);
73-
outputFile = new File(s);
74-
compressedSize = outputFile.length();
75-
compressedSizeValue.setText(compressedSize + "Bytes");
178+
File inputFile = fileHandler.getSelectedFile();
179+
File outputFile = fileHandler.getOutputFile();
180+
181+
originalSizeValue.setText(fileHandler.formatFileSize(inputFile.length()));
182+
compressedSizeValue.setText(fileHandler.formatFileSize(outputFile.length()));
76183
}
77184

185+
@Override
78186
public void actionPerformed(ActionEvent e) {
79187
if (e.getSource() == huffmanCompressButton) {
80188
handleHuffmanCompression();
@@ -89,7 +197,30 @@ public void actionPerformed(ActionEvent e) {
89197
}
90198
}
91199

200+
// Getter methods for testing
201+
public JTextField getFilePathField() { return filePathField; }
202+
public JLabel getOriginalSizeValue() { return originalSizeValue; }
203+
public JLabel getCompressedSizeValue() { return compressedSizeValue; }
204+
public JLabel getStatusLabel() { return statusLabel; }
205+
public JButton getHuffmanCompressButton() { return huffmanCompressButton; }
206+
public JButton getHuffmanDecompressButton() { return huffmanDecompressButton; }
207+
public JButton getLzwCompressButton() { return lzwCompressButton; }
208+
public JButton getLzwDecompressButton() { return lzwDecompressButton; }
209+
public JButton getExitButton() { return exitButton; }
210+
public File getOpenedFile() { return fileHandler.getSelectedFile(); }
211+
212+
/**
213+
* Main entry point for the application
214+
*/
92215
public static void main(String[] args) {
93-
MainFrame.init();
216+
logger.info("Starting File Compressor application");
217+
logger.debug("Java version: {}", System.getProperty("java.version"));
218+
logger.debug("OS: {} {}", System.getProperty("os.name"), System.getProperty("os.version"));
219+
220+
Main app = new Main();
221+
JPanel contentPane = app.createContentPane();
222+
MainWindow.init(contentPane, e -> app.handleFileOpen());
223+
224+
logger.info("Application UI initialized successfully");
94225
}
95226
}

0 commit comments

Comments
 (0)