Files
VisualSapfor/src/_VisualDVM/Visual/Windows/ComparisonForm.java

374 lines
13 KiB
Java
Raw Normal View History

2024-10-09 22:15:56 +03:00
package _VisualDVM.Visual.Windows;
2024-10-07 14:22:52 +03:00
import Common.CommonConstants;
2024-10-14 15:19:13 +03:00
import Common.Database.Objects.DBObject;
import Common.Passes.Pass;
2024-10-11 00:00:30 +03:00
import Common.Utils.Utils_;
2024-10-14 15:19:13 +03:00
import Common.Visual.Controls.ShortLabel;
2025-03-13 00:32:20 +03:00
import Common.Visual.Editor.BaseEditor;
import Common.Visual.Menus.VisualiserMenuBar;
import Common.Visual.UI;
import _VisualDVM.ProjectData.Files.UI.Editor.SPFEditor;
2024-10-14 15:19:13 +03:00
import _VisualDVM.Utils;
2025-03-25 18:56:18 +03:00
import com.github.difflib.text.DiffRow;
import com.github.difflib.text.DiffRowGenerator;
2023-09-17 22:13:42 +03:00
import javafx.util.Pair;
import org.fife.ui.rtextarea.RTextScrollPane;
import javax.swing.*;
2025-03-26 02:07:22 +03:00
import javax.swing.text.Highlighter;
2025-03-26 02:43:58 +03:00
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
2025-03-25 18:56:18 +03:00
import java.util.List;
2023-09-17 22:13:42 +03:00
import java.util.Vector;
2023-10-30 22:37:03 +03:00
public abstract class ComparisonForm<T> {
final String separator = "\u200B";
final char cseparator = '\u200B';
2023-09-17 22:13:42 +03:00
public Class<T> t; //класс объектов.
//-->>
2024-10-14 15:19:13 +03:00
public Vector<String> lines = new Vector<>(); //строки с учетом/неучетом пробелов. для сравнения
public Vector<String> visible_lines = new Vector<>(); //строки с нетронутыми пробелами. для отображения
2023-09-17 22:13:42 +03:00
protected JToolBar tools;
protected JLabel lObjectName;
2023-11-02 00:01:34 +03:00
protected JButton bApplyObject;
protected JButton bClose;
2023-09-17 22:13:42 +03:00
//-->>
2024-10-14 15:19:13 +03:00
protected T object = null;
//-->>
protected BaseEditor Body;
//невидимый пробел https://translated.turbopages.org/proxy_u/en-ru.ru.898e1daf-67e318c0-3fccff8a-74722d776562/https/stackoverflow.com/questions/17978720/invisible-characters-ascii
//--->>
// protected Object ownScrollModel = null;
protected Vector<Pair<Integer, Integer>> diffs = new Vector<>();
2024-10-14 15:19:13 +03:00
//-->>
2023-09-17 22:13:42 +03:00
ComparisonForm<T> this_ = null; //?
ComparisonForm<T> slave = null;
ComparisonForm<T> master = null;
//-->>
2024-10-14 15:19:13 +03:00
private JPanel content;
private JPanel editorPanel;
private JButton bCompare;
2025-03-26 02:43:58 +03:00
private JButton bPrevious;
private JButton bNext;
2023-09-17 22:13:42 +03:00
private RTextScrollPane Scroll;
//-----
private boolean events_on = false;//относится только к мастеру, отвечает за скроллы.
2025-03-26 02:43:58 +03:00
private int current_diff_num = -1;
2024-10-14 15:19:13 +03:00
public ComparisonForm(Class<T> t_in, ComparisonForm<T> slave_in) {
//-
Body = new BaseEditor();
Scroll = new RTextScrollPane(Body);
editorPanel.add(Scroll);
// ownScrollModel = Scroll.getVerticalScrollBar().getModel();
//-
t = t_in;
this_ = this;
slave = slave_in;
Scroll.setLineNumbersEnabled(true);
bApplyObject.addActionListener(e -> {
ApplyObject();
});
//--->>>
Body.setWhitespaceVisible(true);
Body.setEditable(false);
if (isMaster()) {
//<editor-fold desc="синхронизация скроллов">
slave.Scroll.getVerticalScrollBar().setModel(Scroll.getVerticalScrollBar().getModel());
//бяк быть не должно при условии что строк одинаковое количество. а это должно выполняться.
Body.addCaretListener(e -> {
if (events_on && isReady() && slave.isReady()) {
try {
int master_lineNum = Body.getCaretLineNumber();
slave.Body.setCaretPosition(slave.Body.getLineStartOffset(master_lineNum));
} catch (Exception ex) {
Utils_.MainLog.PrintException(ex);
}
}
});
//</editor-fold>
slave.master = this;
bCompare.addActionListener(e -> {
DoComparePass(isReady() && slave.isReady());
});
} else {
//рабу сравнивать не положено.
bCompare.setVisible(false);
}
//--->>>
bClose.addActionListener(e -> {
onClose();
});
2025-03-26 02:43:58 +03:00
bPrevious.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (current_diff_num != CommonConstants.Nan) {
if (current_diff_num > 0)
current_diff_num--;
else
current_diff_num = diffs.size() - 1;
ShowCurrentDiff();
}
}
});
bNext.addActionListener(e -> {
if (current_diff_num != CommonConstants.Nan) {
if (current_diff_num < diffs.size() - 1)
current_diff_num++;
else
current_diff_num = 0;
ShowCurrentDiff();
}
});
2024-10-14 15:19:13 +03:00
}
//---<<
private void ShowCurrentDiff() {
try {
int diff_line = Body.getLineOfOffset(diffs.get(current_diff_num).getKey());
Body.gotoLine_(diff_line);
} catch (Exception ex) {
ex.printStackTrace();
}
}
2024-10-14 15:19:13 +03:00
public JPanel getContent() {
return content;
}
//--->>
2023-09-17 22:13:42 +03:00
public boolean isMaster() {
return slave != null;
}
public boolean isSlave() {
return master != null;
}
//--->>
//неперегружаемые методы
protected void RemoveObject() {
object = null;
removeObject();
showNoObject();
ClearText();
}
public abstract Object getDefaultCurrentObject();
2023-09-17 22:13:42 +03:00
public void ApplyObject() {
if (getDefaultCurrentObject() != null)
ApplyObject(getDefaultCurrentObject());
else UI.Info("Текущий объект для сравнения не назначен!");
2023-09-17 22:13:42 +03:00
}
public void ApplyObject(Object object_in) {
RemoveObject();
2024-10-14 15:19:13 +03:00
object = (T) object_in;
applyObject();
showObject();
}
2023-09-17 22:13:42 +03:00
private void getLines() {
lines.clear();
visible_lines.clear();
//--
Pair<Vector<String>, Vector<String>> p = Utils.getFortranLines(getText());
lines = p.getKey();
visible_lines = p.getValue();
2023-09-17 22:13:42 +03:00
}
protected void ClearText() {
events_on = false;
Body.setText("объект не назначен");
2023-09-17 22:13:42 +03:00
}
//предполагаем что оба объекта есть и мы можем получить с них текст.
protected void Compare() throws Exception {
events_on = false;
2025-03-26 02:43:58 +03:00
current_diff_num = CommonConstants.Nan;
slave.current_diff_num = CommonConstants.Nan;
2023-09-17 22:13:42 +03:00
//-----------------------------------------------------------------------------------------------
Body.setText("");
slave.Body.setText("");
2025-03-26 02:07:22 +03:00
Body.getHighlighter().removeAllHighlights();
slave.Body.getHighlighter().removeAllHighlights();
2023-09-17 22:13:42 +03:00
getLines();
slave.getLines();
//--------------------------------------------------------------------
Vector<String> t1 = new Vector<>();
Vector<String> t2 = new Vector<>();
//------
2025-03-25 18:56:18 +03:00
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.inlineDiffByWord(true)
.ignoreWhiteSpaces(true)
.oldTag(f -> separator)
.newTag(f -> separator)
2025-03-25 18:56:18 +03:00
.build();
List<DiffRow> rows = generator.generateDiffRows(
visible_lines,
slave.visible_lines);
for (DiffRow row : rows) {
t1.add(row.getOldLine());
t2.add(row.getNewLine());
2023-09-17 22:13:42 +03:00
}
Body.setText(String.join("\n", t1));
slave.Body.setText(String.join("\n", t2));
Body.setCaretPosition(0);
slave.Body.setCaretPosition(0);
2025-03-25 18:56:18 +03:00
//--
2025-03-26 02:07:22 +03:00
fillDiffs();
slave.fillDiffs();
colorDiffs();
slave.colorDiffs();
events_on = true;
}
public void fillDiffs() {
diffs.clear();
boolean flag = false;
char[] chars = Body.getText().toCharArray();
int dif_start = CommonConstants.Nan;
int dif_end = CommonConstants.Nan;
2025-03-26 02:07:22 +03:00
for (int i = 0; i < chars.length; ++i) {
char c = chars[i];
//--
if (flag) {
//различие
switch (c) {
2025-03-26 02:07:22 +03:00
case cseparator:
//кончилось различие
dif_end = i;
flag = false;
diffs.add(new Pair<>(dif_start, dif_end));
dif_start = CommonConstants.Nan;
dif_end = CommonConstants.Nan;
2025-03-26 02:07:22 +03:00
break;
}
} else {
//поиск
switch (c) {
case cseparator:
//началось различие
dif_start = i;
flag = true;
2025-03-26 02:07:22 +03:00
break;
default:
break;
}
}
2025-03-25 18:56:18 +03:00
}
2025-03-26 02:43:58 +03:00
if (!diffs.isEmpty())
current_diff_num = 0;
2025-03-26 02:07:22 +03:00
}
public void colorDiffs() throws Exception {
Highlighter.HighlightPainter painter = isMaster() ? SPFEditor.RedTextPainter : SPFEditor.GreenTextPainter;
for (Pair<Integer, Integer> diff : diffs) {
Body.getHighlighter().addHighlight(diff.getKey(), diff.getValue(), painter);
2023-09-17 22:13:42 +03:00
}
}
public void Show() throws Exception {
events_on = false;
2025-03-26 02:43:58 +03:00
current_diff_num = CommonConstants.Nan;
slave.current_diff_num = CommonConstants.Nan;
2023-09-17 22:13:42 +03:00
//----------------------------------------------------------------------------------------------
Body.setText("");
slave.Body.setText("");
2025-03-26 02:07:22 +03:00
Body.getHighlighter().removeAllHighlights();
slave.Body.getHighlighter().removeAllHighlights();
2023-09-17 22:13:42 +03:00
int d = 0;
getLines();
slave.getLines();
//--------------------------------------------------------------------
Vector<String> t1 = new Vector<>();
Vector<String> t2 = new Vector<>();
//------
t1.addAll(visible_lines);
t2.addAll(slave.visible_lines);
//просто выясняем кто из них длиннее, и короткий дополняем пустыми строками.]
int delta = Math.abs(t1.size() - t2.size());
if (lines.size() > slave.lines.size()) {
Utils.addEmptyLines(t2, delta);
} else if (lines.size() < slave.lines.size()) {
Utils.addEmptyLines(t1, delta);
}
///----------------
Body.setText(String.join("\n", t1));
slave.Body.setText(String.join("\n", t2));
Body.setCaretPosition(0);
slave.Body.setCaretPosition(0);
events_on = true;
}
//Перегружаемые методы.
//--->>
protected void showNoObject() {
lObjectName.setText("?");
lObjectName.setToolTipText("Объект не назначен.");
}
protected void showObject() {
2023-10-30 22:37:03 +03:00
if (object instanceof DBObject) {
DBObject dbObject = (DBObject) object;
lObjectName.setText(dbObject.toString());
lObjectName.setToolTipText(dbObject.toString());
}
2023-09-17 22:13:42 +03:00
}
protected void removeObject() {
}
protected void applyObject() {
}
protected abstract String getText();
protected boolean fortranWrapsOn() {
return false;
}
//-->>
private void createUIComponents() {
// TODO: place custom component creation code here
lObjectName = new ShortLabel(40);
tools = new VisualiserMenuBar();
}
//для сравнения по кнопке.
public boolean isReady() {
return object != null;
}
public void onClose() {
RemoveObject();
}
public void DoComparePass(boolean startCondition) {
2024-10-09 23:37:58 +03:00
Pass pass = new Pass() {
2023-09-17 22:13:42 +03:00
@Override
public String getDescription() {
return "Сравнение";
}
@Override
protected boolean needsAnimation() {
return true;
}
@Override
public boolean needsConfirmations() {
return false;
}
@Override
protected boolean canStart(Object... args) throws Exception {
return startCondition;
}
@Override
protected void body() throws Exception {
Compare();
}
};
pass.Do();
}
public void DoShowPass(boolean startCondition) {
2024-10-09 23:37:58 +03:00
Pass pass = new Pass() {
2023-09-17 22:13:42 +03:00
@Override
public String getDescription() {
return "Отображение";
}
@Override
protected boolean needsAnimation() {
return false;
}
@Override
public boolean needsConfirmations() {
return false;
}
@Override
protected boolean canStart(Object... args) throws Exception {
return startCondition;
}
@Override
protected void body() throws Exception {
Show();
}
};
pass.Do();
}
}