Files
VisualSapfor/src/Visual_DVM_2021/UI/Main/ComparisonForm.java
2023-09-29 21:46:08 +03:00

436 lines
17 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package Visual_DVM_2021.UI.Main;
import Common.Constants.Constants;
import Common.Current;
import Common.Database.DBObject;
import Common.Global;
import Common.UI.Editor.BaseEditor;
import Common.UI.Label.ShortLabel;
import Common.UI.Menus_2023.VisualiserMenuBar;
import Common.UI.UI;
import Common.Utils.TextLog;
import Common.Utils.Utils;
import GlobalData.Settings.SettingName;
import Visual_DVM_2021.Passes.Pass_2021;
import javafx.util.Pair;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaHighlighter;
import org.fife.ui.rtextarea.RTextScrollPane;
import javax.swing.*;
import java.util.LinkedHashMap;
import java.util.Vector;
public abstract class ComparisonForm<T extends DBObject> {
public Class<T> t; //класс объектов.
//-->>
private JPanel content;
public JPanel getContent() {
return content;
}
protected JToolBar tools;
private JPanel editorPanel;
protected JLabel lObjectName;
private JButton bApplyObject;
private JButton bPrevious;
private JButton bNext;
private JButton bCompare;
private JButton bClose;
//-->>
ComparisonForm<T> this_ = null; //?
ComparisonForm<T> slave = null;
ComparisonForm<T> master = null;
//-->>
protected T object = null;
//-->>
protected BaseEditor Body;
private RTextScrollPane Scroll;
//-->>
public Vector<String> lines = new Vector<>(); //строки с учетом/неучетом пробелов. для сравнения
public Vector<String> visible_lines = new Vector<>(); //строки с нетронутыми пробелами. для отображения
//подсветка.
public LinkedHashMap<Integer, Pair<Integer, Boolean>> colors = new LinkedHashMap<>();
public RSyntaxTextAreaHighlighter slave_highlighter = null; //погонщик рабов
//-----
private boolean events_on = false;//относится только к мастеру, отвечает за скроллы.
private int current_diff_line = -1;
//--->>
public boolean isMaster() {
return slave != null;
}
public boolean isSlave() {
return master != null;
}
//--->>
//неперегружаемые методы
protected void RemoveObject() {
object = null;
removeObject();
showNoObject();
ClearText();
if (isMaster())
slave.ClearText();
else if (isSlave())
master.ClearText();
}
public void ApplyObject() {
RemoveObject();
TextLog log = new TextLog();
if (Current.Check(log, getCurrentObjectName())) {
object = (T) Current.get(getCurrentObjectName());
applyObject();
showObject();
} else
UI.Info(log.toString());
}
private void ShowCurrentDiff() {
Body.gotoLine_(colors.get(current_diff_line).getKey());
}
public static boolean CompareLines(String line1_raw, String line2_raw) {
String line1 = line1_raw;
String line2 = line2_raw;
if (!Global.db.settings.get(SettingName.RegisterOn).toBoolean()) {
line1 = line1.toUpperCase();
line2 = line2.toUpperCase();
}
if (!Global.db.settings.get(SettingName.SpacesOn).toBoolean()) {
line1 = Utils.remove(line1, " ", "\t");
line2 = Utils.remove(line2, " ", "\t");
}
return line1.equals(line2);
}
public static boolean Contains(Vector<String> list, String line, int max_index) {
int last_index = -1;
for (int i = 0; i < list.size(); ++i)
if (CompareLines(list.get(i), line)) last_index = i;
return (last_index >= max_index);
}
private void getLines() {
lines.clear();
visible_lines.clear();
//1.прочитать весь текст.
char[] chars = getText().toCharArray();
//по символам получить строки.
char c = 0; //текущий символ
int i = 0; //индекс текущего символа.
StringBuilder line = new StringBuilder(); //текущая строка
StringBuilder v_line = new StringBuilder(); //текущая строка
while (i < chars.length) {
c = chars[i];
//System.out.print("`"+c+"`");
++i;
switch (c) {
case '\r': //возврат каретки, игнор
break;
case ' ':
case '\t':
if (Global.db.settings.get(SettingName.SpacesOn).toBoolean()) line.append(c);
v_line.append(c);
break;
case '\n': //конец строки
if (fortranWrapsOn()) {
//оракул. лезем в начало следующей строки
//и анализируем первые 5 символов
boolean hasWrap = false;
int wi;
//------
//System.out.println("checking wrap...");
//с нуля потому что и уже увеличено.
for (int j = 0; (j < 6) && ((wi = i + j) < chars.length); ++j) {
char s = chars[wi];
// System.out.print(s);
if ((j == 0) && ((s == 'c') || (s == 'C') || (s == '!'))) {
// System.out.println("next line is FL comment");
break;
}
if ((j > 0) && (j < 5) && (s == '!')) {
// System.out.println("next line is comment");
break;
}
if ((j == 5) && (s != ' ')) {
hasWrap = true;
i = wi + 1;
// System.out.println("next line is WRAP");
break;
}
}
// System.out.println();
//-----
if (hasWrap)
break;
}
// System.out.println();
//добавление строки в результат.
if ((line.length() > 0) || Global.db.settings.get(SettingName.EmptyLinesOn).toBoolean() &&
Global.db.settings.get(SettingName.SpacesOn).toBoolean()) {
lines.add(line.toString());
visible_lines.add(v_line.toString());
}
//сброс
line = new StringBuilder();
v_line = new StringBuilder();
break;
default:
line.append(c);
v_line.append(c);
break;
}
}
if ((i > 0) && (c != '\n')) {
//строка оборвалась на EOF
//добавление строки в результат.
if ((line.length() > 0) || Global.db.settings.get(SettingName.EmptyLinesOn).toBoolean() && Global.db.settings.get(SettingName.SpacesOn).toBoolean()) {
lines.add(line.toString());
visible_lines.add(v_line.toString());
}
}
}
protected void ClearText() {
events_on = false;
Body.setText("");
}
//предполагаем что оба объекта есть и мы можем получить с них текст.
protected void Compare() throws Exception {
events_on = false;
current_diff_line = Constants.Nan;
colors.clear();
//-----------------------------------------------------------------------------------------------
Body.setText("");
slave.Body.setText("");
int d = 0;
getLines();
slave.getLines();
//--------------------------------------------------------------------
Vector<String> t1 = new Vector<>();
Vector<String> t2 = new Vector<>();
//------
int old_j = 0;
int j = 0;
for (int i = 0; i < lines.size(); ++i) {
if (Contains(slave.lines, lines.get(i), old_j)) {
for (int k = old_j; k < slave.lines.size(); ++k) {
j = k;
if (CompareLines(lines.get(i), slave.lines.get(k))) {
j++;
t1.add(visible_lines.get(i));
t2.add(slave.visible_lines.get(k));
break;
} else {
t1.add("+");
t2.add("+ " + slave.visible_lines.get(k));
colors.put(d, new Pair(t2.size() - 1, true));
++d;
}
}
old_j = j;
} else {
//строки гарантированно нет.
t1.add("- " + visible_lines.get(i));
t2.add("- " + visible_lines.get(i));
colors.put(d, new Pair(t2.size() - 1, false));
++d;
}
}
//теперь граничное условие. если первый файл кончился а второй нет, его остаток это добавление.
for (int i = j; i < slave.lines.size(); ++i) {
t1.add("+");
t2.add("+ " + slave.visible_lines.get(i));
colors.put(d, new Pair(t2.size() - 1, true));
++d;
}
///----------------
Body.setText(String.join("\n", t1));
slave.Body.setText(String.join("\n", t2));
Body.setCaretPosition(0);
slave.Body.setCaretPosition(0);
//теперь покрас.
for (Integer diff_num : colors.keySet()) {
slave_highlighter.addHighlight(
slave.Body.getLineStartOffset(colors.get(diff_num).getKey()),
slave.Body.getLineEndOffset(colors.get(diff_num).getKey()),
colors.get(diff_num).getValue() ? UI.GoodLoopPainter : UI.BadLoopPainter
);
}
if (colors.size() > 0) current_diff_line = 0;
events_on = true;
}
public void Show() throws Exception {
events_on = false;
current_diff_line = Constants.Nan;
colors.clear();
//----------------------------------------------------------------------------------------------
Body.setText("");
slave.Body.setText("");
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 abstract Current getCurrentObjectName();
protected void showNoObject() {
lObjectName.setText("?");
lObjectName.setToolTipText("Объект не назначен.");
}
protected void showObject() {
lObjectName.setText(object.getPK().toString());
lObjectName.setToolTipText(object.getPK().toString());
}
protected void removeObject() {
}
protected void applyObject() {
}
protected abstract String getText();
protected boolean fortranWrapsOn() {
return false;
}
//--->>
// protected Object ownScrollModel = null;
//---<<
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;
bPrevious.setVisible(isMaster());
bNext.setVisible(isMaster());
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());
slave_highlighter = (RSyntaxTextAreaHighlighter) slave.Body.getHighlighter();
//бяк быть не должно при условии что строк одинаковое количество. а это должно выполняться.
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) {
Global.Log.PrintException(ex);
}
}
});
//</editor-fold>
slave.master = this;
bPrevious.addActionListener(e -> {
if (current_diff_line != Constants.Nan) {
if (current_diff_line > 0)
current_diff_line--;
else
current_diff_line = colors.size() - 1;
ShowCurrentDiff();
}
});
bNext.addActionListener(e -> {
if (current_diff_line != Constants.Nan) {
if (current_diff_line < colors.size() - 1)
current_diff_line++;
else
current_diff_line = 0;
ShowCurrentDiff();
}
});
bCompare.addActionListener(e -> {
DoComparePass(isReady() && slave.isReady());
});
} else {
//рабу сравнивать не положено.
bCompare.setVisible(false);
}
//--->>>
bClose.addActionListener(e -> {
onClose();
});
}
//-->>
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) {
Pass_2021 pass = new Pass_2021() {
@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) {
Pass_2021 pass = new Pass_2021() {
@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();
}
}