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.DiffUtils; import com.github.difflib.patch.AbstractDelta; import com.github.difflib.patch.Patch; import com.github.difflib.text.DiffRow; import com.github.difflib.text.DiffRowGenerator; import javafx.util.Pair; import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaHighlighter; import org.fife.ui.rtextarea.RTextScrollPane; import javax.swing.*; import java.util.List; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; public abstract class ComparisonForm { public Class t; //класс объектов. //-->> public Vector lines = new Vector<>(); //строки с учетом/неучетом пробелов. для сравнения public Vector visible_lines = new Vector<>(); //строки с нетронутыми пробелами. для отображения //подсветка. public RSyntaxTextAreaHighlighter slave_highlighter = null; //погонщик рабов 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 RTextScrollPane Scroll; //----- private boolean events_on = false;//относится только к мастеру, отвечает за скроллы. private int current_diff_line = -1; final String separator = "\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; //---<< 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()); 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) { Utils_.MainLog.PrintException(ex); } } }); // slave.master = this; bCompare.addActionListener(e -> { DoComparePass(isReady() && slave.isReady()); }); } else { //рабу сравнивать не положено. bCompare.setVisible(false); } //--->>> bClose.addActionListener(e -> { onClose(); }); } 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 ShowCurrentDiff() { // Body.gotoLine_(colors.get(current_diff_line).getKey()); } 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_line = CommonConstants.Nan; //----------------------------------------------------------------------------------------------- Body.setText(""); slave.Body.setText(""); int d = 0; 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); //-- Pattern master_pattern = Pattern.compile(separator + ".*" + separator); Matcher master_matcher = master_pattern.matcher(Body.getText()); while (master_matcher.find()) { Body.getHighlighter().addHighlight( master_matcher.start(), master_matcher.end(), SPFEditor.RedTextPainter ); } Pattern slave_pattern = Pattern.compile(separator + ".*" + separator); Matcher slave_matcher = slave_pattern.matcher(slave.Body.getText()); while (slave_matcher.find()) { slave_highlighter.addHighlight( slave_matcher.start(), slave_matcher.end(), SPFEditor.GreenTextPainter ); } events_on = true; } public void Show() throws Exception { events_on = false; current_diff_line = CommonConstants.Nan; //---------------------------------------------------------------------------------------------- Body.setText(""); slave.Body.setText(""); 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(); } }