410 lines
15 KiB
Java
410 lines
15 KiB
Java
package Common.Passes;
|
||
import Common.Utils.Utils_;
|
||
import Common.Utils.Stopwatch;
|
||
import Common.Utils.TextLog;
|
||
import Common.Visual.UI_;
|
||
import Visual_DVM_2021.PassStats.PassStats;
|
||
import Visual_DVM_2021.Passes.PassCode;
|
||
import Visual_DVM_2021.Passes.UI.PassForm;
|
||
import _VisualDVM.Current;
|
||
import _VisualDVM.Global;
|
||
import _VisualDVM.Visual.Controls.PassButton;
|
||
import _VisualDVM.Visual.Controls.PassControl;
|
||
import _VisualDVM.Visual.Menus.StablePassMenuItem;
|
||
import _VisualDVM.Visual.UI;
|
||
|
||
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;
|
||
public class Pass<T> {
|
||
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; //внутренний журнал прохода.
|
||
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 Throwable getCauseRec(Throwable ex) {
|
||
Throwable cause = ex.getCause();
|
||
return (cause == null) ? ex : getCauseRec(cause);
|
||
}
|
||
//<editor-fold desc="Интерфейс">
|
||
//https://www.delftstack.com/ru/howto/java/java-resize-image/
|
||
public String getIconPath() {
|
||
return null;
|
||
}
|
||
public Icon getTabIcon() {
|
||
return Utils_.getTabIcon(getIconPath());
|
||
}
|
||
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() {
|
||
}
|
||
public boolean hasStats() {
|
||
return false;
|
||
}
|
||
public void UpdateStatsIfNeed() {
|
||
if (hasStats()) {
|
||
try {
|
||
Global.mainModule.getDb().passStats.IncPassStat(code());
|
||
} catch (Exception ex) {
|
||
Utils_.MainLog.PrintException(ex);
|
||
}
|
||
UI.fastAccessMenuBar.Refresh();
|
||
}
|
||
}
|
||
public PassCode code() {
|
||
return PassCode.valueOf(getClass().getSimpleName());
|
||
}
|
||
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();
|
||
if (UI_.isActive())
|
||
showCanNotStart();
|
||
}
|
||
protected void PerformPreparation() throws Exception {
|
||
performPreparation();
|
||
if (UI_.isActive())
|
||
showPreparation();
|
||
}
|
||
private void PerformFinish() throws Exception {
|
||
performFinish();
|
||
//-
|
||
if (UI_.isActive())
|
||
showFinish();
|
||
}
|
||
private void PerformDone() throws Exception {
|
||
performDone();
|
||
//-
|
||
if (UI_.isActive())
|
||
showDone();
|
||
}
|
||
private void PerformFail() throws Exception {
|
||
performFail();
|
||
//-
|
||
if (UI_.isActive())
|
||
showFail();
|
||
}
|
||
//------
|
||
protected PassCode necessary() {
|
||
return null;
|
||
}
|
||
protected boolean resetsNecessary() {
|
||
return false;
|
||
}
|
||
public void Reset() {
|
||
if (state == PassState.Done)
|
||
state = PassState.Inactive;
|
||
}
|
||
//------
|
||
protected void createStack_r(Stack<Pass> ToDo, Vector<String> ToPrint) {
|
||
ToDo.push(this);
|
||
if (needsConfirmations() // если UI нет, сюда он не дойдет.
|
||
) {
|
||
ToPrint.add(this.getStartDescription());
|
||
}
|
||
if (necessary() != null) {
|
||
Pass next = Global.mainModule.getPass(necessary());
|
||
if (resetsNecessary() || !next.isDone())
|
||
next.createStack_r(ToDo, ToPrint);
|
||
}
|
||
}
|
||
public boolean Do(Object... args) {
|
||
Stack<Pass> ToDo = new Stack<>();
|
||
Vector<String> ToPrint = new Vector<>();
|
||
createStack_r(ToDo, ToPrint);
|
||
if (Global.properties.ConfirmPassesStart && !ToPrint.isEmpty() &&
|
||
!UI_.Question("Выполнить проход(ы):\n" + String.join("\n", ToPrint))
|
||
) 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()
|
||
) {
|
||
UI_.Info("Проход(ы)\n\n" + String.join("\n", ToPrint) +
|
||
"\nуспешно выполнен(ы)!");
|
||
}
|
||
//-
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
//-
|
||
//<editor-fold desc="Анимация">
|
||
protected boolean needsAnimation() {
|
||
return false;
|
||
}
|
||
public void Interrupt() throws Exception {
|
||
UI_.Info("Проход " + Utils_.Brackets(getDescription()) + " не разрешено прерывать.");
|
||
}
|
||
public boolean needsConfirmations() {
|
||
return false;
|
||
}
|
||
//</editor-fold>
|
||
//-
|
||
protected void CheckException(Exception ex) {
|
||
if (ex instanceof PassException) {
|
||
Log.Writeln_(ex.getMessage());
|
||
} else
|
||
Utils_.MainLog.PrintException(ex);
|
||
}
|
||
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())
|
||
Utils_.MainLog.Print(getDescription() + " стартует..");
|
||
timer.Start();
|
||
//------------------------------->
|
||
try {
|
||
if (UI_.isActive()) FocusBeforeStart();
|
||
if (canStart(args)) {
|
||
PerformPreparation();
|
||
//todo тут должна быть вилка на анимацию?
|
||
if (UI_.isActive() && needsAnimation()) {
|
||
animation_sem = new Semaphore(1);
|
||
animation_sem.acquire();
|
||
//---
|
||
form = null;
|
||
Global.mainModule.set(Current.PassForm, null);
|
||
System.gc();
|
||
//--
|
||
Global.mainModule.set(Current.PassForm, form = new PassForm(this));
|
||
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) {
|
||
Utils_.MainLog.PrintException(e);
|
||
}
|
||
//и уничтожаем его.
|
||
// 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;
|
||
Utils_.MainLog.PrintException(ex);
|
||
}
|
||
//------------------------------->
|
||
timer.Stop();
|
||
if (!getDescription().isEmpty()) {
|
||
Utils_.MainLog.Print(
|
||
getDescription() +
|
||
" окончен за " + timer.Print() +
|
||
" состояние " + Utils_.Brackets(state.getDescription())
|
||
);
|
||
if (!Log.isEmpty() && UI_.isActive())
|
||
UI_.Error(
|
||
"проход " + Utils_.Brackets(getDescription()) + "\n" + state.getDescription() + "\n\n" +
|
||
Log.toString());
|
||
}
|
||
//------------------------------->
|
||
return isDone();
|
||
}
|
||
//--
|
||
public void ShowSapforMessage(String message) {
|
||
if (UI_.isActive() && form != null) {
|
||
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;
|
||
}
|
||
} else System.out.println(Utils_.Brackets(message));
|
||
}
|
||
public void ShowMessage1(String message) {
|
||
if (form != null)
|
||
form.fields.Label1.setText((message.length() > 1) ? message : "");
|
||
else System.out.println(Utils_.Brackets(message));
|
||
}
|
||
public void ShowMessage2(String message) {
|
||
if (form != null)
|
||
form.fields.Label2.setText((message.isEmpty() ? "" : message));
|
||
else System.out.println(Utils_.Brackets(message));
|
||
}
|
||
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);
|
||
}
|
||
}
|