package _VisualDVM.Visual.Windows; import Common.CommonConstants; import Common.Database.Objects.DBObject; import Common.Passes.Pass; import Common.Utils.Utils_; import Common.Visual.Controls.ShortLabel; import Common.Visual.Editor.BaseEditor; import Common.Visual.Menus.VisualiserMenuBar; import Common.Visual.UI; import _VisualDVM.ProjectData.Files.UI.Editor.SPFEditor; import _VisualDVM.Utils; import com.github.difflib.text.DiffRow; import com.github.difflib.text.DiffRowGenerator; import javafx.util.Pair; import org.fife.ui.rtextarea.RTextScrollPane; import javax.swing.*; import javax.swing.text.BadLocationException; import javax.swing.text.Highlighter; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; import java.util.Vector; public abstract class ComparisonForm { public Class t; //класс объектов. //-->> public Vector lines = new Vector<>(); //строки с учетом/неучетом пробелов. для сравнения public Vector visible_lines = new Vector<>(); //строки с нетронутыми пробелами. для отображения protected JToolBar tools; protected JLabel lObjectName; protected JButton bApplyObject; protected JButton bClose; //-->> protected T object = null; //-->> protected BaseEditor Body; //-->> ComparisonForm this_ = null; //? ComparisonForm slave = null; ComparisonForm master = null; //-->> private JPanel content; private JPanel editorPanel; private JButton bCompare; private JButton bPrevious; private JButton bNext; private RTextScrollPane Scroll; //----- private boolean events_on = false;//относится только к мастеру, отвечает за скроллы. private int current_diff_num = -1; final String separator = "\u200B"; final char cseparator = '\u200B'; //невидимый пробел 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> diffs = new Vector<>(); //---<< private void ShowCurrentDiff() { try { int diff_line = Body.getLineOfOffset(diffs.get(current_diff_num).getKey()); Body.gotoLine_(diff_line); } catch (Exception ex){ ex.printStackTrace(); } } public ComparisonForm(Class t_in, ComparisonForm 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()) { // 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); } } }); // slave.master = this; bCompare.addActionListener(e -> { DoComparePass(isReady() && slave.isReady()); }); } else { //рабу сравнивать не положено. bCompare.setVisible(false); } //--->>> bClose.addActionListener(e -> { onClose(); }); 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(); } }); } public JPanel getContent() { return content; } //--->> public boolean isMaster() { return slave != null; } public boolean isSlave() { return master != null; } //--->> //неперегружаемые методы protected void RemoveObject() { object = null; removeObject(); showNoObject(); ClearText(); } public abstract Object getDefaultCurrentObject(); public void ApplyObject() { if (getDefaultCurrentObject() != null) ApplyObject(getDefaultCurrentObject()); else UI.Info("Текущий объект для сравнения не назначен!"); } public void ApplyObject(Object object_in) { RemoveObject(); object = (T) object_in; applyObject(); showObject(); } private void getLines() { lines.clear(); visible_lines.clear(); //-- Pair, Vector> p = Utils.getFortranLines(getText()); lines = p.getKey(); visible_lines = p.getValue(); } protected void ClearText() { events_on = false; Body.setText("объект не назначен"); } //предполагаем что оба объекта есть и мы можем получить с них текст. protected void Compare() throws Exception { events_on = false; current_diff_num = CommonConstants.Nan; slave.current_diff_num =CommonConstants.Nan; //----------------------------------------------------------------------------------------------- Body.setText(""); slave.Body.setText(""); Body.getHighlighter().removeAllHighlights(); slave.Body.getHighlighter().removeAllHighlights(); getLines(); slave.getLines(); //-------------------------------------------------------------------- Vector t1 = new Vector<>(); Vector t2 = new Vector<>(); //------ DiffRowGenerator generator = DiffRowGenerator.create() .showInlineDiffs(true) .inlineDiffByWord(true) .ignoreWhiteSpaces(true) .oldTag(f -> separator) .newTag(f -> separator) .build(); List rows = generator.generateDiffRows( visible_lines, slave.visible_lines); for (DiffRow row : rows) { t1.add(row.getOldLine()); t2.add(row.getNewLine()); } Body.setText(String.join("\n", t1)); slave.Body.setText(String.join("\n", t2)); Body.setCaretPosition(0); slave.Body.setCaretPosition(0); //-- 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; for (int i = 0; i < chars.length; ++i) { char c = chars[i]; //-- if (flag) { //различие switch (c){ case cseparator: //кончилось различие dif_end =i; flag=false; diffs.add(new Pair<>(dif_start,dif_end)); dif_start=CommonConstants.Nan; dif_end=CommonConstants.Nan; break; } } else { //поиск switch (c) { case cseparator: //началось различие dif_start =i; flag=true; break; default: break; } } } if (!diffs.isEmpty()) current_diff_num=0; } public void colorDiffs() throws Exception{ Highlighter.HighlightPainter painter = isMaster()? SPFEditor.RedTextPainter: SPFEditor.GreenTextPainter; for (Pair diff: diffs){ Body.getHighlighter().addHighlight(diff.getKey(),diff.getValue(), painter); } } public void Show() throws Exception { events_on = false; current_diff_num = CommonConstants.Nan; slave.current_diff_num =CommonConstants.Nan; //---------------------------------------------------------------------------------------------- Body.setText(""); slave.Body.setText(""); Body.getHighlighter().removeAllHighlights(); slave.Body.getHighlighter().removeAllHighlights(); int d = 0; getLines(); slave.getLines(); //-------------------------------------------------------------------- Vector t1 = new Vector<>(); Vector 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() { if (object instanceof DBObject) { DBObject dbObject = (DBObject) object; lObjectName.setText(dbObject.toString()); lObjectName.setToolTipText(dbObject.toString()); } } 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) { Pass pass = new Pass() { @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 pass = new Pass() { @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(); } }