Files
VisualSapfor/src/Visual_DVM_2021/Passes/Pass.java

447 lines
17 KiB
Java
Raw Normal View History

package Visual_DVM_2021.Passes;
2024-10-09 23:37:58 +03:00
import Common.Current_;
2024-10-07 14:22:52 +03:00
import Common.Utils.CommonUtils;
2024-10-08 22:33:49 +03:00
import Common.Visual.CommonUI;
2024-10-09 22:01:19 +03:00
import _VisualDVM.Current;
2024-10-09 22:21:57 +03:00
import _VisualDVM.GlobalData.GlobalDatabase;
import _VisualDVM.Global;
2024-10-09 22:01:19 +03:00
import _VisualDVM.Visual.Controls.PassButton;
import _VisualDVM.Visual.Controls.PassControl;
import _VisualDVM.Visual.Menus.StablePassMenuItem;
import _VisualDVM.Visual.UI;
2023-09-17 22:13:42 +03:00
import Common.Utils.Stopwatch;
import Common.Utils.TextLog;
import Visual_DVM_2021.PassStats.PassStats;
import Visual_DVM_2021.Passes.UI.PassForm;
2023-09-17 22:13:42 +03:00
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.util.LinkedHashMap;
import java.util.Stack;
import java.util.Vector;
import java.util.concurrent.Semaphore;
2024-10-09 23:37:58 +03:00
public class Pass<T> {
public static Vector<Pass> FAPasses = new Vector<>();
2023-09-17 22:13:42 +03:00
//</editor-fold>
//-
2024-10-09 23:37:58 +03:00
public static LinkedHashMap<PassCode, Pass> passes = new LinkedHashMap<>();
2023-09-17 22:13:42 +03:00
public PassStats stats = null;
public int callsCount = 0; //число вызовов прохода за текущий сеанс визуализатора.
public T target; //главный аргумент.
public PassState state = PassState.Inactive; //текущее состояние прохода.
public Semaphore animation_sem;
//--------------
public Vector<PassControl> controls = new Vector<>();
public TextLog Log; //внутренний журнал прохода.
2023-09-17 22:13:42 +03:00
protected boolean interrupt;
protected SwingWorker dispatcher = null;
private PassForm form = null;
protected JMenuItem menuItem = null;
private JButton button = null;
private JButton tabButton = null;
private Exception last_error; //последнее пойманное исключение выполнения.
//->>
public static Throwable getCauseRec(Throwable ex) {
Throwable cause = ex.getCause();
return (cause == null) ? ex : getCauseRec(cause);
}
2024-10-09 23:37:58 +03:00
public static void setPassesControlsVisible(boolean flag, PassCode... codes_in) {
for (PassCode code_in : codes_in)
2023-09-17 22:13:42 +03:00
passes.get(code_in).setControlsVisible(flag);
}
//важно. вызывать только если есть интерфейс.
public static void CheckAllStats() throws Exception {
2024-10-09 23:37:58 +03:00
for (Pass pass : FAPasses) {
if (!((GlobalDatabase)CommonUtils.db).passStats.Data.containsKey(pass.code()))
CommonUtils.db.Insert(pass.stats = new PassStats(pass));
else pass.stats = ((GlobalDatabase)CommonUtils.db).passStats.Data.get(pass.code());
2023-09-17 22:13:42 +03:00
}
FAPasses.sort(new SortPassesByStats());
}
public static void CreateAll() {
2024-10-09 23:37:58 +03:00
for (PassCode code : PassCode.values()) {
if (code != PassCode.Undefined) {
2023-09-17 22:13:42 +03:00
try {
Class<?> clazz = Class.forName("Visual_DVM_2021.Passes.All." + code.toString());
2024-10-09 23:37:58 +03:00
Pass pass = ((Pass) clazz.newInstance());
2023-09-17 22:13:42 +03:00
passes.put(code, pass);
if (pass.hasStats())
FAPasses.add(pass);
} catch (Exception ex) {
2024-10-07 22:04:09 +03:00
CommonUtils.MainLog.PrintException(ex);
2023-09-17 22:13:42 +03:00
}
}
}
}
//<editor-fold desc="Интерфейс">
//https://www.delftstack.com/ru/howto/java/java-resize-image/
public String getIconPath() {
return null;
}
public Icon getTabIcon(){
return CommonUtils.getTabIcon(getIconPath());
2023-09-17 22:13:42 +03:00
}
public AbstractAction getControlAction() {
return new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
UpdateStatsIfNeed();
Do();
}
};
}
public String getButtonText() {
return getDescription();
}
public JMenuItem createMenuItem() {
if (menuItem == null)
menuItem = new StablePassMenuItem(this);
return menuItem;
}
public JButton createButton() {
if (button == null)
button = new PassButton(this);
return button;
}
public JButton createTabButton() {
if (tabButton == null)
tabButton = new PassButton(this, true);
return tabButton;
}
public void setControlsEnabled(boolean flag) {
for (PassControl control : controls)
control.setEnabled(flag);
}
public void setControlsVisible(boolean flag) {
for (PassControl control : controls)
control.setVisible(flag);
}
public void setControlsToolTipText(String text) {
for (PassControl control : controls)
control.setToolTipText(text);
}
protected void FocusResult() {
}
protected boolean hasStats() {
return false;
}
public void UpdateStatsIfNeed() {
if (hasStats()) {
stats.Inc();
try {
CommonUtils.db.Update(stats);
2023-09-17 22:13:42 +03:00
FAPasses.sort(new SortPassesByStats());
if (Current.HasProject())
UI.fastAccessMenuBar.Refresh();
} catch (Exception ex) {
2024-10-07 22:04:09 +03:00
CommonUtils.MainLog.PrintException(ex);
2023-09-17 22:13:42 +03:00
}
}
}
2024-10-09 23:37:58 +03:00
public PassCode code() {
return PassCode.valueOf(getClass().getSimpleName());
2023-09-17 22:13:42 +03:00
}
public boolean isDone() {
return state == PassState.Done;
}
public void setDone() {
state = PassState.Done;
}
public String getDescription() {
return code().getDescription();
}
public String getStartDescription() {
return getDescription();
}
protected void FocusBeforeStart() {
//отображение вкладок.
}
//-
//объединение старых методов InitArgs и CanStart. зачастую семантика у них пересекалась.
protected boolean canStart(Object... args) throws Exception {
return true;
}
//-
protected void body() throws Exception {
}
protected boolean validate() {
return true;
}
//-
protected void performCanNotStart() throws Exception {
}
protected void showCanNotStart() throws Exception {
}
protected void performPreparation() throws Exception {
}
protected void showPreparation() throws Exception {
}
protected void performFinish() throws Exception {
}
protected void showFinish() throws Exception {
}
protected void performDone() throws Exception {
}
protected void showDone() throws Exception {
}
protected void performFail() throws Exception {
}
protected void showFail() throws Exception {
}
//-
private void PerformCanNotStart() throws Exception {
performCanNotStart();
2024-10-08 22:33:49 +03:00
if (CommonUI.isActive())
2023-09-17 22:13:42 +03:00
showCanNotStart();
}
protected void PerformPreparation() throws Exception {
performPreparation();
2024-10-08 22:33:49 +03:00
if (CommonUI.isActive())
2023-09-17 22:13:42 +03:00
showPreparation();
}
private void PerformFinish() throws Exception {
performFinish();
//-
2024-10-08 22:33:49 +03:00
if (CommonUI.isActive())
2023-09-17 22:13:42 +03:00
showFinish();
}
private void PerformDone() throws Exception {
performDone();
//-
2024-10-08 22:33:49 +03:00
if (CommonUI.isActive())
2023-09-17 22:13:42 +03:00
showDone();
}
private void PerformFail() throws Exception {
performFail();
//-
2024-10-08 22:33:49 +03:00
if (CommonUI.isActive())
2023-09-17 22:13:42 +03:00
showFail();
}
//------
2024-10-09 23:37:58 +03:00
protected PassCode necessary() {
2023-09-17 22:13:42 +03:00
return null;
}
protected boolean resetsNecessary() {
return false;
}
public void Reset() {
if (state == PassState.Done)
state = PassState.Inactive;
}
//------
2024-10-09 23:37:58 +03:00
protected void createStack_r(Stack<Pass> ToDo, Vector<String> ToPrint) {
2023-09-17 22:13:42 +03:00
ToDo.push(this);
if (needsConfirmations() // если UI нет, сюда он не дойдет.
) {
ToPrint.add(this.getStartDescription());
}
if (necessary() != null) {
2024-10-09 23:37:58 +03:00
Pass next = passes.get(necessary());
2023-09-17 22:13:42 +03:00
if (resetsNecessary() || !next.isDone())
next.createStack_r(ToDo, ToPrint);
}
}
public boolean Do(Object... args) {
2024-10-09 23:37:58 +03:00
Stack<Pass> ToDo = new Stack<>();
2023-09-17 22:13:42 +03:00
Vector<String> ToPrint = new Vector<>();
createStack_r(ToDo, ToPrint);
if (Global.properties.ConfirmPassesStart && !ToPrint.isEmpty() &&
2024-10-08 22:33:49 +03:00
!CommonUI.Question("Выполнить проход(ы):\n" + String.join("\n", ToPrint))
2023-09-17 22:13:42 +03:00
) return false;
while (ToDo.size() > 1) {
if (!ToDo.pop().start()) return false;
}
if (start(args)) {
if (Global.properties.FocusPassesResult)
FocusResult();
//-
if (Global.properties.ShowPassesDone && !ToPrint.isEmpty()
) {
2024-10-08 22:33:49 +03:00
CommonUI.Info("Проход(ы)\n\n" + String.join("\n", ToPrint) +
2023-09-17 22:13:42 +03:00
"\nуспешно выполнен(ы)!");
}
//-
return true;
}
return false;
}
//-
//<editor-fold desc="Анимация">
protected boolean needsAnimation() {
return false;
}
public void Interrupt() throws Exception {
2024-10-08 22:33:49 +03:00
CommonUI.Info("Проход " + CommonUtils.Brackets(getDescription()) + " не разрешено прерывать.");
2023-09-17 22:13:42 +03:00
}
public boolean needsConfirmations() {
return false;
}
//</editor-fold>
//-
protected void CheckException(Exception ex) {
if (ex instanceof PassException) {
Log.Writeln_(ex.getMessage());
} else
2024-10-07 22:04:09 +03:00
CommonUtils.MainLog.PrintException(ex);
2023-09-17 22:13:42 +03:00
}
public boolean start(Object... args) {
//------------------------------->
interrupt = false;
callsCount++;
Stopwatch timer = new Stopwatch();
state = PassState.Inactive;
last_error = null;
target = null;
Log = new TextLog();
if (!getDescription().isEmpty())
2024-10-08 23:33:00 +03:00
CommonUtils.MainLog.Print(getDescription() + " стартует..");
2023-09-17 22:13:42 +03:00
timer.Start();
//------------------------------->
try {
2024-10-08 22:33:49 +03:00
if (CommonUI.isActive()) FocusBeforeStart();
2023-09-17 22:13:42 +03:00
if (canStart(args)) {
PerformPreparation();
//todo тут должна быть вилка на анимацию?
2024-10-08 22:33:49 +03:00
if (CommonUI.isActive() && needsAnimation()) {
2023-09-17 22:13:42 +03:00
animation_sem = new Semaphore(1);
animation_sem.acquire();
//---
form = null;
2024-10-09 23:37:58 +03:00
Current_.set(Current.PassForm, null);
2023-09-17 22:13:42 +03:00
System.gc();
//--
2024-10-09 23:37:58 +03:00
Current_.set(Current.PassForm, form = new PassForm(this));
2023-09-17 22:13:42 +03:00
dispatcher = new SwingWorker() {
@Override
protected Object doInBackground() {
// UI.Print(DebugPrintLevel.Passes, "фоновое выполнение началось");
try {
body();
} catch (Exception ex) {
last_error = ex;
}
// UI.Print(DebugPrintLevel.Passes, "Ожидание активации окна анимации ");
//ждем пока окно откроется и освободит его.
try {
animation_sem.acquire();
} catch (InterruptedException e) {
2024-10-07 22:04:09 +03:00
CommonUtils.MainLog.PrintException(e);
2023-09-17 22:13:42 +03:00
}
//и уничтожаем его.
// UI.Print(DebugPrintLevel.Passes, "Окно анимации активировано.");
form.dispose();
form = null;
// UI.Print(DebugPrintLevel.Passes, "Окно анимации закрыто.");
animation_sem.release();
return null;
}
@Override
protected void done() {
//тут ничего не анализируем. события - отдельный поток. тут это не нужно
}
};
dispatcher.execute();
form.ShowDialog();
// UI.Print(DebugPrintLevel.Passes, "фоновое выполнение закончено, обработка резульатов");
if (last_error != null) {
state = PassState.Crushed;
CheckException(last_error);
}
// UI.Print(DebugPrintLevel.Passes, "OK");
dispatcher = null;
} else {
//исключения во время выполнения возможны в штатном режиме.
try {
body();
} catch (Exception ex) {
state = PassState.Crushed;//упал при выполнении.
CheckException(ex);
}
}
//---
// UI.Info(this.getClass().getSimpleName()+" +");
PerformFinish();
// UI.Info(this.getClass().getSimpleName()+" ++");
//---
if ((state != PassState.Crushed) && validate()) {
state = PassState.Done;
PerformDone();
} else {
state = PassState.Failed;
PerformFail();
}
} else {
state = PassState.CantStart;
PerformCanNotStart();
}
} catch (Exception ex) {
state = PassState.ExternalCrushed;
2024-10-07 22:04:09 +03:00
CommonUtils.MainLog.PrintException(ex);
2023-09-17 22:13:42 +03:00
}
//------------------------------->
timer.Stop();
if (!getDescription().isEmpty()) {
2024-10-08 23:33:00 +03:00
CommonUtils.MainLog.Print(
2023-09-17 22:13:42 +03:00
getDescription() +
" окончен за " + timer.Print() +
2024-10-07 14:22:52 +03:00
" состояние " + CommonUtils.Brackets(state.getDescription())
2023-09-17 22:13:42 +03:00
);
2024-10-08 22:33:49 +03:00
if (!Log.isEmpty() && CommonUI.isActive())
CommonUI.Error(
2024-10-07 14:22:52 +03:00
"проход " + CommonUtils.Brackets(getDescription()) + "\n" + state.getDescription() + "\n\n" +
2023-09-17 22:13:42 +03:00
Log.toString());
}
//------------------------------->
return isDone();
}
//--
public void ShowSapforMessage(String message) {
2024-10-08 22:33:49 +03:00
if (CommonUI.isActive() && form != null) {
2023-09-17 22:13:42 +03:00
String[] data = message.split(":");
switch (data[0]) {
case "message_1":
form.fields.Label1.setText((data.length > 1) ? data[1] : "");
break;
case "message_2":
form.fields.Label2.setText((data.length > 1) ? data[1] : "");
break;
case "progress":
form.fields.ProgressBar.setValue((data.length > 1) ? Integer.parseInt(data[1]) : 0);
break;
}
2024-10-07 14:22:52 +03:00
} else System.out.println(CommonUtils.Brackets(message));
2023-09-17 22:13:42 +03:00
}
public void ShowMessage1(String message) {
if (form != null)
form.fields.Label1.setText((message.length() > 1) ? message : "");
2024-10-07 14:22:52 +03:00
else System.out.println(CommonUtils.Brackets(message));
2023-09-17 22:13:42 +03:00
}
public void ShowMessage2(String message) {
if (form != null)
form.fields.Label2.setText((message.isEmpty() ? "" : message));
2024-10-07 14:22:52 +03:00
else System.out.println(CommonUtils.Brackets(message));
2023-09-17 22:13:42 +03:00
}
public void ShowProgress(int total, int current, boolean auto) {
if (form != null) {
form.lTitle.setText(getDescription() + " " + (current + 1) + "/" + total);
if (auto) {
double dp = ((double) current / total) * 100;
int p = (int) dp;
form.fields.ProgressBar.setValue(p);
}
}
}
public void ShowProgress2(int total, int current, String comment) {
if (form != null) {
form.fields.Label2.setText(comment + " " + current + "/" + total);
double dp = ((double) current / total) * 100;
int p = (int) dp;
form.fields.ProgressBar.setValue(p);
}
}
public void ShowProgressTextOnly(int total, int current, String comment) {
if (form != null)
form.lTitle.setText(form.lTitle.getText() + " : " + comment + " " + current + "/" + total);
}
}