file comparison improved
This commit is contained in:
parent
b1b10769e2
commit
f4cb0c4b1f
@ -20,6 +20,8 @@ public class FileComparisonDialog extends JFrame {
|
||||
private final AppConfig config;
|
||||
private JTextPane textPane1;
|
||||
private JTextPane textPane2;
|
||||
private JTextArea lineNumbers1;
|
||||
private JTextArea lineNumbers2;
|
||||
private JScrollPane scroll1;
|
||||
private JScrollPane scroll2;
|
||||
private List<String> lines1 = new ArrayList<>();
|
||||
@ -34,6 +36,7 @@ public class FileComparisonDialog extends JFrame {
|
||||
try {
|
||||
this.lines1 = readLines(file1);
|
||||
this.lines2 = readLines(file2);
|
||||
performSmartAlignment();
|
||||
} catch (IOException e) {
|
||||
JOptionPane.showMessageDialog(this, "Error reading files: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
@ -66,6 +69,14 @@ public class FileComparisonDialog extends JFrame {
|
||||
TextPaneListener listener1 = new TextPaneListener();
|
||||
textPane1.addMouseListener(listener1);
|
||||
scroll1 = new JScrollPane(textPane1);
|
||||
|
||||
lineNumbers1 = new JTextArea("1");
|
||||
lineNumbers1.setEditable(false);
|
||||
lineNumbers1.setBackground(Color.LIGHT_GRAY);
|
||||
lineNumbers1.setForeground(Color.DARK_GRAY);
|
||||
lineNumbers1.setFont(new Font("Monospaced", Font.PLAIN, 12));
|
||||
lineNumbers1.setMargin(new Insets(0, 5, 0, 5));
|
||||
scroll1.setRowHeaderView(lineNumbers1);
|
||||
|
||||
textPane2 = new JTextPane();
|
||||
textPane2.setEditable(false);
|
||||
@ -74,6 +85,14 @@ public class FileComparisonDialog extends JFrame {
|
||||
textPane2.addMouseListener(listener2);
|
||||
scroll2 = new JScrollPane(textPane2);
|
||||
|
||||
lineNumbers2 = new JTextArea("1");
|
||||
lineNumbers2.setEditable(false);
|
||||
lineNumbers2.setBackground(Color.LIGHT_GRAY);
|
||||
lineNumbers2.setForeground(Color.DARK_GRAY);
|
||||
lineNumbers2.setFont(new Font("Monospaced", Font.PLAIN, 12));
|
||||
lineNumbers2.setMargin(new Insets(0, 5, 0, 5));
|
||||
scroll2.setRowHeaderView(lineNumbers2);
|
||||
|
||||
// Synchronize scrolling
|
||||
scroll1.getVerticalScrollBar().setModel(scroll2.getVerticalScrollBar().getModel());
|
||||
|
||||
@ -153,12 +172,12 @@ public class FileComparisonDialog extends JFrame {
|
||||
if (line1 < line2) {
|
||||
int diff = line2 - line1;
|
||||
for (int i = 0; i < diff; i++) {
|
||||
lines1.add(line1, "");
|
||||
lines1.add(line1, null);
|
||||
}
|
||||
} else if (line2 < line1) {
|
||||
int diff = line1 - line2;
|
||||
for (int i = 0; i < diff; i++) {
|
||||
lines2.add(line2, "");
|
||||
lines2.add(line2, null);
|
||||
}
|
||||
}
|
||||
updateDisplay(false);
|
||||
@ -198,6 +217,15 @@ public class FileComparisonDialog extends JFrame {
|
||||
textPane2.setForeground(dark ? Color.WHITE : Color.BLACK);
|
||||
textPane1.setCaretColor(dark ? Color.WHITE : Color.BLACK);
|
||||
textPane2.setCaretColor(dark ? Color.WHITE : Color.BLACK);
|
||||
|
||||
if (lineNumbers1 != null) {
|
||||
lineNumbers1.setBackground(dark ? bg.brighter() : bg.darker());
|
||||
lineNumbers1.setForeground(dark ? Color.LIGHT_GRAY : Color.DARK_GRAY);
|
||||
}
|
||||
if (lineNumbers2 != null) {
|
||||
lineNumbers2.setBackground(dark ? bg.brighter() : bg.darker());
|
||||
lineNumbers2.setForeground(dark ? Color.LIGHT_GRAY : Color.DARK_GRAY);
|
||||
}
|
||||
}
|
||||
Font f = config.getGlobalFont();
|
||||
if (f != null) {
|
||||
@ -205,6 +233,8 @@ public class FileComparisonDialog extends JFrame {
|
||||
Font mono = new Font("Monospaced", Font.PLAIN, f.getSize());
|
||||
textPane1.setFont(mono);
|
||||
textPane2.setFont(mono);
|
||||
if (lineNumbers1 != null) lineNumbers1.setFont(mono);
|
||||
if (lineNumbers2 != null) lineNumbers2.setFont(mono);
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,6 +252,8 @@ public class FileComparisonDialog extends JFrame {
|
||||
textPane2.setText("");
|
||||
StyledDocument doc1 = textPane1.getStyledDocument();
|
||||
StyledDocument doc2 = textPane2.getStyledDocument();
|
||||
StringBuilder ln1 = new StringBuilder();
|
||||
StringBuilder ln2 = new StringBuilder();
|
||||
|
||||
Style diffStyle = textPane1.addStyle("diff", null);
|
||||
Color bg = textPane1.getBackground();
|
||||
@ -230,16 +262,35 @@ public class FileComparisonDialog extends JFrame {
|
||||
StyleConstants.setForeground(diffStyle, dark ? Color.WHITE : Color.BLACK);
|
||||
|
||||
int maxLines = Math.max(lines1.size(), lines2.size());
|
||||
for (int i = 0; i < maxLines; i++) {
|
||||
String l1 = i < lines1.size() ? lines1.get(i) : "";
|
||||
String l2 = i < lines2.size() ? lines2.get(i) : "";
|
||||
int counter1 = 1;
|
||||
int counter2 = 1;
|
||||
|
||||
boolean different = !l1.equals(l2);
|
||||
for (int i = 0; i < maxLines; i++) {
|
||||
String l1 = i < lines1.size() ? lines1.get(i) : null;
|
||||
String l2 = i < lines2.size() ? lines2.get(i) : null;
|
||||
|
||||
boolean different = (l1 == null && l2 != null) || (l1 != null && l2 == null) || (l1 != null && l2 != null && !l1.equals(l2));
|
||||
Style s = different ? diffStyle : null;
|
||||
|
||||
doc1.insertString(doc1.getLength(), l1 + "\n", s);
|
||||
doc2.insertString(doc2.getLength(), l2 + "\n", s);
|
||||
if (l1 != null) {
|
||||
doc1.insertString(doc1.getLength(), l1 + "\n", s);
|
||||
ln1.append(counter1++).append("\n");
|
||||
} else {
|
||||
doc1.insertString(doc1.getLength(), "\n", s);
|
||||
ln1.append("\n");
|
||||
}
|
||||
|
||||
if (l2 != null) {
|
||||
doc2.insertString(doc2.getLength(), l2 + "\n", s);
|
||||
ln2.append(counter2++).append("\n");
|
||||
} else {
|
||||
doc2.insertString(doc2.getLength(), "\n", s);
|
||||
ln2.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (lineNumbers1 != null) lineNumbers1.setText(ln1.toString());
|
||||
if (lineNumbers2 != null) lineNumbers2.setText(ln2.toString());
|
||||
|
||||
if (resetCaret) {
|
||||
textPane1.setCaretPosition(0);
|
||||
@ -250,6 +301,60 @@ public class FileComparisonDialog extends JFrame {
|
||||
}
|
||||
}
|
||||
|
||||
private void performSmartAlignment() {
|
||||
if (lines1.isEmpty() || lines2.isEmpty()) return;
|
||||
|
||||
// Skip alignment for very large files to avoid O(N^2) memory/time issues
|
||||
if (lines1.size() > 2000 || lines2.size() > 2000) return;
|
||||
|
||||
int n = lines1.size();
|
||||
int m = lines2.size();
|
||||
int[][] dp = new int[n + 1][m + 1];
|
||||
|
||||
// LCS computation with similarity check (exact or trimmed match)
|
||||
for (int i = 1; i <= n; i++) {
|
||||
for (int j = 1; j <= m; j++) {
|
||||
String s1 = lines1.get(i - 1);
|
||||
String s2 = lines2.get(j - 1);
|
||||
if (s1.equals(s2) || (!s1.trim().isEmpty() && s1.trim().equals(s2.trim()))) {
|
||||
dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||
} else {
|
||||
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> aligned1 = new ArrayList<>();
|
||||
List<String> aligned2 = new ArrayList<>();
|
||||
int i = n, j = m;
|
||||
while (i > 0 || j > 0) {
|
||||
if (i > 0 && j > 0) {
|
||||
String s1 = lines1.get(i - 1);
|
||||
String s2 = lines2.get(j - 1);
|
||||
if (s1.equals(s2) || (!s1.trim().isEmpty() && s1.trim().equals(s2.trim()))) {
|
||||
aligned1.add(0, s1);
|
||||
aligned2.add(0, s2);
|
||||
i--;
|
||||
j--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (j > 0 && (i == 0 || dp[i][j - 1] >= dp[i - 1][j])) {
|
||||
aligned1.add(0, null); // Added gap marker
|
||||
aligned2.add(0, lines2.get(j - 1));
|
||||
j--;
|
||||
} else if (i > 0) {
|
||||
aligned1.add(0, lines1.get(i - 1));
|
||||
aligned2.add(0, null); // Added gap marker
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
this.lines1 = aligned1;
|
||||
this.lines2 = aligned2;
|
||||
}
|
||||
|
||||
private List<String> readLines(File f) throws IOException {
|
||||
List<String> lines = new ArrayList<>();
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(f))) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user