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;
|
2024-10-14 20:57:18 +03:00
|
|
|
|
import Common.Visual.Menus.VisualiserMenuBar;
|
2024-10-15 15:13:57 +03:00
|
|
|
|
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> {
|
2025-03-26 16:12:00 +03:00
|
|
|
|
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;
|
2025-03-26 16:12:00 +03:00
|
|
|
|
//невидимый пробел 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
|
|
|
|
}
|
2025-03-26 16:12:00 +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();
|
|
|
|
|
|
}
|
2024-10-24 23:40:24 +03:00
|
|
|
|
public abstract Object getDefaultCurrentObject();
|
2023-09-17 22:13:42 +03:00
|
|
|
|
public void ApplyObject() {
|
2024-10-25 02:08:23 +03:00
|
|
|
|
if (getDefaultCurrentObject() != null)
|
2024-10-24 23:40:24 +03:00
|
|
|
|
ApplyObject(getDefaultCurrentObject());
|
|
|
|
|
|
else UI.Info("Текущий объект для сравнения не назначен!");
|
2023-09-17 22:13:42 +03:00
|
|
|
|
}
|
2024-10-24 23:40:24 +03:00
|
|
|
|
public void ApplyObject(Object object_in) {
|
2024-03-04 20:29:05 +03:00
|
|
|
|
RemoveObject();
|
2024-10-14 15:19:13 +03:00
|
|
|
|
object = (T) object_in;
|
2024-03-04 20:29:05 +03:00
|
|
|
|
applyObject();
|
|
|
|
|
|
showObject();
|
|
|
|
|
|
}
|
2023-09-17 22:13:42 +03:00
|
|
|
|
private void getLines() {
|
|
|
|
|
|
lines.clear();
|
|
|
|
|
|
visible_lines.clear();
|
2024-05-24 16:10:18 +03:00
|
|
|
|
//--
|
|
|
|
|
|
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;
|
2023-11-02 20:43:45 +03:00
|
|
|
|
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;
|
2025-03-26 16:12:00 +03:00
|
|
|
|
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)
|
2025-03-26 00:11:41 +03:00
|
|
|
|
.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();
|
2025-03-26 16:12:00 +03:00
|
|
|
|
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) {
|
|
|
|
|
|
//различие
|
2025-03-26 16:12:00 +03:00
|
|
|
|
switch (c) {
|
2025-03-26 02:07:22 +03:00
|
|
|
|
case cseparator:
|
|
|
|
|
|
//кончилось различие
|
2025-03-26 16:12:00 +03:00
|
|
|
|
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:
|
|
|
|
|
|
//началось различие
|
2025-03-26 16:12:00 +03:00
|
|
|
|
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())
|
2025-03-26 16:12:00 +03:00
|
|
|
|
current_diff_num = 0;
|
2025-03-26 02:07:22 +03:00
|
|
|
|
}
|
2025-03-26 16:12:00 +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;
|
2025-03-26 16:12:00 +03:00
|
|
|
|
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();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|