+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PerformanceAnalyzer/1049392283/stat.json b/PerformanceAnalyzer/1049392283/stat.json
new file mode 100644
index 00000000..ded4cdb9
--- /dev/null
+++ b/PerformanceAnalyzer/1049392283/stat.json
@@ -0,0 +1 @@
+{"inter":[{"col_op":[{"comm":0.0,"ncall":8,"overlap":0.0,"real_comm":0.0,"synch":0.0,"time_var":0.0},{"comm":0.0,"ncall":0,"overlap":0.0,"real_comm":0.0,"synch":0.0,"time_var":0.0},{"comm":0.0,"ncall":0,"overlap":0.0,"real_comm":0.0,"synch":0.0,"time_var":0.0},{"comm":0.0,"ncall":0,"overlap":0.0,"real_comm":0.0,"synch":0.0,"time_var":0.0}],"id":{"expr":2000000000,"nenter":1.0,"nlev":0,"nline":6,"nline_end":64,"pname":"jac3d.f","t":21},"proc_times":[{"comm":0.0,"exec_time":0.3102550506591797,"gpu_time_lost":0.0,"gpu_time_prod":0.0,"gpu_times":null,"idle":0.0,"insuf_sys":0.0,"insuf_user":0.0,"load_imb":0.0,"lost_time":0.0,"num_gpu":0,"num_threads":0,"overlap":0.0,"prod_cpu":0.3100552558898926,"prod_io":0.0001800060272216797,"prod_sys":1.9788742065429688e-05,"real_comm":0.0,"synch":0.0,"sys_time":0.0,"th_times":null,"thr_sys_time":0.0,"thr_user_time":0.0,"time_var":0.0}],"times":{"comm":0.0,"comm_start":0.0,"efficiency":1.0,"exec_time":0.3102550506591797,"gpu_time_lost":0.0,"gpu_time_prod":0.0,"idle":0.0,"insuf":0.0,"insuf_sys":0.0,"insuf_user":0.0,"load_imb":0.0,"lost_time":0.0,"nproc":1,"overlap":0.0,"prod_cpu":0.3100552558898926,"prod_io":0.0001800060272216797,"prod_sys":1.9788742065429688e-05,"real_comm":0.0,"synch":0.0,"sys_time":0.3102550506591797,"thr_sys_time":0.0,"thr_user_time":0.0,"threadsOfAllProcs":2,"time_var":0.0}}],"iscomp":false,"nproc":1,"p_heading":"1*1","proc":[{"node_name":"mic.dvm-system.org","test_time":0.5540609359741211}]}
\ No newline at end of file
diff --git a/PerformanceAnalyzer/139606632/stat.json b/PerformanceAnalyzer/139606632/stat.json
new file mode 100644
index 00000000..519065e8
--- /dev/null
+++ b/PerformanceAnalyzer/139606632/stat.json
@@ -0,0 +1 @@
+{"inter":[{"col_op":[{"comm":0.0,"ncall":107,"overlap":0.0,"real_comm":0.0,"synch":0.09642767906188965,"time_var":0.10170316696166992},{"comm":0.09526991844177246,"ncall":100,"overlap":0.00025081634521484375,"real_comm":0.0,"synch":2.384185791015625e-05,"time_var":1.5735626220703125e-05},{"comm":0.01116180419921875,"ncall":100,"overlap":7.390975952148438e-05,"real_comm":0.0,"synch":0.0018832683563232422,"time_var":0.0013852119445800781},{"comm":0.0,"ncall":0,"overlap":0.0,"real_comm":0.0,"synch":0.0,"time_var":0.0}],"id":{"expr":2000000000,"nenter":1.0,"nlev":0,"nline":15,"nline_end":71,"pname":"jac2d.for","t":21},"proc_times":[{"comm":0.008355379104614258,"exec_time":4.960660934448242,"gpu_time_lost":0.0,"gpu_time_prod":0.0,"gpu_times":null,"idle":0.00014519691467285156,"insuf_sys":0.02597987651824951,"insuf_user":0.002836167812347412,"load_imb":0.0,"lost_time":0.03731662034988403,"num_gpu":0,"num_threads":0,"overlap":0.0,"prod_cpu":4.9148295521736145,"prod_io":0.0015007257461547852,"prod_sys":0.007159233093261719,"real_comm":0.0,"synch":0.015146493911743164,"sys_time":1.42268456e-316,"th_times":null,"thr_sys_time":0.0,"thr_user_time":0.0,"time_var":0.011813640594482422},{"comm":0.020066499710083008,"exec_time":4.960740089416504,"gpu_time_lost":0.0,"gpu_time_prod":0.0,"gpu_times":null,"idle":6.604194641113281e-05,"insuf_sys":0.022036850452423096,"insuf_user":0.0030239224433898926,"load_imb":0.006429493427276611,"lost_time":0.04519331455230713,"num_gpu":0,"num_threads":0,"overlap":0.0,"prod_cpu":4.9082671999931335,"prod_io":5.352497100830078e-05,"prod_sys":0.0072920918464660645,"real_comm":0.0,"synch":0.021478652954101563,"sys_time":1632742196.495043,"th_times":null,"thr_sys_time":0.0,"thr_user_time":0.0,"time_var":0.024171829223632813},{"comm":0.05277681350708008,"exec_time":4.960806131362915,"gpu_time_lost":0.0,"gpu_time_prod":0.0,"gpu_times":null,"idle":0.0,"insuf_sys":0.023320376873016357,"insuf_user":0.0034398436546325684,"load_imb":0.040790677070617676,"lost_time":0.079537034034729,"num_gpu":0,"num_threads":0,"overlap":0.0,"prod_cpu":4.873495638370514,"prod_io":7.098913192749023e-05,"prod_sys":0.007702469825744629,"real_comm":0.0,"synch":0.03799128532409668,"sys_time":5.51718905656e-313,"th_times":null,"thr_sys_time":0.0,"thr_user_time":0.0,"time_var":0.04065394401550293},{"comm":0.025233030319213867,"exec_time":4.960805177688599,"gpu_time_lost":0.0,"gpu_time_prod":0.0,"gpu_times":null,"idle":9.5367431640625e-07,"insuf_sys":0.022124826908111572,"insuf_user":0.0031962990760803223,"load_imb":0.011793673038482666,"lost_time":0.05055510997772217,"num_gpu":0,"num_threads":0,"overlap":0.0,"prod_cpu":4.902876079082489,"prod_io":5.5909156799316406e-05,"prod_sys":0.007319033145904541,"real_comm":0.0,"synch":0.02371835708618164,"sys_time":1.4228205e-316,"th_times":null,"thr_sys_time":0.0,"thr_user_time":0.0,"time_var":0.02646470069885254}],"times":{"comm":0.10643172264099121,"comm_start":0.0,"efficiency":0.989285910732807,"exec_time":4.960806131362915,"gpu_time_lost":0.0,"gpu_time_prod":0.0,"idle":0.00021219253540039063,"insuf":0.10595816373825073,"insuf_sys":0.09346193075180054,"insuf_user":0.012496232986450195,"load_imb":0.05901384353637695,"lost_time":0.21260207891464233,"nproc":4,"overlap":0.0003247261047363281,"prod_cpu":19.59946846961975,"prod_io":0.0016811490058898926,"prod_sys":0.029472827911376953,"real_comm":0.0,"synch":0.09833478927612305,"sys_time":19.84322452545166,"thr_sys_time":0.0,"thr_user_time":0.0,"threadsOfAllProcs":4,"time_var":0.1031041145324707}}],"iscomp":false,"nproc":4,"p_heading":"2*2","proc":[{"node_name":"mic.dvm-system.org","test_time":0.5796339511871338},{"node_name":"mic.dvm-system.org","test_time":0.5798628330230713},{"node_name":"mic.dvm-system.org","test_time":0.5795998573303223},{"node_name":"mic.dvm-system.org","test_time":0.5797138214111328}]}
\ No newline at end of file
diff --git a/PerformanceAnalyzer/1664247100/stat.json b/PerformanceAnalyzer/1664247100/stat.json
new file mode 100644
index 00000000..f96aaa5a
--- /dev/null
+++ b/PerformanceAnalyzer/1664247100/stat.json
@@ -0,0 +1 @@
+{"inter":[{"col_op":[{"comm":0.0,"ncall":107,"overlap":0.0,"real_comm":0.0,"synch":0.0,"time_var":0.0},{"comm":0.0012249946594238281,"ncall":100,"overlap":0.00010442733764648438,"real_comm":0.0,"synch":0.0,"time_var":0.0},{"comm":0.0,"ncall":100,"overlap":5.507469177246094e-05,"real_comm":0.0,"synch":0.0,"time_var":0.0},{"comm":0.0,"ncall":0,"overlap":0.0,"real_comm":0.0,"synch":0.0,"time_var":0.0}],"id":{"expr":2000000000,"nenter":1.0,"nlev":0,"nline":15,"nline_end":71,"pname":"jac2d.for","t":21},"proc_times":[{"comm":0.0012249946594238281,"exec_time":12.855837106704712,"gpu_time_lost":0.0,"gpu_time_prod":0.0,"gpu_times":null,"idle":0.0,"insuf_sys":0.0,"insuf_user":0.0,"load_imb":0.0,"lost_time":0.0012249946594238281,"num_gpu":0,"num_threads":0,"overlap":0.0,"prod_cpu":12.844730615615845,"prod_io":0.0035636425018310547,"prod_sys":0.006317853927612305,"real_comm":0.0,"synch":0.0,"sys_time":1.4784531e-316,"th_times":null,"thr_sys_time":0.0,"thr_user_time":0.0,"time_var":0.0}],"times":{"comm":0.0012249946594238281,"comm_start":0.0,"efficiency":0.9999047129604042,"exec_time":12.855837106704712,"gpu_time_lost":0.0,"gpu_time_prod":0.0,"idle":0.0,"insuf":0.0,"insuf_sys":0.0,"insuf_user":0.0,"load_imb":0.0,"lost_time":0.0012249946594238281,"nproc":1,"overlap":0.0001595020294189453,"prod_cpu":12.844730615615845,"prod_io":0.0035636425018310547,"prod_sys":0.006317853927612305,"real_comm":0.0,"synch":0.0,"sys_time":12.855837106704712,"thr_sys_time":0.0,"thr_user_time":0.0,"threadsOfAllProcs":1,"time_var":0.0}}],"iscomp":false,"nproc":1,"p_heading":"1*1","proc":[{"node_name":"mic.dvm-system.org","test_time":0.5531537532806396}]}
\ No newline at end of file
diff --git a/PerformanceAnalyzer/535943622/stat.json b/PerformanceAnalyzer/535943622/stat.json
new file mode 100644
index 00000000..cfb1ec1e
--- /dev/null
+++ b/PerformanceAnalyzer/535943622/stat.json
@@ -0,0 +1 @@
+{"inter":[{"col_op":[{"comm":0.0,"ncall":54,"overlap":0.0,"real_comm":0.0,"synch":0.0,"time_var":0.0},{"comm":0.0,"ncall":0,"overlap":0.0,"real_comm":0.0,"synch":0.0,"time_var":0.0},{"comm":0.0,"ncall":0,"overlap":0.0,"real_comm":0.0,"synch":0.0,"time_var":0.0},{"comm":0.0,"ncall":0,"overlap":0.0,"real_comm":0.0,"synch":0.0,"time_var":0.0}],"id":{"expr":2000000000,"nenter":1.0,"nlev":0,"nline":174,"nline_end":298,"pname":"bt.f","t":21},"proc_times":[{"comm":0.0,"exec_time":37.97893500328064,"gpu_time_lost":0.0,"gpu_time_prod":0.0,"gpu_times":null,"idle":0.0,"insuf_sys":0.0,"insuf_user":0.0,"load_imb":0.0,"lost_time":0.0,"num_gpu":0,"num_threads":0,"overlap":0.0,"prod_cpu":37.97744798660278,"prod_io":0.0006661415100097656,"prod_sys":0.0008208751678466797,"real_comm":0.0,"synch":0.0,"sys_time":4.080717506121202e-33,"th_times":null,"thr_sys_time":0.0,"thr_user_time":0.0,"time_var":0.0}],"times":{"comm":0.0,"comm_start":0.0,"efficiency":1.0,"exec_time":37.97893500328064,"gpu_time_lost":0.0,"gpu_time_prod":0.0,"idle":0.0,"insuf":0.0,"insuf_sys":0.0,"insuf_user":0.0,"load_imb":0.0,"lost_time":0.0,"nproc":1,"overlap":0.0,"prod_cpu":37.97744798660278,"prod_io":0.0006661415100097656,"prod_sys":0.0008208751678466797,"real_comm":0.0,"synch":0.0,"sys_time":37.97893500328064,"thr_sys_time":0.0,"thr_user_time":0.0,"threadsOfAllProcs":12,"time_var":0.0}}],"iscomp":false,"nproc":1,"p_heading":"1*1*1*1","proc":[{"node_name":"mic.dvm-system.org","test_time":0.5507678985595703}]}
\ No newline at end of file
diff --git a/PerformanceAnalyzer/622828792/stat.json b/PerformanceAnalyzer/622828792/stat.json
new file mode 100644
index 00000000..d4769aa2
--- /dev/null
+++ b/PerformanceAnalyzer/622828792/stat.json
@@ -0,0 +1 @@
+{"inter":[{"col_op":[{"comm":0.0,"ncall":107,"overlap":0.0,"real_comm":0.0,"synch":0.0,"time_var":0.0},{"comm":0.0011873245239257813,"ncall":100,"overlap":9.274482727050781e-05,"real_comm":0.0,"synch":0.0,"time_var":0.0},{"comm":0.0,"ncall":100,"overlap":5.435943603515625e-05,"real_comm":0.0,"synch":0.0,"time_var":0.0},{"comm":0.0,"ncall":0,"overlap":0.0,"real_comm":0.0,"synch":0.0,"time_var":0.0}],"id":{"expr":2000000000,"nenter":1.0,"nlev":0,"nline":15,"nline_end":71,"pname":"jac2d.for","t":21},"proc_times":[{"comm":0.0011873245239257813,"exec_time":12.533138990402222,"gpu_time_lost":0.0,"gpu_time_prod":0.0,"gpu_times":null,"idle":0.0,"insuf_sys":0.0,"insuf_user":0.0,"load_imb":0.0,"lost_time":0.0011873245239257813,"num_gpu":0,"num_threads":0,"overlap":0.0,"prod_cpu":12.522205114364624,"prod_io":0.0035867691040039063,"prod_sys":0.006159782409667969,"real_comm":0.0,"synch":0.0,"sys_time":2.49049955e-316,"th_times":null,"thr_sys_time":0.0,"thr_user_time":0.0,"time_var":0.0}],"times":{"comm":0.0011873245239257813,"comm_start":0.0,"efficiency":0.999905265191359,"exec_time":12.533138990402222,"gpu_time_lost":0.0,"gpu_time_prod":0.0,"idle":0.0,"insuf":0.0,"insuf_sys":0.0,"insuf_user":0.0,"load_imb":0.0,"lost_time":0.0011873245239257813,"nproc":1,"overlap":0.00014710426330566406,"prod_cpu":12.522205114364624,"prod_io":0.0035867691040039063,"prod_sys":0.006159782409667969,"real_comm":0.0,"synch":0.0,"sys_time":12.533138990402222,"thr_sys_time":0.0,"thr_user_time":0.0,"threadsOfAllProcs":1,"time_var":0.0}}],"iscomp":false,"nproc":1,"p_heading":"1*1","proc":[{"node_name":"mic.dvm-system.org","test_time":0.5526328086853027}]}
\ No newline at end of file
diff --git a/Planner/Array.h b/Planner/Array.h
new file mode 100644
index 00000000..f1e59f8a
--- /dev/null
+++ b/Planner/Array.h
@@ -0,0 +1,42 @@
+#include
+#include
+#include
+#pragma once
+template
+class Array {
+protected:
+ long length;
+ T** elements;
+public:
+ Array(){
+ length=0;
+ elements=NULL;
+ }
+ virtual ~Array(){
+ if (elements !=NULL){
+ for (long i=0; i {
+public:
+ CompilationSupervisor(){
+ this->init("compilationTasks", 4);
+ }
+ CompilationTask * getTaskById(long task_id){
+ for (long i=0; i< length; ++i){
+ CompilationTask * task = get(i);
+ if (task->getId()==task_id)
+ return task;
+ }
+ return NULL;
+ }
+ virtual String getStatePrefix(){
+ return String("Compilation");
+ }
+};
\ No newline at end of file
diff --git a/Planner/CompilationTask.h b/Planner/CompilationTask.h
new file mode 100644
index 00000000..ba1fb457
--- /dev/null
+++ b/Planner/CompilationTask.h
@@ -0,0 +1,47 @@
+#include "Task.h"
+#pragma once
+class CompilationTask: public Task {
+ String test_id;
+ String makefile_text;
+public:
+ void setTestId(String * test_id_in){
+ test_id = String(test_id_in->getCharArray());
+ }
+ void setMakefileText(String * makefile_text_in){
+ makefile_text = String(makefile_text_in->getCharArray(), '|');
+ }
+ virtual void print(){
+ printf("id=%ld; maxtime=%d; test_id=%s\n", id, maxtime,
+ test_id.getCharArray());
+ printf("makefile_text=%s\n", makefile_text.getCharArray());
+ }
+ CompilationTask(Text * lines, int offset):Task(lines,offset) {
+ setTestId(lines->get(offset+2));
+ setMakefileText(lines->get(offset+3));
+ setState(Waiting);
+ kernels=1;
+ }
+
+ virtual void prepareWorkspace(){
+ String makeFilePath = String(id)+"/Makefile";
+ File makeFileFile = File(makeFilePath, this->makefile_text);
+ String tests = userWorkspace+"/projects";
+ String testPath= tests+"/"+test_id;
+ String copyCommand = "cp -r " + String::DQuotes(testPath + "/.") + " "+ String::DQuotes(workspace);
+ system(copyCommand.getCharArray());
+ }
+ virtual String getLaunchScriptText(){
+ String modules = userWorkspace+"/modules";
+ String starterCall = modules+"/starter";
+ String launcherCall = modules+"/launcher";
+ return String::DQuotes(starterCall)+" "+
+ String::DQuotes(launcherCall)+" "+
+ String(maxtime)+" "+
+ String::DQuotes("")+" "+
+ "make -j -f Makefile";
+ }
+ virtual void analyseResults(){
+ String binary = workspace+"/0";
+ state = Utils::Exists(binary)? Done:DoneWithErrors;
+ }
+};
\ No newline at end of file
diff --git a/Planner/File.h b/Planner/File.h
new file mode 100644
index 00000000..06c92ffc
--- /dev/null
+++ b/Planner/File.h
@@ -0,0 +1,64 @@
+#include "Text.h"
+#pragma once
+class File {
+ FILE* ptr;
+public:
+ File(String* name) {
+ ptr = fopen(name->getCharArray(), "r");
+ }
+ File(const char * name) {
+ ptr = fopen(name, "r");
+ }
+ File(const String& name, const String& text){
+ ptr = fopen(name.getCharArray(), "w");
+ fprintf(ptr, "%s\n", text.getCharArray());
+ }
+ ~File() {
+ if (ptr != NULL) {
+ fclose(ptr);
+ ptr = NULL;
+ }
+ }
+ Text* readLines(){
+ Text* lines = new Text();
+ int c;
+ String * line = NULL;
+ bool lineStarted = false;
+ do {
+ c = fgetc(ptr);
+ if (lineStarted){
+ switch (c) {
+ case '\r':
+ break;
+ case '\n':
+ case EOF:
+ lines->add(line);
+ line = NULL;
+ lineStarted = false;
+ break;
+ default:
+ line->addChar((char)c);
+ break;
+ }
+ }else {
+ switch (c){
+ case '\r':
+ break;
+ case '\n':
+ line = new String();
+ lines->add(line);
+ line = NULL;
+ break;
+ case EOF:
+ break;
+ default:
+ line = new String();
+ line->addChar((char)c);
+ lineStarted = true;
+ break;
+ }
+ }
+ }while (c!=EOF);
+ return lines;
+ }
+};
\ No newline at end of file
diff --git a/Planner/Global.h b/Planner/Global.h
new file mode 100644
index 00000000..965e4836
--- /dev/null
+++ b/Planner/Global.h
@@ -0,0 +1,13 @@
+#include "String.h"
+#pragma once
+String userWorkspace;
+#pragma once
+String packageWorkspace;
+#pragma once
+int maxKernels;
+#pragma once
+int busyKernels;
+#pragma once
+int freeKernels;
+#pragma once
+String dvm_drv;
\ No newline at end of file
diff --git a/Planner/Planner.cpp b/Planner/Planner.cpp
new file mode 100644
index 00000000..9b0a2d8c
--- /dev/null
+++ b/Planner/Planner.cpp
@@ -0,0 +1,28 @@
+#include "CompilationSupervisor.h"
+#include "RunSupervisor.h"
+#include "Global.h"
+int main(int argc, char ** argv)
+{
+ userWorkspace = String(argv[1]);
+ packageWorkspace = String(argv[2]);
+ maxKernels = atoi(argv[3]);
+ dvm_drv = String(argv[4]);
+ //--
+ freeKernels = maxKernels;
+ busyKernels= 0;
+ //--
+ chdir(packageWorkspace.getCharArray());
+ userWorkspace.println();
+ packageWorkspace.println();
+ printf("%d\n", maxKernels);
+
+ CompilationSupervisor * compilationSupervisor = new CompilationSupervisor();
+ printf("%ld\n", compilationSupervisor->getLength());
+ compilationSupervisor->Do();
+
+ RunSupervisor * runSupervisor = new RunSupervisor(compilationSupervisor);
+ printf("%ld\n", runSupervisor->getLength());
+ runSupervisor->print();
+ runSupervisor->Do();
+ return 0;
+}
diff --git a/Planner/RunSupervisor.h b/Planner/RunSupervisor.h
new file mode 100644
index 00000000..e1105615
--- /dev/null
+++ b/Planner/RunSupervisor.h
@@ -0,0 +1,31 @@
+#include "CompilationSupervisor.h"
+#include "RunTask.h"
+#pragma once
+class RunSupervisor: public Supervisor {
+public:
+ RunSupervisor(CompilationSupervisor * compilationSupervisor){
+ this->init("runTasks", 8);
+ //проверить отмененные задачи.
+ for (long i=0; i< this->length; ++i){
+ RunTask * task = this->get(i);
+ CompilationTask * parent = compilationSupervisor->getTaskById( task->getTestCompilationTaskId());
+ task->setState((parent->getState()==Done)?Waiting:Canceled);
+ task->setParent(parent);
+ printf("id=%ld; parent_id = %ld; state=%s\n",
+ task->getId(),
+ task->getParent()->getId(),
+ task->printState().getCharArray());
+ }
+ }
+ virtual String getStatePrefix(){
+ return String("Running");
+ }
+ virtual void Finalize(){
+ this->state = Archivation;
+ saveState();
+ printf("Archivation started\n");
+ Utils::ZipFolder(String("./"),String("archive.zip"));
+ printf("Archivation ended\n");
+
+ }
+};
\ No newline at end of file
diff --git a/Planner/RunTask.h b/Planner/RunTask.h
new file mode 100644
index 00000000..1120c231
--- /dev/null
+++ b/Planner/RunTask.h
@@ -0,0 +1,94 @@
+#include "CompilationTask.h"
+#pragma once
+class RunTask : public Task {
+ long testcompilationtask_id;
+ String binary_name;
+ String matrix;
+ String environments;
+ String usr_par;
+ String args;
+ CompilationTask* parent;
+public:
+ virtual void print(){
+ printf("id=%ld; maxtime=%d; testcompilationtask_id=%ld; matrix=%s; environments=%s; usr_par=%s; args=%s kernels=%d\n",
+ id,
+ maxtime,
+ testcompilationtask_id,
+ matrix.getCharArray(),
+ environments.getCharArray(),
+ usr_par.getCharArray(),
+ args.getCharArray(),
+ kernels
+ );
+ }
+ int setKernels(String * kernels_s){
+ return kernels = atoi(kernels_s->getCharArray());
+ }
+ long setTestCompilationTaskId(String * id_s){
+ return testcompilationtask_id=strtol(id_s->getCharArray(), NULL, 10);
+ }
+ long getTestCompilationTaskId(){
+ return testcompilationtask_id;
+ }
+ void setMatrix(String * matrix_in){
+ matrix= String (matrix_in->getCharArray());
+ }
+ void setEnvironments(String * environments_in){
+ environments= String(environments_in->getCharArray());
+ }
+ void setUsrPar(String * usr_par_in){
+ usr_par= String(usr_par_in->getCharArray(),'|');
+ }
+ void setArgs(String * args_in){
+ args= String(args_in->getCharArray());
+ }
+ void setParent(CompilationTask * parent_in){
+ parent = parent_in;
+ binary_name = "spf_"+ String(id)+"_"+matrix.Replace(' ','_');
+ }
+ CompilationTask * getParent(){
+ return parent;
+ }
+ RunTask(Text * lines, int offset):Task(lines,offset) {
+ setTestCompilationTaskId(lines->get(offset+2));
+ setMatrix(lines->get(offset+3));
+ setEnvironments(lines->get(offset+4));
+ setUsrPar(lines->get(offset+5));
+ setArgs(lines->get(offset+6));
+ setKernels(lines->get(offset+7));
+ }
+
+ virtual String getLaunchScriptText(){
+ String modules = userWorkspace+"/modules";
+ String starterCall = modules+"/starter";
+ String launcherCall = modules+"/launcher";
+ //-
+ String dvm_start = String::DQuotes(dvm_drv) + " run ";
+ if (!matrix.isEmpty())
+ dvm_start = dvm_start+matrix + " ";
+ dvm_start = dvm_start+ String::DQuotes("./" + binary_name);
+ if (!args.isEmpty())
+ dvm_start = dvm_start+ " " + args;
+ return String::DQuotes(starterCall)+" "+
+ String::DQuotes(launcherCall)+" "+
+ String(maxtime)+" "+
+ String::DQuotes("killall -SIGKILL " + binary_name)+" "+
+ dvm_start;
+ }
+ virtual void prepareWorkspace(){
+ String binary_src = parent->getWorkspace()+"/0";
+ String binary_dst = workspace+"/"+binary_name;
+ Utils::Copy(binary_src, binary_dst);
+ if (!usr_par.isEmpty()){
+ String parPath = String(id)+"/usr.par";
+ File parFile = File(parPath, usr_par);
+ }
+ }
+ virtual String getStartCommand(){
+ String res = workspace+"/run";
+ if (!environments.isEmpty())
+ res = environments+" "+res;
+ printf("START %ld: %s\n", id, res.getCharArray());
+ return res;
+ }
+};
\ No newline at end of file
diff --git a/Planner/String.h b/Planner/String.h
new file mode 100644
index 00000000..ed85121d
--- /dev/null
+++ b/Planner/String.h
@@ -0,0 +1,220 @@
+#include
+#include
+#include
+#include
+#pragma once
+class String {
+ friend String operator+(const String& a, const String& b);
+ long length;
+ char* body;
+public:
+ String() {
+ length = 0;
+ body = new char[1];
+ body[0] = '\0';
+ }
+
+ String(const char* s) {
+ length = strlen(s);
+ body = new char[length + 1];
+ for (long i = 0; i < length; ++i)
+ body[i] = s[i];
+ body[length]='\0';
+ }
+ String(const char* s, char ps) {
+ length = strlen(s);
+ body = new char[length + 1];
+ for (long i = 0; i < length; ++i){
+ body[i] = (s[i]==ps)? '\n': s[i];
+ }
+ body[length]='\0';
+ }
+ ~String() {
+ if (body != NULL) {
+ delete[] body;
+ }
+ }
+ void println() const{
+ printf("[%s]\n", body);
+ }
+ void addChar(char c) {
+ char* buf = new char[length + 2];
+ for (long i = 0; i < length; ++i) {
+ buf[i] = body[i];
+ }
+ buf[length] = c;
+
+ length++;
+ //--
+ buf[length] = '\0';
+ delete[] body;
+ body = buf;
+ buf = NULL;
+ }
+ char * getCharArray() const{
+ return body;
+ }
+
+
+ String (int s){
+ length = 0;
+ body = new char[1];
+ body[0] = '\0';
+ if (s>=0){
+ int s_ = s;
+ int size = 1;
+ while (s_>=10){
+ s_ = s_/10;
+ size++;
+ }
+ length = size;
+ body = new char [size+1];
+ sprintf(body, "%d", s);
+ }
+ }
+ String (long s){
+ length = 0;
+ body = new char[1];
+ body[0] = '\0';
+ if (s>=0){
+ long s_ = s;
+ long size = 1;
+ while (s_>=10){
+ s_ = s_/10;
+ size++;
+ }
+ length = size;
+ body = new char [size+1];
+ sprintf(body, "%ld", s);
+ }
+ }
+
+ const String& operator=(const String& s){
+ if (body != NULL)
+ delete[] body;
+ length = s.length;
+ body = new char[length+1];
+ for (long i=0; ilength) return false;
+ long k=0;
+ long start=-1;
+ for (long i=0; igetCharArray());
+ for (long i=0; i
+#include
+
+int main(void) {
+ FILE * f;
+ int c;
+
+ if ( ! ( f = fopen("file.txt", "r") ) )
+ return -1;
+
+ while ( ( c = fgetc(f) ) != EOF )
+ putchar( isupper(c) ? tolower(c) : toupper(c) );
+
+ return ( fclose(f) );
+}
+ */
+
+};
+
+String operator+(const String& a, const String& b){
+ String res = String();
+ res.length =a.length+b.length;
+ res.body = new char[res.length+1];
+ for (long i=0; i
+
+#pragma once
+enum SupervisorState {
+ WorkspacesCreation, //0
+ Preparation, //1
+ Execution, //2
+ Archivation, //3
+ End //4
+};
+#pragma once
+template
+class Supervisor : public Array {
+protected:
+ SupervisorState state;
+public:
+ virtual String getStatePrefix(){
+ return String("");
+ }
+ String printState(){
+ switch(state){
+ case WorkspacesCreation:
+ return String("WorkspacesCreation");
+ case Preparation:
+ return String("Preparation");
+ case Execution:
+ return String("Execution");
+ case Archivation:
+ return String("Archivation");
+ case End:
+ return String("End");
+ default:
+ return "?";
+ }
+ }
+ //-
+ void print(){
+ for (long i=0; i< this->length; ++i)
+ this->elements[i]->print();
+ }
+ void init(const char * fileName, int recordSize){
+ state = WorkspacesCreation;
+ File * packedTasks = new File(fileName);
+ Text * lines = packedTasks->readLines();
+ this->length = lines->getLength()/recordSize;
+ this->elements = new T* [this->length];
+ int offset=0;
+ for (int i=0; i< this->length; ++i){
+ this->elements[i]= new T(lines, offset);
+ offset+=recordSize;
+ }
+ delete packedTasks;
+ delete lines;
+ }
+ void Do(){
+ saveState();
+ long activeCount=0;
+ //todo обязательно убрать отладочную печать.
+ printf("tasks count = %ld\n", this->length);
+ while (this->state!= End){
+// printf("state=%d\n", this->state);
+// printf("max=%d; busy=%d; free=%d\n", maxKernels, busyKernels, freeKernels);
+ activeCount=0;
+ for (long i=0; ilength; ++i){
+ T * task = this->elements[i];
+ switch (this->state){
+ case WorkspacesCreation:
+ if (task->getState()==Waiting){
+ activeCount++;
+ task->createWorkspace();
+ task->setState(WorkspaceCreated);
+ }
+ break;
+ case Preparation:
+ if (task->getState()==WorkspaceCreated){
+ activeCount++;
+ task->prepareWorkspace();
+ task->createLaunchScript();
+ task->setState(WorkspaceReady);
+ }
+ break;
+ case Execution:
+ if (task->getState()==WorkspaceReady){
+ activeCount++;
+ task->Start();
+ }else if (task->getState()==Running){
+ activeCount++;
+ task->Check();
+ }
+ break;
+ default:
+// printf("id = %ld; state = %d\n", task->getId(), task->getState());
+ break;
+ }
+ }
+// printf("active count = %d\n", activeCount);
+ if (activeCount==0){
+ switch (this->state){
+ case WorkspacesCreation:
+ this->state = Preparation;
+ saveState();
+ break;
+ case Preparation:
+ this->state = Execution;
+ saveState();
+ break;
+ case Execution:
+ Finalize();
+ this->state = End;
+ saveState();
+ break;
+ default:
+ this->state = End;
+ break;
+ }
+ }
+ Utils::Sleep(2);
+ }
+ }
+ virtual void Finalize(){}
+ void saveState(){
+ Utils::Sleep(1); //чтобы не было одинаковых по дате файлов.
+ String stateFile = packageWorkspace+"/state/"+getStatePrefix()+printState();
+ //printf("stateFile=<%s>\n", stateFile.getCharArray());
+ File(stateFile, Utils::getDate());
+ }
+};
\ No newline at end of file
diff --git a/Planner/Task.h b/Planner/Task.h
new file mode 100644
index 00000000..19891b5d
--- /dev/null
+++ b/Planner/Task.h
@@ -0,0 +1,163 @@
+#include "File.h"
+#include "Utils.h"
+#include "Global.h"
+
+#pragma once
+enum TaskState {
+ Inactive, //0
+ Waiting, //1
+ WorkspaceCreated, //2
+ WorkspaceReady, //3
+ Running, //4
+ Canceled, //5
+ Finished, //6
+ FinishedAbortedByTimeout, //7
+ FinishedAbortedByUser, //8
+ Done, //9
+ DoneWithErrors, //10
+ AbortedByTimeout, //11
+ AbortedByUser, //12
+ Crushed, //13
+ WrongTestFormat, //14
+ InternalError, //15
+ Queued, //16
+ NoSuchTask, //17
+ FailedToQueue, //18
+ AbortingByUser //19
+};
+#pragma once
+enum TestType{
+ Default, //0
+ Correctness, //1
+ Performance, //2
+};
+
+#pragma once
+class Task {
+protected:
+ long id;
+ int maxtime;
+ int kernels; //получение зависит от типа задачи.
+ String workspace;
+ TaskState state;
+public:
+ String printState(){
+ switch(state){
+ case Inactive:
+ return String("Inactive");
+ case Waiting:
+ return String("Waiting");
+ case WorkspaceCreated:
+ return String("WorkspaceCreated");
+ case WorkspaceReady:
+ return String("WorkspaceReady");
+ case Running:
+ return String("Running");
+ case Canceled:
+ return String("Canceled");
+ case Finished:
+ return String("Finished");
+ case FinishedAbortedByTimeout:
+ return String("FinishedAbortedByTimeout");
+ case FinishedAbortedByUser:
+ return String("FinishedAbortedByUser");
+ case Done:
+ return String("Done");
+ case DoneWithErrors:
+ return String("DoneWithErrors");
+ case AbortedByTimeout:
+ return String("AbortedByTimeout");
+ case AbortedByUser:
+ return String("AbortedByUser");
+ case Crushed:
+ return String("Crushed");
+ case WrongTestFormat:
+ return String("WrongTestFormat");
+ case InternalError:
+ return String("InternalError");
+ case Queued:
+ return String("Queued");
+ case NoSuchTask:
+ return String("NoSuchTask");
+ case FailedToQueue:
+ return String("FailedToQueue");
+ case AbortingByUser:
+ return String("AbortingByUser");
+ default:
+ return "?";
+ }
+ }
+ //-------------->>
+ long getId(){return id;}
+ long setId(String * id_s){
+ return id=strtol(id_s->getCharArray(), NULL, 10);
+ }
+ int getMaxtime(){return maxtime;}
+ int setMaxtime(String * maxtime_s){
+ return maxtime=atoi(maxtime_s->getCharArray());
+ }
+ const String& getWorkspace(){return workspace;}
+ TaskState getState(){return state;}
+ TaskState setState(TaskState state_in){return state=state_in;}
+ Task(Text * lines, int offset){
+ setId(lines->get(offset));
+ setMaxtime(lines->get(offset+1));
+ workspace = packageWorkspace+"/"+String(id);
+ }
+ virtual void print()=0;
+ //-
+ virtual void prepareWorkspace(){}
+ virtual String getLaunchScriptText()=0;
+ virtual String getStartCommand(){
+ return workspace+"/run";
+ }
+
+ void createWorkspace(){
+ Utils::Mkdir(workspace);
+ }
+ void createLaunchScript(){
+ String launchScriptPath = workspace+"/run";
+ String launchScriptText =
+ String("cd ")+String::DQuotes(workspace)+"\n"+
+ getLaunchScriptText();
+ File launchScriptFile = File(launchScriptPath, launchScriptText);
+ Utils::Chmod(launchScriptPath);
+ }
+ virtual void Start(){
+
+ if (kernels<=freeKernels){
+ system(getStartCommand().getCharArray());
+ state=Running;
+ //-
+ busyKernels= Utils::min(busyKernels+kernels, maxKernels);
+ freeKernels= Utils::max(0, maxKernels-busyKernels);
+ //-
+ }
+ }
+ virtual void analyseResults(){
+ state=Finished;
+ }
+ virtual void Check(){
+ if (Utils::Exists(workspace+"/DONE")){
+ analyseResults();
+ }else {
+ if (Utils::Exists(workspace+"/TIMEOUT")){
+ state=AbortedByTimeout;
+ //todo определить по интервалу времени на всякий случай.
+ }else if (Utils::Exists(workspace+"/INTERRUPT")){
+ state=AbortedByUser;
+ }
+ }
+ if (state!=Running){
+ //-
+ busyKernels= Utils::min(busyKernels-kernels, maxKernels);
+ freeKernels= Utils::max(0, maxKernels-busyKernels);
+ //-
+ saveState(); //не нужно. только для отладки. анализ будет делаться архивом.
+ }
+ }
+ virtual void saveState(){
+ String stateFile = workspace+"/TaskState";
+ File(stateFile, printState());
+ }
+};
diff --git a/Planner/Text.h b/Planner/Text.h
new file mode 100644
index 00000000..d1a57075
--- /dev/null
+++ b/Planner/Text.h
@@ -0,0 +1,25 @@
+#include "String.h"
+#include "Array.h"
+#pragma once
+class Text: public Array {
+ public:
+ void Print(){
+ printf("text length=%ld\n", length);
+
+ for (long i=0; igetCharArray());
+ // elements[i]->println();
+ }
+ }
+ bool hasMatch(const String& s){
+
+ for (long i=0; igetCharArray());
+ return true;
+ }
+ }
+ //printf("no matches for [%s]\n", s.getCharArray());
+ return false;
+ }
+};
\ No newline at end of file
diff --git a/Planner/Utils.h b/Planner/Utils.h
new file mode 100644
index 00000000..eb077069
--- /dev/null
+++ b/Planner/Utils.h
@@ -0,0 +1,49 @@
+#include
+#include
+#include
+#include
+#include
+#include "String.h"
+#pragma once
+class Utils {
+public:
+ static int max(int a, int b){
+ return (a > b)? a:b;
+ }
+ static int min(int a, int b){
+ return (a > b)? b:a;
+ }
+ static void Mkdir(const String& path){
+ mkdir(path.getCharArray(), 0777);
+ }
+ //https://stackoverflow.com/questions/4568681/using-chmod-in-a-c-program
+ static void Chmod(const String& path){
+ String command = "chmod 777 "+String::DQuotes(path);
+ system(command.getCharArray());
+ }
+ //https://stackoverflow.com/questions/230062/whats-the-best-way-to-check-if-a-file-exists-in-c
+ static bool Exists(const String& path){
+ struct stat buffer;
+ return (stat (path.getCharArray(), &buffer) == 0);
+ }
+ static void Sleep(int s){
+ usleep(s* 1000000);
+ }
+ static void Copy(const String& src, const String& dst){
+ String command = "cp "+String::DQuotes(src)+" "+String::DQuotes(dst);
+ system(command.getCharArray());
+ }
+ static long getAbsoluteTime(){
+ return time (NULL);
+ }
+ static String getDate(){
+ long int ttime;
+ ttime = time (NULL);
+ String res(ctime (&ttime));
+ return res;
+ }
+ static void ZipFolder(const String& src, const String& dst){
+ String command = "zip -r "+String::DQuotes(dst)+" "+String::DQuotes(src);
+ system(command.getCharArray());
+ }
+};
\ No newline at end of file
diff --git a/README.md b/README.md
index a17ac84e..8189f484 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,8 @@
-# VisualSapfor
+# Visual_DVM_2020
+Визуализатор 3.0
+
+Инструкция для установки и настройки Диалоговой обочки https://cloud.mail.ru/public/NDxu/LJJhQgQUG
+
+Проект SAPFOR FORTRAN https://bitbucket.org/ALEXks/sapfor_2017/src/master/
++
\ No newline at end of file
diff --git a/Thumbs.db b/Thumbs.db
new file mode 100644
index 00000000..dab64c44
Binary files /dev/null and b/Thumbs.db differ
diff --git a/Visual_DVM_2020.iml b/Visual_DVM_2020.iml
new file mode 100644
index 00000000..58652714
--- /dev/null
+++ b/Visual_DVM_2020.iml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Visualizer_2.exe b/Visualizer_2.exe
new file mode 100644
index 00000000..08f77b20
Binary files /dev/null and b/Visualizer_2.exe differ
diff --git a/properties b/properties
new file mode 100644
index 00000000..749da7ab
--- /dev/null
+++ b/properties
@@ -0,0 +1,29 @@
+{
+ "Mode": "Normal",
+ "SocketTimeout": 5000,
+ "OldServer": false,
+ "SMTPHost": "smtp.mail.ru",
+ "SMTPPort": 465,
+ "MailSocketPort": 465,
+ "BackupWorkspace": "_sapfor_x64_backups",
+ "BackupHour": 5,
+ "BackupMinute": 0,
+ "EmailAdminsOnStart": false,
+ "AutoUpdateSearch": true,
+ "ConfirmPassesStart": true,
+ "ShowPassesDone": true,
+ "FocusPassesResult": true,
+ "GlobalDBName": "db7.sqlite",
+ "ProjectDBName": "new_project_base.sqlite",
+ "BugReportsDBName": "bug_reports.sqlite",
+ "TestsDBName": "tests.sqlite",
+ "ComponentsWindowWidth": 866,
+ "ComponentsWindowHeight": 297,
+ "VisualiserPath": "C:\\Users\\misha\\Downloads",
+ "Sapfor_FPath": "E:\\",
+ "Visualizer_2Path": "C:\\Users\\misha\\Documents",
+ "InstructionPath": "",
+ "PerformanceAnalyzerPath": "",
+ "ComponentsBackUpsCount": 10,
+ "SapforTaskMaxId": 4212
+}
\ No newline at end of file
diff --git a/src/Common/Current.java b/src/Common/Current.java
new file mode 100644
index 00000000..d8192fe1
--- /dev/null
+++ b/src/Common/Current.java
@@ -0,0 +1,495 @@
+package Common;
+import Common.Database.iDBObject;
+import Common.UI.Themes.VisualiserTheme;
+import Common.Utils.TextLog;
+import GlobalData.Account.Account;
+import GlobalData.Compiler.Compiler;
+import GlobalData.Machine.Machine;
+import GlobalData.Makefile.Makefile;
+import GlobalData.Module.Module;
+import GlobalData.RemoteFile.RemoteFile;
+import GlobalData.RemoteSapfor.RemoteSapfor;
+import GlobalData.RunConfiguration.RunConfiguration;
+import GlobalData.Tasks.CompilationTask.CompilationTask;
+import GlobalData.Tasks.RunTask.RunTask;
+import GlobalData.User.User;
+import ProjectData.Files.DBProjectFile;
+import ProjectData.Project.db_project_info;
+import ProjectData.SapforData.Functions.FuncInfo;
+import ProjectData.SapforData.Regions.ParallelRegion;
+import Repository.BugReport.BugReport;
+import Repository.Subscribes.Subscriber;
+import TestingSystem.Configuration.Configuration;
+import TestingSystem.Sapfor.SapforConfiguration.SapforConfiguration;
+import TestingSystem.Sapfor.SapforTask.SapforTask_2023;
+import TestingSystem.Sapfor.SapforTasksPackage.SapforTasksPackage_2023;
+import TestingSystem.Tasks.TestCompilationTask;
+import TestingSystem.Tasks.TestRunTask;
+import TestingSystem.TasksPackage.TasksPackage;
+import TestingSystem.Test.Test;
+import Visual_DVM_2021.Passes.UI.PassForm;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import java.io.File;
+import java.util.LinkedHashMap;
+public enum Current {
+ Undefined,
+ //--
+ SapforEtalonTaskResult,//самый левый пакет
+ SapforTaskResult,
+ //--
+ ComponentServerBackup,
+ Subscriber,
+ Theme,
+ FileGraphElement,
+ InlineGraphElement,
+ InlineGraphElement2,
+ IncludeGraphElement,
+ Component,
+ Project,
+ File,
+ Root,
+ Version,
+ BugReport,
+ Account,
+ DBArray,
+ ProjectArray,
+ ParallelRegionInfo,
+ ParallelVariant,
+ Machine,
+ User,
+ Compiler,
+ Makefile,
+ Module,
+ RunConfiguration,
+ EnvironmentValue,
+ CompilationTask,
+ RunTask,
+ ProjectNode, //узел в дереве проекта. нужен для отображения добавленных файлов
+ SelectedDirectory,
+ SelectedFile,
+ //текущий выбранный удаленный файл
+ RemoteFile,
+ PassForm, //текущее окно анимации. нужно для сообщений сапфора по сокету.
+ RunStsRecord,
+ //только для того, чтобы закодировать таблицу.
+ Array,
+ ParallelRegion,
+ Dimensions,
+ //----------
+ Warnings,
+ Errors,
+ Notes,
+ Recommendations,
+ //-
+ Sapfor,
+ //-
+ Scenario,
+ ScenarioCommand,
+ //-
+ Configuration,
+ Group,
+ //-
+ DVMParameterValue,
+ Test,
+ Function,
+ SelectedFunction,
+ //-
+ Credentials,
+ TestCompilationTask,
+ TestRunTask,
+ TasksPackage,
+ //-
+ DialogWindow,
+ //-
+ SapforTasksPackage,
+ PackageVersion,
+ RemoteSapfor,
+ SapforConfiguration,
+ SapforConfigurationCommand,
+ SapforTask,
+ SapforProfile,
+ SapforProfileSetting,
+ //--
+ ProjectView;
+ //-
+ //---
+ private static final LinkedHashMap objects = new LinkedHashMap<>();
+ public static Mode mode;
+ public static boolean hasUI() {
+ return Current.mode.equals(Current.Mode.Normal);
+ }
+ public static boolean HasProject() {
+ return get(Project) != null;
+ }
+ public static boolean HasFile() {
+ return get(File) != null;
+ }
+ public static boolean HasSelectedFile() {
+ return get(SelectedFile) != null;
+ }
+ public static boolean HasAccount() {
+ return get(Account) != null;
+ }
+ public static boolean HasMachine() {
+ return get(Machine) != null;
+ }
+ public static boolean HasUser() {
+ return get(User) != null;
+ }
+ public static boolean HasCompiler() {
+ return get(Compiler) != null;
+ }
+ public static boolean HasRemoteFile() {
+ return get(RemoteFile) != null;
+ }
+ public static boolean HasMakefile() {
+ return get(Makefile) != null;
+ }
+ public static boolean HasRunConfiguration() {
+ return get(RunConfiguration) != null;
+ }
+ public static boolean HasCompilationTask() {
+ return get(CompilationTask) != null;
+ }
+ public static boolean HasRunTask() {
+ return get(RunTask) != null;
+ }
+ public static boolean HasPassForm() {
+ return get(PassForm) != null;
+ }
+ public static boolean HasProjectView() {
+ return get(ProjectView) != null;
+ }
+ //для быстрого доступа на чтение. слишком много на нем завязано.
+ public static db_project_info getProject() {
+ return (db_project_info) get(Project);
+ }
+ public static DBProjectFile getFile() {
+ return (DBProjectFile) get(File);
+ }
+ public static Repository.Component.Component getComponent() {
+ return (Repository.Component.Component) get(Component);
+ }
+ public static Repository.BugReport.BugReport getBugReport() {
+ return (BugReport) get(BugReport);
+ }
+ public static db_project_info getRoot() {
+ return (db_project_info) get(Root);
+ }
+ public static boolean HasRoot() {
+ return get(Root) != null;
+ }
+ public static db_project_info getVersion() {
+ return (db_project_info) get(Version);
+ }
+ public static Account getAccount() {
+ return (Account) get(Account);
+ }
+ public static boolean HasSubscriber() {
+ return get(Current.Subscriber) != null;
+ }
+ public static Repository.Subscribes.Subscriber getSubscriber() {
+ return (Subscriber) get(Current.Subscriber);
+ }
+ public static Machine getMachine() {
+ return (Machine) get(Current.Machine);
+ }
+ public static User getUser() {
+ return (User) get(Current.User);
+ }
+ public static Compiler getCompiler() {
+ return (Compiler) get(Current.Compiler);
+ }
+ public static CompilationTask getCompilationTask() {
+ return (CompilationTask) get(Current.CompilationTask);
+ }
+ public static RunTask getRunTask() {
+ return (RunTask) get(Current.RunTask);
+ }
+ public static RemoteFile getRemoteFile() {
+ return (RemoteFile) get(Current.RemoteFile);
+ }
+ public static Makefile getMakefile() {
+ return (Makefile) get(Current.Makefile);
+ }
+ public static Module getModule() {
+ return (Module) get(Current.Module);
+ }
+ public static RunConfiguration getRunConfiguration() {
+ return (RunConfiguration) get(Current.RunConfiguration);
+ }
+ public static Repository.Component.Sapfor.Sapfor getSapfor() {
+ return (Repository.Component.Sapfor.Sapfor) get(Current.Sapfor);
+ }
+ public static boolean HasGroup() {
+ return get(Current.Group) != null;
+ }
+ public static TestingSystem.Group.Group getGroup() {
+ return (TestingSystem.Group.Group) get(Current.Group);
+ }
+ //--
+ public static boolean HasConfiguration() {
+ return get(Current.Configuration) != null;
+ }
+ public static TestingSystem.Configuration.Configuration getConfiguration() {
+ return (Configuration) get(Current.Configuration);
+ }
+ public static SapforConfiguration getSapforConfiguration() {
+ return (TestingSystem.Sapfor.SapforConfiguration.SapforConfiguration) get(Current.SapforConfiguration);
+ }
+ //--
+ public static Test getTest() {
+ return (TestingSystem.Test.Test) get(Current.Test);
+ }
+ public static boolean HasTest() {
+ return get(Current.Test) != null;
+ }
+ public static boolean HasVersion() {
+ return get(Current.Version) != null;
+ }
+ public static TestCompilationTask getTestCompilationTask() {
+ return (TestingSystem.Tasks.TestCompilationTask) get(Current.TestCompilationTask);
+ }
+ public static boolean HasTestCompilationTask() {
+ return get(Current.TestCompilationTask) != null;
+ }
+ public static boolean HasTestRunTask() {
+ return get(Current.TestRunTask) != null;
+ }
+ public static TestRunTask getTestRunTask() {
+ return (TestingSystem.Tasks.TestRunTask) get(Current.TestRunTask);
+ }
+ public static RemoteFile getComponentServerBackup() {
+ return (RemoteFile) get(Current.ComponentServerBackup);
+ }
+ public static boolean HasComponentServerBackup() {
+ return get(Current.ComponentServerBackup) != null;
+ }
+ //-
+ public static boolean HasSapforTasksPackage() {
+ return get(Current.SapforTasksPackage) != null;
+ }
+ public static SapforTasksPackage_2023 getSapforTasksPackage() {
+ return (SapforTasksPackage_2023) get(Current.SapforTasksPackage);
+ }
+ //-
+ public static DefaultMutableTreeNode getProjectNode() {
+ return (DefaultMutableTreeNode) get(Current.ProjectNode);
+ }
+ public static DefaultMutableTreeNode getProjectCurrentParentNode() {
+ DefaultMutableTreeNode node = Current.getProjectNode();
+ //если в дереве еще никто не выделялся, берем корень.
+ if (node == null)
+ return Current.getProject().filesTreeRoot;
+ return (node.getUserObject() instanceof DBProjectFile) ? (DefaultMutableTreeNode) node.getParent() : node;
+ }
+ public static File getSelectedDirectory() {
+ return (File) get(Current.SelectedDirectory);
+ }
+ public static DBProjectFile getSelectedFile() {
+ return (DBProjectFile) get(Current.SelectedFile);
+ }
+ //-
+ public static boolean HasBugReport() {
+ return get(Current.BugReport) != null;
+ }
+ public static PassForm getPassForm() {
+ return (Visual_DVM_2021.Passes.UI.PassForm) get(Current.PassForm);
+ }
+ public static VisualiserTheme getTheme() {
+ return (VisualiserTheme) get(Current.Theme);
+ }
+ //--------------------------------------------------------------------------------
+ public static ParallelRegion getParallelRegion() {
+ return (ParallelRegion) get(Current.ParallelRegion);
+ }
+ public static boolean HasParallelRegion() {
+ return get(Current.ParallelRegion) != null;
+ }
+ public static boolean HasFunction() {
+ return get(Current.Function) != null;
+ }
+ public static boolean HasSelectedFunction() {
+ return get(Current.SelectedFunction) != null;
+ }
+ public static FuncInfo getFunction() {
+ return (FuncInfo) get(Current.Function);
+ }
+ public static FuncInfo getSelectionFunction() {
+ return (FuncInfo) get(Current.SelectedFunction);
+ }
+ public static boolean HasTasksPackage() {
+ return get(Current.TasksPackage) != null;
+ }
+ public static TasksPackage getTasksPackage() {
+ return (TasksPackage) get(Current.TasksPackage);
+ }
+ public static boolean HasScenario() {
+ return get(Current.Scenario) != null;
+ }
+ public static db_project_info getPackageVersion() {
+ return (db_project_info) get(Current.PackageVersion);
+ }
+ public static boolean HasPackageVersion() {
+ return get(Current.PackageVersion) != null;
+ }
+ public static GlobalData.RemoteSapfor.RemoteSapfor getRemoteSapfor() {
+ return (RemoteSapfor) get(RemoteSapfor);
+ }
+ public static boolean HasRemoteSapfor() {
+ return get(Current.RemoteSapfor) != null;
+ }
+ public static boolean HasSapforConfiguration() {
+ return get(Current.SapforConfiguration) != null;
+ }
+ public static boolean HasSapforTask() {
+ return get(Current.SapforTask) != null;
+ }
+ public static SapforTask_2023 getSapforTask() {
+ return (SapforTask_2023) get(Current.SapforTask);
+ }
+ public static ProjectData.ProjectView getProjectView() {
+ return (ProjectData.ProjectView) get(ProjectView);
+ }
+ public static boolean Check(TextLog Log, Current... names) {
+ for (Current name : names)
+ if (get(name) == null)
+ Log.Writeln_(name.getDescription() + " не выбран(а)");
+ return Log.isEmpty();
+ }
+ public static void CreateAll() {
+ for (Current c : values())
+ objects.put(c, null);
+ }
+ //-----------------------------------------
+ public static Object get(Current name) {
+ return objects.get(name);
+ }
+ public static Object set(Current name, Object object) {
+ objects.replace(name, object);
+ return object;
+ }
+ //применять только для наследников iDBObject
+ public static boolean CheckID(Current name, int id) {
+ return (get(name) != null) && (((iDBObject) get(name)).id == id);
+ }
+ public static TestingSystem.Sapfor.SapforConfigurationCommand.SapforConfigurationCommand getSapforConfigurationCommand() {
+ return (TestingSystem.Sapfor.SapforConfigurationCommand.SapforConfigurationCommand) get(Current.SapforConfigurationCommand);
+ }
+ public static boolean HasSapforProfile() {
+ return get(Current.SapforProfile)!=null;
+ }
+ public static GlobalData.SapforProfile.SapforProfile getSapforProfile(){
+ return (GlobalData.SapforProfile.SapforProfile) get(Current.SapforProfile);
+ }
+ //--------------------------------------------
+ public String getDescription() {
+ switch (this) {
+ case SapforProfile:
+ return "Профиль SAPFOR";
+ case SapforProfileSetting:
+ return "Настройка профиля SAPFOR";
+ case SapforEtalonTaskResult:
+ return "Задача SAPFOR(Эталон)";
+ case SapforTaskResult:
+ return "Задача SAPFOR";
+ case ComponentServerBackup:
+ return "Версия компонента для восстановления с сервера";
+ case Subscriber:
+ return "Адресат";
+ case SapforTask:
+ return "Задача SAPFOR";
+ case SelectedFunction:
+ return "Выбранный узел графа процедур";
+ case SapforConfigurationCommand:
+ return "Команда конфигурации тестирования SAPFOR";
+ case SapforConfiguration:
+ return "Конфигурация тестирования SAPFOR";
+ case RemoteSapfor:
+ return "SAPFOR";
+ case PackageVersion:
+ return "Версия пакетного режима";
+ case SapforTasksPackage:
+ return "Пакет задач SAPFOR";
+ case TasksPackage:
+ return "Пакет задач";
+ case Credentials:
+ return "Учётные данные";
+ case Function:
+ return "Функция";
+ case TestRunTask:
+ return "Задача на запуск теста";
+ case TestCompilationTask:
+ return "Задача на компиляцию теста";
+ case DVMParameterValue:
+ return "Параметр DVM системы";
+ case ParallelRegion:
+ return "Область распараллеливания";
+ case Group:
+ return "Группа тестов DVM";
+ case Scenario:
+ return "Сценарий";
+ case ScenarioCommand:
+ return "Команда сценария";
+ case ProjectNode:
+ return "текущий узел дерева проектов"; //служебка
+ case Test:
+ return "Тест";
+ case Sapfor:
+ return "SAPFOR";
+ case Theme:
+ return "Тема";
+ case EnvironmentValue:
+ return "Значение переменной окружения";
+ case SelectedDirectory:
+ return "Папка проекта";
+ case SelectedFile:
+ return "Файл проекта";
+ case RunConfiguration:
+ return "Конфигурация запуска";
+ case RunTask:
+ return "Задача на запуск";
+ case CompilationTask:
+ return "Задача на компиляцию";
+ case Makefile:
+ return "Мейкфайл";
+ case Module:
+ return "Языковой модуль мейкфайла";
+ case RemoteFile:
+ return "Удалённый файл";
+ case Component:
+ return "Компонент";
+ case Project:
+ return "Проект";
+ case File:
+ return "Файл";
+ case Root:
+ return "Корень дерева версий";
+ case Version:
+ return "Версия";
+ case BugReport:
+ return "Отчёт об ошибке";
+ case Account:
+ return "Аккаунт";
+ case Machine:
+ return "Машина";
+ case User:
+ return "Пользователь";
+ case Compiler:
+ return "Компилятор";
+ case DialogWindow:
+ return "Диалоговое окно";
+ default:
+ return "";
+ }
+ }
+ //---
+ public enum Mode {
+ Undefined,
+ Normal,
+ Server,
+ Testing,
+ Package
+ }
+}
diff --git a/src/Common/Database/ColumnType.java b/src/Common/Database/ColumnType.java
new file mode 100644
index 00000000..50551850
--- /dev/null
+++ b/src/Common/Database/ColumnType.java
@@ -0,0 +1,31 @@
+package Common.Database;
+public enum ColumnType {
+ UNDEFINED,
+ INT,
+ LONG,
+ DOUBLE,
+ STRING;
+ public static ColumnType valueOf(Class> type) {
+ ColumnType res = UNDEFINED;
+ try {
+ res = valueOf(type.getSimpleName().toUpperCase());
+ } catch (Exception ignored) {
+ }
+ return res;
+ }
+ public String getSQLType() {
+ String res = "";
+ switch (this) {
+ case INT:
+ case LONG:
+ res = "INTEGER";
+ break;
+ case DOUBLE:
+ res = "REAL";
+ break;
+ case STRING:
+ res = "VARCHAR";
+ }
+ return res;
+ }
+}
diff --git a/src/Common/Database/DBObject.java b/src/Common/Database/DBObject.java
new file mode 100644
index 00000000..7506e6ea
--- /dev/null
+++ b/src/Common/Database/DBObject.java
@@ -0,0 +1,64 @@
+package Common.Database;
+import Common.UI.Selectable;
+import Common.Utils.Index;
+import Common.Utils.Utils;
+import com.sun.org.glassfish.gmbal.Description;
+
+import java.io.Serializable;
+import java.util.Objects;
+public abstract class DBObject implements Selectable, Serializable {
+ //
+ @Description("IGNORE")
+ private boolean selected = false;
+ @Override
+ public boolean isSelected() {
+ return selected;
+ }
+ @Override
+ public void select(boolean flag) {
+ if (selected != flag) {
+ selected = flag;
+ Index counter = getSelectionCounter();
+ if (Objects.nonNull(counter)) {
+ if (selected) counter.Inc();
+ else counter.Dec();
+ }
+ }
+ }
+ //
+ public Index getSelectionCounter() {
+ return null;
+ }
+ public boolean isVisible() {
+ return true;
+ }
+ public abstract Object getPK();
+ public String getBDialogName() {
+ return Utils.Brackets(getDialogName());
+ }
+ public String getDialogName() {
+ return getPK().toString();
+ }
+ //статус. например завершенность багрепорта или состояние задачи на запуск. как правило обладает цветным шрифтом.
+ //как объект будут называть по внешним ключам.
+ public String getFKName() {
+ return null;
+ }
+ public Object getEmptyFK() {
+ return null;
+ }
+ @Override
+ public String toString() {
+ return getBDialogName();
+ }
+ //---
+ public void SynchronizeFields(DBObject src){
+ selected = src.selected;
+ }
+ //------
+ public DBObject(){}
+ public DBObject(DBObject src){
+ this.SynchronizeFields(src);
+ }
+ //---------
+}
diff --git a/src/Common/Database/DBTable.java b/src/Common/Database/DBTable.java
new file mode 100644
index 00000000..38b0b575
--- /dev/null
+++ b/src/Common/Database/DBTable.java
@@ -0,0 +1,34 @@
+package Common.Database;
+import java.lang.reflect.Field;
+public abstract class DBTable extends DataSet {
+ //-
+ public DBTableColumn PK = null;
+ private Database db = null; //база данных - владелец таблицы.
+ public DBTable(Class k_in, Class d_in) {
+ super(k_in, d_in);
+ for (Field field : d.getFields()) {
+ DBTableColumn column = new DBTableColumn(field);
+ if ((!column.Ignore) && !columns.containsKey(column.Name)) {
+ columns.put(column.Name, column);
+ if (column.PrimaryKey) PK = column;
+ }
+ }
+ }
+ public Database getDb() {
+ return db;
+ }
+ public void setDb(Database db_in) {
+ db = db_in;
+ }
+ @Override
+ public String getPKName() {
+ return PK.Name;
+ }
+ @Override
+ public String toString() {
+ StringBuilder res = new StringBuilder(Name + "\n");
+ for (DBTableColumn c : columns.values())
+ res.append(c).append("\n");
+ return res.toString();
+ }
+}
diff --git a/src/Common/Database/DBTableColumn.java b/src/Common/Database/DBTableColumn.java
new file mode 100644
index 00000000..70d0bc1a
--- /dev/null
+++ b/src/Common/Database/DBTableColumn.java
@@ -0,0 +1,50 @@
+package Common.Database;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Vector;
+public class DBTableColumn {
+ public String Name = "";
+ public ColumnType type = ColumnType.UNDEFINED;
+ public Vector attributes = new Vector();
+ public boolean Ignore = false;
+ public boolean PrimaryKey = false;
+ public boolean AutoIncrement = false;
+ public Object default_value = null;
+ public DBTableColumn(Field field) {
+ ExtractAttributes(field);
+ PrimaryKey = attributes.contains("PRIMARY KEY");
+ AutoIncrement = attributes.contains("AUTOINCREMENT");
+ Name = field.getName();
+ type = (field.getType().isEnum()) ? ColumnType.STRING : ColumnType.valueOf(field.getType());
+ Ignore = ((Modifier.isStatic(field.getModifiers()) ||
+ type.equals(ColumnType.UNDEFINED) ||
+ attributes.contains("IGNORE")
+ )
+ );
+ }
+ public String QName() {
+ return "\"" + Name + "\"";
+ }
+ public void ExtractAttributes(Field field) {
+ attributes = new Vector();
+ Annotation[] annotations = field.getAnnotations();
+ for (Annotation a : annotations) {
+ String[] data = a.toString().split("value=");
+ if (data.length > 1) {
+ String[] attributes_ = data[1].split("[,\")]");
+ for (String attribute : attributes_) {
+ if (attribute.length() > 0)
+ attributes.add(attribute);
+ }
+ }
+ }
+ }
+ @Override
+ public String toString() {
+ String res = QName() + " " + type.getSQLType();
+ if (attributes.size() > 0)
+ res += " " + String.join(" ", attributes);
+ return res;
+ }
+}
diff --git a/src/Common/Database/DataSet.java b/src/Common/Database/DataSet.java
new file mode 100644
index 00000000..3d4fc6d7
--- /dev/null
+++ b/src/Common/Database/DataSet.java
@@ -0,0 +1,253 @@
+package Common.Database;
+import Common.Current;
+import Common.UI.DataSetControlForm;
+import Common.UI.Menus_2023.DataMenuBar;
+import Common.UI.Tables.ColumnFilter;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.DBObjectDialog;
+import Common.UI.Windows.Dialog.DialogFields;
+import Common.Utils.TextLog;
+import Visual_DVM_2021.UI.Interface.FilterWindow;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.Vector;
+import java.util.stream.Collectors;
+public class DataSet extends DataSetAnchestor {
+ //-
+ public static LinkedHashMap selections = new LinkedHashMap<>();
+ //-
+ public String Name;
+ public Class k; //класс первичного ключа.
+ public Class d; //класс объектов.
+ public LinkedHashMap Data = new LinkedHashMap<>(); //наполнение
+ //-
+ //
+ public DataSetControlForm ui_;
+ protected FilterWindow f_ui;
+ //
+ //-
+ public LinkedHashMap columnsFilters = new LinkedHashMap<>();
+ public DataSet(Class k_in, Class d_in) {
+ k = k_in;
+ d = d_in;
+ Name = d.getSimpleName();
+ }
+ public void mountUI(JPanel content_in) {
+ UI.Clear(content_in);
+ //-->
+ ui_ = createUI();
+ ui_.setContent(content_in);
+ //-->
+ if (UI.menuBars.containsKey(getClass())) {
+ DataMenuBar bar = UI.menuBars.get(getClass());
+ content_in.add(bar, BorderLayout.NORTH);
+ setFilterUI(count -> UI.menuBars.get(getClass()).countLabel.setText(String.valueOf(count)));
+ if (ui_.hasCheckBox())
+ bar.createSelectionButtons(this);
+ }
+ content_in.add(ui_.getDataPanel(), BorderLayout.CENTER);
+ }
+ public DataSetControlForm getUi() {
+ return ui_;
+ }
+ public void setFilterUI(FilterWindow ui_in) {
+ f_ui = ui_in;
+ }
+ public void ShowUI() {
+ if (ui_ != null) {
+ ui_.Show();
+ if (f_ui != null)
+ f_ui.ShowMatchesCount(getRowCountUI());
+ }
+ }
+ public void ShowUI(Object key) {
+ if (ui_ != null) {
+ ui_.Show(key);
+ if (f_ui != null)
+ f_ui.ShowMatchesCount(getRowCountUI());
+ }
+ }
+ public void ClearUI() {
+ if ((ui_ != null) && ui_.isShown()) {
+ ui_.ClearSelection();
+ ui_.Clear();
+ if (f_ui != null)
+ f_ui.ShowNoMatches();
+ }
+ }
+ public void RefreshUI() {
+ if (ui_ != null) ui_.Refresh();
+ }
+ public int getRowCountUI() {
+ return ui_.getRowCount();
+ }
+ public void SetCurrentObjectUI(Object pk) {
+ if (ui_ != null) {
+ //todo возможно проверить, что текущий объект уже соответствует ключу, и если да, то ничего делать.
+ ui_.ClearSelection(); //сброс текущего объекта и всего что с ним связано.
+ ui_.Select(pk);
+ }
+ }
+ //столбы/ потом переименовать обратно в getUIColumnNames.сейчас так для скорости переноса.
+ public String[] getUIColumnNames() {
+ return new String[]{};
+ }
+ protected DataSetControlForm createUI() {
+ return null;
+ }
+ public boolean hasUI() {
+ return ui_ != null;
+ }
+ public void CheckAll(boolean flag) {
+ for (D object : Data.values()) {
+ if (object.isVisible())
+ object.Select(flag);
+ }
+ RefreshUI();
+ }
+ public D getFirstRecord() {
+ return Data.values().stream().findFirst().orElse(null);
+ }
+ public Vector getOrderedRecords(Comparator comparator) {
+ Vector res = new Vector<>(Data.values());
+ res.sort(comparator);
+ return res;
+ }
+ @SuppressWarnings("unchecked")
+ public DBObjectDialog getDialog() {
+ return null;
+ }
+ public boolean ShowAddObjectDialog(DBObject object) {
+ return getDialog().ShowDialog(getSingleDescription() + ": добавление", object);
+ }
+ public boolean ShowEditObjectDialog(DBObject object) {
+ DBObjectDialog dialog = getDialog();
+ dialog.edit = true;
+ dialog.SetEditLimits();
+ return dialog.ShowDialog(getSingleDescription() + ": редактирование", object);
+ }
+ public boolean ViewObject(DBObject object) {
+ DBObjectDialog dialog = getDialog();
+ dialog.SetReadonly();
+ dialog.ShowDialog(getSingleDescription() + ": просмотр", object);
+ return false;
+ }
+ public boolean ShowDeleteObjectDialog(DBObject object) {
+ return UI.Warning(getSingleDescription() + " " + object.getBDialogName() + " будет удален(а)");
+ }
+ public String QName() {
+ return "\"" + Name + "\"";
+ }
+ public String getPKName() {
+ return "";
+ } //получить имя ключевого поля. нужно для таблиц.
+ public String getPluralDescription() {
+ return "";
+ }
+ public String getSingleDescription() {
+ return "";
+ }
+ //времянки
+ public Current CurrentName() {
+ return Current.Undefined;
+ }
+ public boolean CheckCurrent(TextLog log) {
+ return Current.Check(log, CurrentName());
+ }
+ public boolean hasCurrent() {
+ return Current.get(CurrentName()) != null;
+ }
+ public void dropCurrent() {
+ Current.set(CurrentName(), null);
+ }
+ public D getCurrent() {
+ return (D) Current.get(CurrentName());
+ }
+ public void setCurrent(D o) {
+ Current.set(CurrentName(), o);
+ }
+ //-
+ public void put(Object key, D object) {
+ Data.put((K) key, object);
+ }
+ public D get(Object key) {
+ return Data.get(key);
+ }
+ public Object getFieldAt(D object, int columnIndex) {
+ return null;
+ }
+ public void clear() {
+ Data.clear();
+ }
+ public int size() {
+ return Data.size();
+ }
+ public boolean containsKey(Object key) {
+ return Data.containsKey(key);
+ }
+ //-
+ public Vector getVisibleKeys() {
+ Comparator comparator = getComparator();
+ Vector res = new Vector<>();
+ if (comparator == null) {
+ for (K key : Data.keySet())
+ if (Data.get(key).isVisible())
+ res.add(key);
+ } else {
+ Vector raw = new Vector<>();
+ for (D object : Data.values()) {
+ if (object.isVisible())
+ raw.add(object);
+ }
+ raw.sort(comparator);
+ for (D object : raw)
+ res.add((K) object.getPK());
+ }
+ return res;
+ }
+ protected Comparator getComparator() {
+ return null;
+ }
+ public int getCheckedCount() {
+ return (int) Data.values().stream().filter(d -> d.isVisible() && d.isSelected()).count();
+ }
+ public Vector getCheckedItems() {
+ return Data.values().stream().filter(d -> d.isVisible() && d.isSelected()).collect(Collectors.toCollection(Vector::new));
+ }
+ public Vector getCheckedKeys() {
+ return Data.values().stream().filter(DBObject::isSelected).map(d -> (K) d.getPK()).collect(Collectors.toCollection(Vector::new));
+ }
+ //--
+ public void SaveLastSelections() {
+ if (hasUI()) {
+ Object lastPk = null;
+ if ((CurrentName() != Current.Undefined) && (getCurrent() != null))
+ lastPk = getCurrent().getPK();
+ if (!selections.containsKey(getClass()))
+ selections.put(getClass(), lastPk);
+ else selections.replace(getClass(), lastPk);
+ }
+ }
+ public void RestoreLastSelections() {
+ if (hasUI()) {
+ Object lastPk = selections.get(getClass());
+ // if (lastPk != null) UI.Info(this.getClass() + ":" + lastPk.toString());
+ if ((CurrentName() != Current.Undefined) && (lastPk != null)) {
+ // UI.Info(lastPk.toString());
+ // System.out.println(ui);
+ // UI.Info("+");
+ ui_.Select(lastPk);
+ }
+ }
+ }
+ //---
+ // применить значение фильтра к фильру объекта напирмер Message.filterValue = text;
+ public void changeColumnFilterValue(int columnIndex, String text) {
+ }
+ public Object getColumnFilterValue(int columnIndex) {
+ return "";
+ }
+}
diff --git a/src/Common/Database/DataSetAnchestor.java b/src/Common/Database/DataSetAnchestor.java
new file mode 100644
index 00000000..99730376
--- /dev/null
+++ b/src/Common/Database/DataSetAnchestor.java
@@ -0,0 +1,11 @@
+package Common.Database;
+import java.util.LinkedHashMap;
+public abstract class DataSetAnchestor {
+ //чтобы обмануть стирание типов во всех параметризованных полях. используется не во всех потомках.
+ //ибо не все наборы данных относятся к базам.
+ public LinkedHashMap columns = new LinkedHashMap<>();
+ //то же самое. на самом деле внешние ключи бывают только у таблиц бд
+ public LinkedHashMap, FKBehaviour> getFKDependencies() {
+ return new LinkedHashMap<>();
+ }
+}
diff --git a/src/Common/Database/Database.java b/src/Common/Database/Database.java
new file mode 100644
index 00000000..405ea182
--- /dev/null
+++ b/src/Common/Database/Database.java
@@ -0,0 +1,274 @@
+package Common.Database;
+import Common.Global;
+import Common.Utils.Utils;
+import Repository.RepositoryRefuseException;
+
+import java.io.File;
+import java.util.LinkedHashMap;
+import java.util.Vector;
+//самый общий интерфейс базы данных, независимо от реализации.
+public abstract class Database {
+ //------------------------------
+ public LinkedHashMap, DBTable> tables = new LinkedHashMap<>(); //таблицы
+ protected File file = null;
+ public Database(File file_in) {
+ file = file_in;
+ }
+ public File getFile() {
+ return file;
+ }
+ public void setFile(File file_in) {
+ file = file_in;
+ }
+ //
+ public void Connect() throws Exception {
+ // UI.Print(DebugPrintLevel.Database, "соединение с базой данных " + file.getAbsolutePath());
+ connect();
+ }
+ public void prepareTablesStatements() throws Exception {
+ }
+ public void Disconnect() throws Exception {
+ // UI.Print(DebugPrintLevel.Database, "закрытие соединения с базой данных " + file.getAbsolutePath());
+ disconnect();
+ }
+ public void BeginTransaction() throws Exception {
+ // UI.Print(DebugPrintLevel.Database, "BEGIN TRANSACTION:");
+ beginTransaction();
+ }
+ public void Commit() throws Exception {
+ // UI.Print(DebugPrintLevel.Database, "COMMIT");
+ commit();
+ }
+ public void CreateAllTables() throws Exception {
+ BeginTransaction();
+ initAllTables(); // все добавления новых таблиц - туть.
+ for (DBTable table : tables.values()) {
+ CreateTable(table);
+ table.setDb(this);
+ }
+ Commit();
+ }
+ //схема как с проходами. в методе initAllTables добавляем все таблицы через уникальные конструкторы
+ public void addTable(DBTable table) {
+ tables.put(table.d, table);
+ }
+ public void Synchronize() throws Exception {
+ BeginTransaction();
+ for (DBTable table : tables.values())
+ LoadAll(table);
+ Init(); //перегружаемая часть синхронизации.
+ Commit();
+ }
+ public void LoadAllTablesWithoutInit() throws Exception {
+ BeginTransaction();
+ for (DBTable table : tables.values())
+ LoadAll(table);
+ Commit();
+ }
+ public void LoadAll(DBTable table) throws Exception {
+ table.Data.clear();
+ loadAll(table);
+ }
+ public DBObject Insert(DBObject o) throws Exception {
+ DBTable table = tables.get(o.getClass());
+ insert(table, o);
+ table.Data.put(o.getPK(), o);
+ return o;
+ }
+ public DBObject InsertWithCheck(DBObject o) throws Exception {
+ DBTable table = tables.get(o.getClass());
+ if (!table.Data.containsKey(o.getPK())) {
+ insert(table, o);
+ table.Data.put(o.getPK(), o);
+ } else
+ throw new RepositoryRefuseException("Таблица " + Utils.Brackets(table.Name) + " уже содержит объект с ключом " + Utils.Brackets(o.getPK().toString()));
+ return o;
+ }
+ public DBObject InsertWithCheck_(DBObject o) throws Exception {
+ DBTable table = tables.get(o.getClass());
+ if (!table.Data.containsKey(o.getPK())) {
+ insert(table, o);
+ table.Data.put(o.getPK(), o);
+ return o;
+ }
+ return null;
+ }
+ // не работает с автоинкрементом.
+ public DBObject UpdateWithCheck(DBObject to_update) throws Exception {
+ DBTable table = tables.get(to_update.getClass());
+ if (table.Data.containsKey(to_update.getPK())) {
+ DBObject o = (DBObject) table.Data.get(to_update.getPK());
+ o.SynchronizeFields(to_update);
+ update(table, o);
+ return o;
+ } else {
+ insert(table, to_update);
+ table.Data.put(to_update.getPK(), to_update);
+ return to_update;
+ }
+ }
+ public DBObject DeleteWithCheck(DBObject to_delete) throws Exception {
+ DBTable table = tables.get(to_delete.getClass());
+ if (table.Data.containsKey(to_delete.getPK())) {
+ DBObject o = (DBObject) table.Data.get(to_delete.getPK());
+ delete(table, o);
+ table.Data.remove(o.getPK());
+ return o;
+ } else
+ throw new RepositoryRefuseException("Таблица " + Utils.Brackets(table.Name) + " не содержит объект с ключом " + Utils.Brackets(to_delete.getPK().toString()));
+ }
+ // не работает с автоинкрементом.
+ public DBObject getObjectCopyByPK(Class table_class, Object pk) throws Exception {
+ DBTable table = tables.get(table_class);
+ Object res_ = table_class.newInstance();
+ DBObject res = (DBObject) res_;
+ if (table.Data.containsKey(pk)) {
+ DBObject original = (DBObject) table.Data.get(pk);
+ res.SynchronizeFields(original);
+ } else {
+ table_class.getField(table.getPKName()).set(res, pk); //инче просто синхроним пк. и вставляем
+ insert(table, res);
+ }
+ return res;
+ }
+ public boolean checkObjectExistense(Class table_class, Object pk) throws Exception {
+ DBTable table = tables.get(table_class);
+ return table.containsKey(pk);
+ }
+ public Vector
+ //
+ public Vector getVectorByFK(O owner, Class fk_class) {
+ Vector res = new Vector<>();
+ try {
+ for (Object o : tables.get(fk_class).Data.values()) {
+ if (fk_class.getField(owner.getFKName()).get(o).equals(owner.getPK())) res.add((DBObject) o);
+ }
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ return res;
+ }
+ public void DeleteByFK(DBObject master, Class fk_class) throws Exception {
+ Vector to_delete = getVectorByFK(master, fk_class);
+ BeginTransaction();
+ for (DBObject object : to_delete)
+ Delete(object);
+ Commit();
+ }
+ //-----------
+ public void DropByFK(DBObject master, Class fk_class) throws Exception {
+ Vector to_drop = getVectorByFK(master, fk_class);
+ BeginTransaction();
+ for (DBObject object : to_drop) {
+ fk_class.getField(master.getFKName()).set(object, master.getEmptyFK());
+ Update(object);
+ }
+ Commit();
+ }
+ public LinkedHashMap getMapByFK(O owner, Class fk_class, Class key_class) {
+ LinkedHashMap res = new LinkedHashMap<>();
+ try {
+ for (Object o : tables.get(fk_class).Data.values()) {
+ F f = (F) o;
+ if (fk_class.getField(owner.getFKName()).get(f).equals(owner.getPK())) res.put((K) f.getPK(), f);
+ }
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ return res;
+ }
+ public LinkedHashMap getMapByFKi(O owner, Class fk_class) {
+ return getMapByFK(owner, fk_class, java.lang.Integer.class);
+ }
+ //-
+ public Vector getVectorStringByFK(O owner, Class fk_class) {
+ Vector res = new Vector<>();
+ try {
+ for (Object o : tables.get(fk_class).Data.values()) {
+ if (fk_class.getField(owner.getFKName()).get(o).equals(owner.getPK())) res.add(o.toString());
+ }
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ return res;
+ }
+ //безопасное получение объекта по первичному ключу.
+ public O getByPK(Class class_in, Object pk, Object undefined_pk) {
+ return ((!pk.equals(undefined_pk)) && tables.get(class_in).Data.containsKey(pk)) ?
+ (O) (tables.get(class_in).Data.get(pk)) : null;
+ }
+ public O getById(Class class_in, int pk) {
+ return getByPK(class_in, pk, Utils.Nan);
+ }
+ public LinkedHashMap getByFKAndGroupBy(O owner, Class fk_class, String group_field, Class group_class) {
+ LinkedHashMap res = new LinkedHashMap<>();
+ try {
+ for (Object o : tables.get(fk_class).Data.values()) {
+ F f = (F) o;
+ if (fk_class.getField(owner.getFKName()).get(f).equals(owner.getPK()))
+ res.put((G) (fk_class.getField(group_field).get(f)), f);
+ }
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ return res;
+ }
+ //
+ //
+ //-
+ protected abstract void connect() throws Exception;
+ protected abstract void disconnect() throws Exception;
+ //-
+ protected abstract void beginTransaction() throws Exception;
+ protected abstract void commit() throws Exception;
+ //-
+ protected abstract boolean TableExists(DBTable table) throws Exception;
+ protected abstract void CreateTable(DBTable table) throws Exception;
+ protected abstract void loadAll(DBTable table) throws Exception;
+ protected abstract void initAllTables() throws Exception;
+ //перегружаемая часть синхронизации
+ public void Init() throws Exception {
+ }
+ protected abstract void insert(DBTable table, DBObject o) throws Exception;
+ protected abstract void delete(DBTable table, DBObject o) throws Exception;
+ protected abstract void deleteAll(DBTable table) throws Exception;
+ protected abstract void update(DBTable table, DBObject o) throws Exception;
+ protected abstract void resetAI(DBTable table) throws Exception;
+ //-
+ public void SaveLastSelections() {
+ for (DataSet dataSet : tables.values())
+ dataSet.SaveLastSelections();
+ }
+ public void RestoreLastSelections() {
+ for (DataSet dataSet : tables.values())
+ dataSet.RestoreLastSelections();
+ }
+}
diff --git a/src/Common/Database/FKBehaviour.java b/src/Common/Database/FKBehaviour.java
new file mode 100644
index 00000000..b0d28f0f
--- /dev/null
+++ b/src/Common/Database/FKBehaviour.java
@@ -0,0 +1,9 @@
+package Common.Database;
+public class FKBehaviour {
+ public FKDataBehaviour data; //поведение данных внешнего ключа при удалении/модификации
+ public FKCurrentObjectBehaviuor ui; //поведение интерфейсов таблиц внешнего ключа при показе текущего объекта.
+ public FKBehaviour(FKDataBehaviour data_in, FKCurrentObjectBehaviuor ui_in) {
+ data = data_in;
+ ui = ui_in;
+ }
+}
diff --git a/src/Common/Database/FKCurrentObjectBehaviuor.java b/src/Common/Database/FKCurrentObjectBehaviuor.java
new file mode 100644
index 00000000..3e457eb5
--- /dev/null
+++ b/src/Common/Database/FKCurrentObjectBehaviuor.java
@@ -0,0 +1,5 @@
+package Common.Database;
+public enum FKCurrentObjectBehaviuor {
+ PASSIVE,
+ ACTIVE
+}
diff --git a/src/Common/Database/FKDataBehaviour.java b/src/Common/Database/FKDataBehaviour.java
new file mode 100644
index 00000000..8ba134e8
--- /dev/null
+++ b/src/Common/Database/FKDataBehaviour.java
@@ -0,0 +1,7 @@
+package Common.Database;
+//поведение таблиц имеющих внешние ключи
+public enum FKDataBehaviour {
+ NONE,
+ DROP,
+ DELETE
+}
diff --git a/src/Common/Database/SQLITE/SQLiteDatabase.java b/src/Common/Database/SQLITE/SQLiteDatabase.java
new file mode 100644
index 00000000..0449b873
--- /dev/null
+++ b/src/Common/Database/SQLITE/SQLiteDatabase.java
@@ -0,0 +1,261 @@
+package Common.Database.SQLITE;
+import Common.Database.DBObject;
+import Common.Database.DBTable;
+import Common.Database.DBTableColumn;
+import Common.Database.Database;
+import Common.UI.UI;
+import Common.Utils.Utils;
+import Visual_DVM_2021.Passes.PassException;
+import javafx.util.Pair;
+
+import java.io.File;
+import java.sql.*;
+import java.util.LinkedHashMap;
+import java.util.Vector;
+
+import static Common.Utils.Utils.requireNonNullElse;
+public abstract class SQLiteDatabase extends Database {
+ protected Connection conn = null;
+ protected Statement statement = null;
+ protected ResultSet resSet = null;
+ public LinkedHashMap, PreparedStatement> insertStatements = new LinkedHashMap<>();
+ public LinkedHashMap, PreparedStatement> updateStatements = new LinkedHashMap<>();
+ public LinkedHashMap, PreparedStatement> deleteStatements = new LinkedHashMap<>();
+ //->>
+ public SQLiteDatabase(File file_in) {
+ super(file_in);
+ }
+ @Override
+ protected void connect() throws Exception {
+ Class.forName("org.sqlite.JDBC");
+ for (int i = 0; i < 5; ++i) {
+ try {
+ conn = DriverManager.getConnection("jdbc:sqlite:" + file.getAbsolutePath());
+ break;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ conn = null;
+ System.gc();
+ Utils.sleep(2000);
+ }
+ }
+ if (conn == null)
+ throw new PassException("Внутренняя ошибка sqlite. Не удалось установить соединение за 5 попыток.");
+ statement = conn.createStatement();
+ }
+ @Override
+ protected void disconnect() throws Exception {
+ if (conn != null) {
+ conn.close();
+ conn = null;
+ }
+ if (statement != null) {
+ statement.close();
+ statement = null;
+ }
+ if (resSet != null) {
+ resSet.close();
+ resSet = null;
+ }
+ for (PreparedStatement preparedStatement : insertStatements.values()) {
+ if (preparedStatement != null)
+ preparedStatement.close();
+ }
+ for (PreparedStatement preparedStatement : updateStatements.values()) {
+ if (preparedStatement != null)
+ preparedStatement.close();
+ }
+ for (PreparedStatement preparedStatement : deleteStatements.values()) {
+ if (preparedStatement != null)
+ preparedStatement.close();
+ }
+ insertStatements.clear();
+ updateStatements.clear();
+ deleteStatements.clear();
+ //-->>
+ System.gc();
+ //->>
+ }
+ @Override
+ protected void beginTransaction() throws Exception {
+ conn.setAutoCommit(false);
+ }
+ @Override
+ protected void commit() throws Exception {
+ conn.commit();
+ conn.setAutoCommit(true);
+ }
+ @Override
+ protected boolean TableExists(DBTable table) throws Exception {
+ int count = 0;
+ resSet = statement.executeQuery("SELECT count(*) FROM 'sqlite_master' WHERE type=\"table\" AND name=" + table.QName());
+ if (resSet.next())
+ count = resSet.getInt(1);
+ return count > 0;
+ }
+ @Override
+ public void CreateTable(DBTable table) throws Exception {
+ if (table.columns.size() > 0) {
+ if (TableExists(table)) {
+ Vector existing_columns = new Vector<>();
+ Vector columns_to_create = new Vector<>();
+ //предполагаем что первичный ключ и атрибуты не изменятся.
+ //и что не будет столбов с одинаковыми именами но разными типами.
+ resSet = statement.executeQuery("pragma table_info(" + table.QName() + ")");
+ while (resSet.next())
+ existing_columns.add(resSet.getString(2));
+ //-
+ for (String target_column : table.columns.keySet()) {
+ if (!existing_columns.contains(target_column))
+ columns_to_create.add(target_column);
+ }
+ for (String cn : columns_to_create)
+ statement.execute("ALTER TABLE " + table.QName() + " ADD COLUMN " + table.columns.get(cn));
+ } else {
+ String cmd = "CREATE TABLE if not exists " + table.QName() + " ";
+ Vector columns_names = new Vector<>();
+ for (DBTableColumn column : table.columns.values())
+ columns_names.add(column.toString());
+ cmd += Utils.RBrackets(String.join(",", columns_names));
+ statement.execute(cmd);
+ }
+ }
+ }
+ @Override
+ public void prepareTablesStatements() throws Exception {
+ for (DBTable table : tables.values()) {
+ //---
+ Vector column_names = new Vector<>();
+ Vector column_values = new Vector<>();
+ for (DBTableColumn column : table.columns.values()) {
+ if (!column.AutoIncrement) {
+ column_names.add(column.QName());
+ column_values.add("?");
+ }
+ }
+ insertStatements.put(table.d, conn.prepareStatement(
+ "INSERT OR REPLACE INTO " + table.QName() + " " +
+ Utils.RBrackets(String.join(",", column_names)) + " " + "VALUES " +
+ Utils.RBrackets(String.join(",", column_values))));
+ //------------------------------------------------------------------------------->>
+ Vector new_values = new Vector();
+ for (DBTableColumn column : table.columns.values()) {
+ if (!column.AutoIncrement) {
+ new_values.add(column.QName() + "=?");
+ }
+ }
+ updateStatements.put(table.d, conn.prepareStatement(
+ "UPDATE " + table.QName() + " " +
+ "SET " + String.join(",", new_values) + " " +
+ "WHERE (" + table.PK.QName() + "=?)"
+ ));
+ //---------------------------------------------------------------------------------->>>
+ deleteStatements.put(table.d, conn.prepareStatement("DELETE FROM " + table.QName() + " WHERE " + table.PK.QName() + " = ?"));
+ }
+ }
+ @Override
+ protected void delete(DBTable table, DBObject o) throws Exception {
+ PreparedStatement ps = deleteStatements.get(table.d);
+ ps.setObject(1, o.getPK());
+ ps.executeUpdate();
+ }
+ protected Pair readRecord(DBTable table) throws Exception {
+ D o = table.d.newInstance();
+ for (DBTableColumn column : table.columns.values()) {
+ Object field_value = null;
+ switch (column.type) {
+ case DOUBLE:
+ field_value = requireNonNullElse(resSet.getDouble(column.Name), 0);
+ break;
+ case UNDEFINED:
+ break;
+ case INT:
+ field_value = requireNonNullElse(resSet.getInt(column.Name), 0);
+ break;
+ case LONG:
+ field_value = requireNonNullElse(resSet.getLong(column.Name), 0);
+ break;
+ case STRING:
+ if (table.d.getField(column.Name).getType().isEnum()) {
+ Class enum_class = Class.forName(table.d.getField(column.Name).getType().getName());
+ String string = resSet.getString(column.Name);
+ Object[] enum_constants = enum_class.getEnumConstants();
+ if (string != null) {
+ try {
+ field_value = Enum.valueOf(enum_class, string);
+ } catch (Exception ignore) {
+ System.out.println(Utils.Brackets(string) + "not found");
+ field_value = enum_constants[0];
+ System.out.println(field_value);
+ }
+ } else field_value = enum_constants[0];
+ } else
+ field_value = requireNonNullElse(resSet.getString(column.Name), "");
+ break;
+ }
+ if (field_value != null) {
+ table.d.getField(column.Name).set(o, field_value);
+ } else
+ throw new PassException("Ошибка при загрузке поля " + Utils.Brackets(column.Name) + " класса " + Utils.Brackets(table.d.getSimpleName()));
+ }
+ return new Pair<>((K) o.getPK(), o);
+ }
+ @Override
+ protected void loadAll(DBTable table) throws Exception {
+ resSet = statement.executeQuery("SELECT * FROM " + table.QName());
+ while (resSet.next()) {
+ Pair record = readRecord(table);
+ table.Data.put(record.getKey(), record.getValue());
+ }
+ }
+ @Override
+ protected void insert(DBTable table, DBObject o) throws Exception {
+ PreparedStatement ps = insertStatements.get(table.d);
+ if (ps == null)
+ UI.Info("INSERT NULL");
+ int i = 1;
+ for (DBTableColumn column : table.columns.values()) {
+ if (!column.AutoIncrement) {
+ ps.setObject(i, o.getClass().getField(column.Name).get(o));
+ ++i;
+ }
+ }
+ ps.execute();
+ //-->
+ for (DBTableColumn column : table.columns.values()) {
+ if (column.AutoIncrement) {
+ resSet = statement.executeQuery("SELECT MAX(" + column.QName() + ") AS LAST FROM " + table.QName());
+ String maxId = resSet.getString("LAST");
+ int intMaxId = Integer.parseInt(maxId);
+ o.getClass().getField(column.Name).set(o, intMaxId);
+ break;
+ }
+ }
+ }
+ @Override
+ protected void update(DBTable table, DBObject o) throws Exception {
+ PreparedStatement ps = updateStatements.get(table.d);
+ if (ps == null)
+ UI.Info("UPDATE NULL");
+ int i = 1;
+ for (DBTableColumn column : table.columns.values()) {
+ if (!column.AutoIncrement) {
+ ps.setObject(i, o.getClass().getField(column.Name).get(o));
+ ++i;
+ }
+ }
+ ps.setObject(i, o.getPK());
+ ps.executeUpdate();
+ }
+ @Override
+ protected void deleteAll(DBTable table) throws Exception {
+ statement.executeUpdate("DELETE FROM " + table.QName());
+ }
+ @Override
+ protected void resetAI(DBTable table) throws Exception {
+ statement.executeUpdate("UPDATE SQLITE_SEQUENCE SET SEQ = 0 WHERE NAME =" + table.QName());
+ }
+ //--
+ //https://stackoverflow.com/questions/8558099/sqlite-query-with-byte-where-clause
+
+}
\ No newline at end of file
diff --git a/src/Common/Database/TableFilter.java b/src/Common/Database/TableFilter.java
new file mode 100644
index 00000000..e4e61865
--- /dev/null
+++ b/src/Common/Database/TableFilter.java
@@ -0,0 +1,43 @@
+package Common.Database;
+import Common.UI.Menus_2023.StableMenuItem;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+public class TableFilter {
+ DataSet table;
+ public JMenuItem menuItem; //пункт меню фильтра. ( возможно потом сделать и кнопку)
+ String description;
+ boolean active = false; //включен ли фильтр
+ public int count = 0;
+ protected boolean validate(D object) {
+ return true;
+ }
+ public boolean Validate(D object) {
+ boolean valid;
+ if (valid=validate(object))
+ count++;
+ return !active || valid;
+ }
+ static String getNotActiveIconPath() {
+ return "/icons/NotPick.png";
+ }
+ static String getActiveIconPath() {
+ return "/icons/Pick.png";
+ }
+ public TableFilter(DataSet table_in, String description_in) {
+ table = table_in;
+ menuItem = new StableMenuItem((description = description_in)+" (0)");
+ menuItem.addActionListener(e -> {
+ active = !active;
+ Mark();
+ table.ShowUI();
+ });
+ Mark();
+ }
+ public void Mark() {
+ menuItem.setIcon(Utils.getIcon(active ? getActiveIconPath() : getNotActiveIconPath()));
+ }
+ public void ShowDescriptionAndCount() {
+ menuItem.setText(description + " " + Utils.RBrackets(count));
+ }
+}
diff --git a/src/Common/Database/iDBObject.java b/src/Common/Database/iDBObject.java
new file mode 100644
index 00000000..beefc57e
--- /dev/null
+++ b/src/Common/Database/iDBObject.java
@@ -0,0 +1,30 @@
+package Common.Database;
+import Common.Utils.Utils;
+import com.sun.org.glassfish.gmbal.Description;
+//автоинкрементальный ключ
+public class iDBObject extends DBObject {
+ @Description("PRIMARY KEY,AUTOINCREMENT")
+ public int id;
+ @Override
+ public Object getPK() {
+ return id;
+ }
+ @Override
+ public String getFKName() {
+ return getClass().getSimpleName().toLowerCase() + "_id";
+ }
+ @Override
+ public Object getEmptyFK() {
+ return Utils.Nan;
+ }
+ //---
+ @Override
+ public void SynchronizeFields(DBObject src) {
+ super.SynchronizeFields(src);
+ id = ((iDBObject)src).id;
+ }
+ public iDBObject(){}
+ public iDBObject(iDBObject src){
+ this.SynchronizeFields(src);
+ }
+}
diff --git a/src/Common/Database/iDBTable.java b/src/Common/Database/iDBTable.java
new file mode 100644
index 00000000..5c1ac4c5
--- /dev/null
+++ b/src/Common/Database/iDBTable.java
@@ -0,0 +1,6 @@
+package Common.Database;
+public abstract class iDBTable extends DBTable {
+ public iDBTable(Class d_in) {
+ super(Integer.class, d_in);
+ }
+}
diff --git a/src/Common/Database/nDBObject.java b/src/Common/Database/nDBObject.java
new file mode 100644
index 00000000..99c1880a
--- /dev/null
+++ b/src/Common/Database/nDBObject.java
@@ -0,0 +1,35 @@
+package Common.Database;
+import Common.Utils.Utils;
+import com.sun.org.glassfish.gmbal.Description;
+public abstract class nDBObject extends DBObject {
+ String getClassNameL() {
+ return getClass().getSimpleName().toLowerCase();
+ }
+ @Description("PRIMARY KEY, UNIQUE")
+ public String id = "";
+ @Override
+ public Object getPK() {
+ return id;
+ }
+ @Override
+ public String getFKName() {
+ return getClassNameL() + "_id";
+ }
+ @Override
+ public Object getEmptyFK() {
+ return "";
+ }
+ public void genName() {
+ id = Utils.getDateName(getClassNameL());
+ }
+ //-
+ @Override
+ public void SynchronizeFields(DBObject src) {
+ super.SynchronizeFields(src);
+ id = ((nDBObject)src).id;
+ }
+ public nDBObject(nDBObject src){
+ this.SynchronizeFields(src);
+ }
+ public nDBObject(){}
+}
diff --git a/src/Common/Database/rDBObject.java b/src/Common/Database/rDBObject.java
new file mode 100644
index 00000000..d6eb5cc5
--- /dev/null
+++ b/src/Common/Database/rDBObject.java
@@ -0,0 +1,32 @@
+package Common.Database;
+import java.util.Date;
+//объект репозитория. ключ имя, и есть данные отправителя.
+public class rDBObject extends nDBObject {
+ public String sender_name = "";
+ public String sender_address = "";
+ public String description = "";
+ //-
+ public long date = 0;
+ public long change_date;
+ public Date getDate() {
+ return new Date(date);
+ }
+ public Date getChangeDate() {
+ return new Date(change_date);
+ }
+ @Override
+ public void SynchronizeFields(DBObject src) {
+ super.SynchronizeFields(src);
+ rDBObject r = (rDBObject) src;
+ sender_name = r.sender_name;
+ sender_address = r.sender_address;
+ description = r.description;
+ date = r.date;
+ change_date = r.change_date;
+ }
+ public rDBObject(rDBObject src) {
+ this.SynchronizeFields(src);
+ }
+ public rDBObject() {
+ }
+}
diff --git a/src/Common/Global.java b/src/Common/Global.java
new file mode 100644
index 00000000..a01fd5d5
--- /dev/null
+++ b/src/Common/Global.java
@@ -0,0 +1,403 @@
+package Common;
+import Common.Database.DataSet;
+import Common.UI.Menus_2023.ComponentsMenuBar.ComponentsMenuBar;
+import Common.UI.UI;
+import Common.Utils.Utils;
+import GlobalData.GlobalDatabase;
+import GlobalData.Settings.DBSetting;
+import GlobalData.Settings.SettingName;
+import ProjectData.ProjectView;
+import Repository.Component.*;
+import Repository.Component.PerformanceAnalyzer.PerformanceAnalyzer;
+import Repository.Component.Sapfor.MessagesServer;
+import Repository.Component.Sapfor.Sapfor_F;
+import Repository.Component.Sapfor.TransformationPermission;
+import Repository.Server.ComponentsServer;
+import TestingSystem.TestingServer;
+import Visual_DVM_2021.Passes.All.PerformSapforTasksPackage;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+import Visual_DVM_2021.UI.Interface.Loggable;
+import org.apache.commons.io.FileUtils;
+import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory;
+import org.fife.ui.rsyntaxtextarea.TokenMakerFactory;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.nio.file.Paths;
+import java.util.Vector;
+public class Global {
+ //кронтаб и перезагрузка
+ //https://snipp.ru/raznoe/crontab
+ // /var/spool/cron/crontabs/testuser что менять
+ //https://saribzhanov.ru/tehno/perezagruzka-ubuntu-po-cron/ //раз в сутки
+ //testuser ALL=NOPASSWD:/sbin/reboot
+ //0 2 2,15 * * reboot &>/var/log/reboot.log
+ //https://unix.stackexchange.com/questions/117148/how-can-i-run-reboot-as-a-normal-user-without-needing-to-enter-a-password
+ public static final String ServerAddress = "alex-freenas.ddns.net";
+ public static final String MailAddress = "sapfor.tracker@internet.ru";
+ // public static final String MailPassword = "3s4w9e5fs3c1a89AA"; основной пароль.
+ public static final String MailPassword = "knKn2PpfrC348ZxHtMnT"; //пароль для сапфора как внешнего приложения.
+ public static final String dateNaN = "NaN";
+ //--------------------------------------------------
+ //текущая папка системы. в отличие от шарпа никогда не должна меняться.
+ public static final String components = "Components";
+ public static final String data = "Data";
+ public static final String Bugs = "Bugs";
+ public static final String BackUps = "BackUps";
+ public static final String DataBackUps = "DataBackUps";
+ public static final String Temp = "Temp";
+ public static final String Projects = "Projects";
+ public static final String CompilationTasks = "CompilationTasks";
+ public static final String RunTasks = "RunTasks";
+ public static final String Sts = "Sts";
+ public static final String Repo = "Repo";
+ public static final String Tests = "Tests";
+ public static final String Packages = "Packages";
+ public static final String PerformanceAnalyzer = "PerformanceAnalyzer";
+ public static GlobalProperties properties = new GlobalProperties();
+ //
+ //------------------------------------------------------
+ public static boolean enable_text_changed = false;
+ //---
+ public static boolean files_multiselection = false;
+ public static boolean versions_multiselection = false;
+ //---
+ public static TransformationPermission transformationPermission = TransformationPermission.None;
+ //??
+ public static DataSet Components = null;
+ public static MessagesServer messagesServer = null;
+ //--------------------------------------------------
+ public static GlobalDatabase db = null;
+ public static String[] admins_mails = new String[]{
+ "vmk-post@yandex.ru",
+ "79854210702@ya.ru"
+ };
+ //-
+ public static String Home;
+ public static File ComponentsDirectory;
+ public static File DataDirectory;
+ public static File BugReportsDirectory;
+ public static File BackUpsDirectory;
+ public static File TempDirectory;
+ public static File ProjectsDirectory;
+ public static File CompilationTasksDirectory;
+ public static File RunTasksDirectory;
+ public static File StsDirectory;
+ public static File RepoDirectory;
+ public static File TestsDirectory;
+ public static File PerformanceAnalyzerDirectory;
+ public static File DataBackUpsDirectory;
+ public static File PackagesDirectory;
+ public static File SapforPackagesDirectory;
+ //------------------------------------------------------------------
+ public static Visualiser visualiser = null;
+ public static Visualizer_2 visualizer_2 = null;
+ public static PerformanceAnalyzer performanceAnalyzer = null;
+ //------------------------------------------------------------------
+ public static ComponentsServer componentsServer = new ComponentsServer();
+ public static TestingServer testingServer = new TestingServer();
+ //------------------------------------------------------------------
+ public static boolean isWindows;
+ public static int bad_state = 0;
+ public static int need_update = 0;
+ public static int need_publish = 0;
+ //------------------------------------------------------------------------
+ public static Loggable Log;
+ public static void SynschronizeProperties() {
+ //---- NEW -----
+ try {
+ File new_propertiesFile = Paths.get(Home, "properties").toFile();
+ if (new_propertiesFile.exists()) {
+ String packed = FileUtils.readFileToString(new_propertiesFile, Charset.defaultCharset());
+ properties = Utils.gson.fromJson(packed, GlobalProperties.class);
+ }
+ //пусть всегда в него пишет. с учетом того, что новые настройки могут появиться.
+ FileUtils.writeStringToFile(new_propertiesFile, Utils.jsonToPrettyFormat(Utils.gson.toJson(properties)));
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ public static void CheckVisualiserDirectories() {
+ Utils.CheckDirectory(ComponentsDirectory = Paths.get(Home, components).toFile());
+ Utils.CheckAndCleanDirectory(TempDirectory = Paths.get(Home, Temp).toFile());
+ Utils.CheckDirectory(DataDirectory = Paths.get(Home, data).toFile());
+ //-
+ Utils.CheckDirectory(RepoDirectory = Paths.get(Home, Repo).toFile());
+ Utils.CheckDirectory(BugReportsDirectory = Paths.get(Home, Bugs).toFile());
+ Utils.CheckDirectory(BackUpsDirectory = Paths.get(Home, BackUps).toFile());
+ Utils.CheckDirectory(ProjectsDirectory = Paths.get(Home, Projects).toFile());
+ Utils.CheckDirectory(CompilationTasksDirectory = Paths.get(Home, CompilationTasks).toFile());
+ Utils.CheckDirectory(RunTasksDirectory = Paths.get(Home, RunTasks).toFile());
+ Utils.CheckDirectory(StsDirectory = Paths.get(Home, Sts).toFile());
+ Utils.CheckDirectory(TestsDirectory = Paths.get(Home, Tests).toFile());
+ Utils.CheckDirectory(PerformanceAnalyzerDirectory = Paths.get(Home, PerformanceAnalyzer).toFile());
+ Utils.CheckDirectory(SapforPackagesDirectory = Paths.get(Home, "SapforTasksPackages").toFile());
+ }
+ public static void CheckServerDirectories() {
+ Utils.CheckDirectory(ComponentsDirectory = Paths.get(Home, components).toFile());
+ Utils.CheckAndCleanDirectory(TempDirectory = Paths.get(Home, Temp).toFile());
+ Utils.CheckDirectory(DataDirectory = Paths.get(Home, data).toFile());
+ //-
+ Utils.CheckDirectory(BugReportsDirectory = Paths.get(Home, Bugs).toFile());
+ Utils.CheckDirectory(DataBackUpsDirectory = Paths.get(Home, DataBackUps).toFile());
+ }
+ public static void CheckTestingSystemDirectories() {
+ Utils.CheckDirectory(ComponentsDirectory = Paths.get(Home, components).toFile());
+ Utils.CheckAndCleanDirectory(TempDirectory = Paths.get(Home, Temp).toFile());
+ Utils.CheckDirectory(DataDirectory = Paths.get(Home, data).toFile());
+ //-
+ Utils.CheckDirectory(TestsDirectory = Paths.get(Home, Tests).toFile());
+ Utils.CheckDirectory(RepoDirectory = Paths.get(Home, Repo).toFile());
+ Utils.CheckDirectory(PackagesDirectory = Paths.get(Home, Packages).toFile());
+ }
+ public static void CreateLog() {
+ Log = new Loggable() {
+ @Override
+ public String getLogHomePath() {
+ return Paths.get(Home, "Components").toString();
+ }
+ @Override
+ public String getLogName() {
+ return "VisualDVM";
+ }
+ };
+ Log.ClearLog();
+ }
+ //-
+ public static void FinishApplication() {
+ try {
+ if (db != null) db.Disconnect();
+ if (componentsServer.db != null)
+ componentsServer.db.Disconnect();
+ if (testingServer.db != null)
+ testingServer.db.Disconnect();
+ if (visualizer_2 != null)
+ visualizer_2.Shutdown();
+ if (messagesServer != null)
+ messagesServer.Shutdown();
+ if (performanceAnalyzer != null)
+ performanceAnalyzer.Shutdown();
+ } catch (Exception ex) {
+ if (Log != null) {
+ Log.PrintException(ex);
+ } else {
+ ex.printStackTrace();
+ }
+ }
+ System.exit(0);
+ }
+ public static void ActivateDB() throws Exception {
+ db = new GlobalDatabase();
+ db.Connect();
+ db.CreateAllTables();
+ db.prepareTablesStatements();
+ db.Synchronize();
+ }
+ public static void RefreshUpdatesStatus() {
+ Components.RefreshUI();
+ ValidateComponentsStates();
+ if (UI.HasNewMainWindow())
+ UI.getMainWindow().ShowUpdatesIcon();
+ }
+ public static boolean ValidateComponentsStates() {
+ bad_state = need_update = need_publish = 0;
+ for (Component component : Components.Data.values()) {
+ if (component.isVisible()) {
+ switch (component.getState()) {
+ case Not_found:
+ case Unknown_version:
+ case Old_version:
+ if (component.isNecessary())
+ bad_state++;
+ component.Select(true);
+ break;
+ case Needs_update:
+ need_update++;
+ component.Select(true);
+ break;
+ case Needs_publish:
+ need_publish++;
+ break;
+ default:
+ component.Select(false);
+ break;
+ }
+ }
+ }
+ return (bad_state == 0);
+ }
+ public static DBSetting getSetting(SettingName settingName) throws Exception {
+ switch (Current.mode) {
+ case Normal:
+ return db.settings.get(settingName);
+ default:
+ return null;
+ }
+ }
+ public static void changeSetting(SettingName settingName, Object new_value) throws Exception {
+ Pass_2021.passes.get(PassCode_2021.UpdateSetting).Do(settingName, new_value);
+ }
+ public static String packSapforSettings() {
+ Vector res_ = new Vector<>();
+ Vector forbidden = new Vector<>();
+ forbidden.add(SettingName.GCOVLimit);
+ forbidden.add(SettingName.Precompilation);
+ forbidden.add(SettingName.DVMConvertationOptions);
+ forbidden.add(SettingName.SaveModifications);
+ for (DBSetting setting : db.settings.getSettingsByOwner(ComponentType.SapforOptions)) {
+ if (!forbidden.contains(setting.Name))
+ res_.add(setting.Value);
+ }
+ return String.join("|", res_);
+ }
+ //--
+ public static void NormalMode(int port) throws Exception {
+ isWindows = System.getProperty("os.name").startsWith("Windows");
+ CheckVisualiserDirectories();
+ CreateLog();
+ //-
+ visualizer_2 = new Visualizer_2(port);
+ visualizer_2.Connect();
+ visualizer_2.refreshPid();
+ //если делать раньше, то не удастся убить сервер.
+ if (Utils.ContainsCyrillic(Global.Home)) {
+ UI.Info("В пути к корневой папке " + Utils.DQuotes(Global.Home) + "\n" +
+ "Найдены русские буквы.\n" +
+ "Визуализатор завершает работу."); //
+ FinishApplication();
+ }
+ messagesServer = new MessagesServer();
+ messagesServer.Start();
+ //создание списков служебных объектов
+ Current.CreateAll();
+ UI.CreateAll();
+ Pass_2021.CreateAll();
+ Utils.init();
+ //единственное меню до остальных.
+ UI.menuBars.put(ComponentsSet.class, new ComponentsMenuBar());
+ Components = new ComponentsSet();
+ Current.set(Current.ProjectView, ProjectView.Files);
+ Components.put(ComponentType.Visualiser, visualiser = new Visualiser());
+ Components.put(ComponentType.Sapfor_F, (Component) Current.set(Current.Sapfor, new Sapfor_F()));
+ Components.put(ComponentType.Visualizer_2, visualizer_2);
+ Components.put(ComponentType.PerformanceAnalyzer, performanceAnalyzer = new PerformanceAnalyzer());
+ Components.put(ComponentType.Instruction, new Instruction());
+ //-
+ for (Component component : Components.Data.values())
+ if (component.isVisible()) component.InitialVersionCheck();
+ //-
+ UI.CreateComponentsForm();
+ AbstractTokenMakerFactory atmf = (AbstractTokenMakerFactory) TokenMakerFactory.getDefaultInstance();
+ atmf.putMapping("text/FortranSPF", "Common.UI.Themes.FortranSPFTokenMaker");
+ atmf.putMapping("text/FreeFortranSPF", "Common.UI.Themes.FreeFortranSPFTokenMaker");
+ // FoldParserManager.get().addFoldParserMapping("text/FortranSPF", new FortranFolder()); блоки кода. todo
+ //-------->>
+ //-------->>
+ if (properties.AutoUpdateSearch)
+ Pass_2021.passes.get(PassCode_2021.GetComponentsActualVersions).Do();
+ ValidateComponentsStates();
+ if ((need_update > 0) || (bad_state > 0)) {
+ boolean flag = true;
+ do {
+ UI.ShowComponentsWindow();
+ if (flag = (!ValidateComponentsStates())) {
+ if (!UI.Question("Найдено " + bad_state + " некорректных необходимых компонент.Работа визуализатора невозможна.\n" +
+ "Вернуться к окну компонент"
+ )) {
+ UI.Info("Визуализатор завершает работу.");
+ FinishApplication();
+ }
+ }
+ } while (flag);
+ }
+ //---
+ ActivateDB(); //тут current getAccount; роль по умолчанию всегда неизвестна.
+ ///--------------
+ Pass_2021.passes.get(PassCode_2021.CheckAccount).Do();
+ //---------------
+ componentsServer.ActivateDB();
+ testingServer.ActivateDB();
+ //-- чисто чтобы создать таблицы. соединения на стороне клиента не предвидится.
+ testingServer.SetCurrentAccountDB(Current.getAccount().email);
+ //--->>>
+ if (db.settings.get(SettingName.AutoBugReportsLoad).toBoolean())
+ Pass_2021.passes.get(PassCode_2021.SynchronizeBugReports).Do();
+ //--
+ if (db.settings.get(SettingName.AutoTestsLoad).toBoolean())
+ Pass_2021.passes.get(PassCode_2021.SynchronizeTests).Do();
+ Pass_2021.CheckAllStats();
+ Current.getSapfor().refreshPid(); //без сапфора сюда это все равно не дойдет.
+ UI.CreateMenus();
+ UI.CreateWindows();
+ }
+ public static void ServerMode() throws Exception {
+ isWindows = false;
+ CheckServerDirectories();
+ CreateLog();
+ componentsServer = new ComponentsServer();
+ componentsServer.ActivateDB();
+ componentsServer.Start();
+ System.exit(0);
+ }
+ public static void TestingSystemMode() throws Exception {
+ isWindows = false;
+ CheckTestingSystemDirectories();
+ CreateLog();
+ testingServer = new TestingServer();
+ testingServer.ActivateDB();
+ testingServer.Start();
+ System.exit(0);
+ }
+ public static void PackageMode() throws Exception {
+ Log = new Loggable() {
+ @Override
+ public String getLogHomePath() {
+ return Home;
+ }
+ @Override
+ public String getLogName() {
+ return "PackageMode";
+ }
+ };
+ Log.ClearLog();
+ //--
+ Pass_2021 pass = new PerformSapforTasksPackage();
+ pass.Do(Home);
+ //--
+ }
+ //---
+ public static void Init(String... args) {
+ System.out.println("VisualSapfor.jar started..");
+ Home = System.getProperty("user.dir"); //если Linux, дает без слеша в конце !!!
+ System.out.println("home directory is" + Utils.Brackets(Home));
+ //---
+ SynschronizeProperties();
+ Current.mode = properties.Mode;
+ System.out.println("mode is " + Current.mode);
+ try {
+ switch (Current.mode) {
+ case Normal:
+ NormalMode(Integer.parseInt(args[1]));
+ break;
+ case Server:
+ ServerMode();
+ break;
+ case Testing:
+ TestingSystemMode();
+ break;
+ case Package:
+ PackageMode();
+ break;
+ case Undefined:
+ break;
+ }
+ } catch (Exception ex) {
+ System.out.println("VISUALISER FAILED");
+ ex.printStackTrace();
+ if (Global.Log != null)
+ Global.Log.PrintException(ex);
+ FinishApplication();
+ }
+ }
+}
diff --git a/src/Common/GlobalProperties.java b/src/Common/GlobalProperties.java
new file mode 100644
index 00000000..f16ecba0
--- /dev/null
+++ b/src/Common/GlobalProperties.java
@@ -0,0 +1,87 @@
+package Common;
+import com.google.gson.annotations.Expose;
+
+import java.io.File;
+import java.nio.file.Paths;
+public class GlobalProperties extends Properties {
+ @Expose
+ public Current.Mode Mode = Current.Mode.Normal;
+ //---
+ @Expose
+ public int SocketTimeout = 5000;
+ @Expose
+ public boolean OldServer = false;
+ //---
+ @Expose
+ public String SMTPHost = "smtp.mail.ru";
+ @Expose
+ public int SMTPPort = 465;
+ @Expose
+ public int MailSocketPort = 465;
+ //---
+ @Expose
+ public String BackupWorkspace = "_sapfor_x64_backups";
+ @Expose
+ public int BackupHour = 5;
+ @Expose
+ public int BackupMinute = 0;
+ @Expose
+ public boolean EmailAdminsOnStart = false;
+ //---
+ @Expose
+ public boolean AutoUpdateSearch = true;
+ // настройки визуализатора. по крайней мере, флаги.
+ @Expose
+ public boolean ConfirmPassesStart = true;
+ @Expose
+ public boolean ShowPassesDone = true;
+ @Expose
+ public boolean FocusPassesResult = true;
+ //-
+ @Expose
+ public String GlobalDBName = "db7.sqlite";
+ @Expose
+ public String ProjectDBName = "new_project_base.sqlite";
+ @Expose
+ public String BugReportsDBName = "bug_reports.sqlite";
+ @Expose
+ public String TestsDBName = "tests.sqlite";
+ //-
+ @Expose
+ public int ComponentsWindowWidth = 650;
+ @Expose
+ public int ComponentsWindowHeight = 250;
+ //-
+ @Expose
+ public String VisualiserPath = "";
+ @Expose
+ public String Sapfor_FPath = "";
+ @Expose
+ public String Visualizer_2Path = "";
+ @Expose
+ public String InstructionPath = "";
+ @Expose
+ public String PerformanceAnalyzerPath = "";
+ @Expose
+ public int ComponentsBackUpsCount=10;
+ @Expose
+ public long SapforTaskMaxId = 0; //вероятно, временно. когда перейдем на удаленную машину.
+ //-
+ @Override
+ public String getFieldDescription(String fieldName) {
+ switch (fieldName) {
+ case "ShowPassesDone":
+ return "Сообщать об успешном выполнении проходов";
+ case "ConfirmPassesStart":
+ return "Запрашивать подтверждения начала выполнения проходов";
+ case "FocusPassesResult":
+ return "Переходить на результирующую вкладку проходов по их завершении";
+ default:
+ return "?";
+ }
+ }
+ @Override
+ public File getFile() {
+ return Paths.get(System.getProperty("user.dir"),"properties").toFile();
+ }
+}
diff --git a/src/Common/PackageModeSupervisor.java b/src/Common/PackageModeSupervisor.java
new file mode 100644
index 00000000..456e06ca
--- /dev/null
+++ b/src/Common/PackageModeSupervisor.java
@@ -0,0 +1,3 @@
+package Common;
+public class PackageModeSupervisor {
+}
diff --git a/src/Common/Properties.java b/src/Common/Properties.java
new file mode 100644
index 00000000..2492fbde
--- /dev/null
+++ b/src/Common/Properties.java
@@ -0,0 +1,50 @@
+package Common;
+import Common.UI.Menus_2023.StableMenuItem;
+import Common.Utils.Utils;
+import org.apache.commons.io.FileUtils;
+
+import javax.swing.*;
+import java.io.File;
+public abstract class Properties {
+ public void addFlagMenuItem(JMenu menu, String fieldName) {
+ JMenuItem menu_item = new StableMenuItem(getFieldDescription(fieldName),
+ getFlag(fieldName) ? "/icons/Pick.png" : "/icons/NotPick.png");
+ //-
+ menu_item.addActionListener(e -> {
+ switchFlag(fieldName);
+ Update();
+ menu_item.setIcon(Utils.getIcon(getFlag(fieldName) ? "/icons/Pick.png" : "/icons/NotPick.png"));
+ });
+ menu.add(menu_item);
+ }
+ public boolean getFlag(String fieldName) {
+ boolean field = false;
+ try {
+ field = (boolean) GlobalProperties.class.getField(fieldName).get(this);
+ //
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ return field;
+ }
+ public void switchFlag(String fieldName) {
+ boolean field = false;
+ try {
+ field = (boolean) GlobalProperties.class.getField(fieldName).get(this);
+ GlobalProperties.class.getField(fieldName).set(this, !field);
+ //
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ public void Update() {
+ try {
+ FileUtils.write(getFile(), Utils.jsonToPrettyFormat(Utils.gson.toJson(this)));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ //--
+ public abstract String getFieldDescription(String fieldName);
+ public abstract File getFile();
+}
diff --git a/src/Common/UI/ComboBox/StyledTextComboBox.java b/src/Common/UI/ComboBox/StyledTextComboBox.java
new file mode 100644
index 00000000..1e3c428b
--- /dev/null
+++ b/src/Common/UI/ComboBox/StyledTextComboBox.java
@@ -0,0 +1,9 @@
+package Common.UI.ComboBox;
+import Common.UI.Menus.TextComboBoxMenu;
+
+import javax.swing.*;
+public class StyledTextComboBox extends JComboBox {
+ public StyledTextComboBox() {
+ setComponentPopupMenu(new TextComboBoxMenu(this));
+ }
+}
diff --git a/src/Common/UI/ControlForm.java b/src/Common/UI/ControlForm.java
new file mode 100644
index 00000000..8b63ae6f
--- /dev/null
+++ b/src/Common/UI/ControlForm.java
@@ -0,0 +1,53 @@
+package Common.UI;
+import Common.Global;
+
+import javax.swing.*;
+import java.awt.*;
+//класс, представляющий собой прокручиваемую панель, на которой лежит нечто.
+public class ControlForm {
+ public C control = null;
+ protected Class control_class;
+ protected JPanel content; //задник.
+ public JScrollPane scroll = null;
+ public ControlForm(Class class_in) {
+ control_class = class_in;
+ setContent(new JPanel(new BorderLayout()));
+ }
+ //нужно будет вывестии сделать нормальные формы для деревьев а не ручное создание.
+ public JPanel getContent() {
+ return content;
+ }
+ public void setContent(JPanel content_in) {
+
+ content = content_in;
+ }
+ //-
+ public void Show() {
+ Clear();
+ CreateControl();
+ //------------------------
+ scroll = new JScrollPane(control);
+ scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
+ scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ }
+ public void CreateControl() {
+ try {
+ control = control_class.newInstance();
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ }
+ public boolean isShown() {
+ return control != null;
+ }
+ public void Clear() {
+ control = null; //очищено.
+ }
+ public void Refresh() {
+ if (control != null)
+ refresh();
+ }
+ //-
+ protected void refresh() {
+ } //перерисовать контрол.
+}
diff --git a/src/Common/UI/ControlWithCurrentForm.java b/src/Common/UI/ControlWithCurrentForm.java
new file mode 100644
index 00000000..4bd6e0e9
--- /dev/null
+++ b/src/Common/UI/ControlWithCurrentForm.java
@@ -0,0 +1,19 @@
+package Common.UI;
+import Common.Current;
+
+import java.awt.*;
+public class ControlWithCurrentForm extends ControlForm {
+ public ControlWithCurrentForm(Class class_in) {
+ super(class_in);
+ }
+ //-
+ public Current CurrentName() {
+ return Current.Undefined;
+ }
+ public void ShowCurrentObject() throws Exception {
+ }
+ public void ShowNoCurrentObject() throws Exception {
+ }
+ public void MouseAction2() throws Exception {
+ }
+}
diff --git a/src/Common/UI/DataControl.java b/src/Common/UI/DataControl.java
new file mode 100644
index 00000000..3377dbef
--- /dev/null
+++ b/src/Common/UI/DataControl.java
@@ -0,0 +1,7 @@
+package Common.UI;
+import Common.Database.DBObject;
+public interface DataControl {
+ DBObject getRowObject(int rowIndex); //получить объект, сответствующий данной строке.
+ void SelectRowByPK(Object pk);
+ //выделить строку где лежит объект с данным первичным ключом.
+}
diff --git a/src/Common/UI/DataControl_OLD.java b/src/Common/UI/DataControl_OLD.java
new file mode 100644
index 00000000..ed892f13
--- /dev/null
+++ b/src/Common/UI/DataControl_OLD.java
@@ -0,0 +1,13 @@
+package Common.UI;
+import Common.Current;
+public interface DataControl_OLD {
+ //todo скорее всего устареет.
+ default Current getCurrent() {
+ return Current.Undefined;
+ }
+ //-?
+ default void ShowCurrentObject() throws Exception {
+ }
+ default void ShowNoCurrentObject() throws Exception {
+ }
+}
diff --git a/src/Common/UI/DataSetControlForm.java b/src/Common/UI/DataSetControlForm.java
new file mode 100644
index 00000000..9ce7165a
--- /dev/null
+++ b/src/Common/UI/DataSetControlForm.java
@@ -0,0 +1,329 @@
+package Common.UI;
+import Common.Current;
+import Common.Database.DBObject;
+import Common.Database.DBTable;
+import Common.Database.DataSet;
+import Common.Database.FKBehaviour;
+import Common.Global;
+import Common.UI.Menus.TableMenu;
+import Common.UI.Tables.ColumnInfo;
+import Common.UI.Tables.DataTable;
+import Common.UI.Tables.Grid.GridAnchestor;
+import Common.Utils.Utils;
+import GlobalData.Grid.Grid;
+
+import javax.swing.*;
+import javax.swing.table.TableColumn;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Arrays;
+import java.util.Vector;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static Common.UI.Tables.TableEditors.EditorSelect;
+import static Common.UI.Tables.TableRenderers.RendererSelect;
+public class DataSetControlForm extends ControlWithCurrentForm {
+ protected JPanel dataPanel;
+ protected DataSet dataSource;
+ public JPanel getDataPanel() {
+ return dataPanel;
+ }
+ protected int current_row_i;
+ protected boolean events_on = true;
+ protected String colNamesAndSizes = "";
+ protected Vector columns = new Vector<>();
+ public DataSetControlForm(DataSet dataSource_in) {
+ this(dataSource_in, DataTable.class);
+ }
+ public DataSetControlForm(DataSet dataSource_in, Class tableClass) {
+ super(tableClass);
+ dataSource = dataSource_in;
+ //---
+ dataPanel = new JPanel(new BorderLayout());
+ content.add(dataPanel, BorderLayout.CENTER);
+ }
+ @Override
+ public void Show() {
+ super.Show();
+ dataPanel.add(scroll);
+ dataPanel.updateUI();
+ }
+ @Override
+ public void Clear() {
+ super.Clear();
+ UI.Clear(dataPanel);
+ }
+ public DataSet getDataSource() {
+ return dataSource;
+ }
+ @Override
+ public Current CurrentName() {
+ return getDataSource().CurrentName();
+ }
+ public void SaveColumns() {
+ if (Global.db != null) {
+ try {
+ if ((CurrentName() != Current.Undefined)) {
+ Vector widths = IntStream.range(0, columns.size()).mapToObj(i -> String.valueOf(control.getColumnModel().getColumn(i).getWidth())).collect(Collectors.toCollection(Vector::new));
+ String packed = String.join("|", widths);
+ Grid grid;
+ if (Global.db.grids.containsKey(CurrentName())) {
+ grid = Global.db.grids.get(CurrentName());
+ } else {
+ grid = new Grid(CurrentName());
+ Global.db.Insert(grid);
+ }
+ grid.sizes = packed;
+ Global.db.Update(grid);
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ public boolean hasCheckBox() {
+ return false;
+ }
+ private Vector getHeaders() {
+ return columns.stream().map(ColumnInfo::getName).collect(Collectors.toCollection(Vector::new));
+ }
+ protected void CreateColumnsInfo() {
+ columns.clear();
+ columns.add(new ColumnInfo(getDataSource().getPKName()));
+ if (hasCheckBox()) {
+ columns.add(new ColumnInfo("", RendererSelect, EditorSelect));
+ columns.get(1).setMinWidth(25);
+ columns.get(1).setMaxWidth(25);
+ }
+ Arrays.stream(getDataSource().getUIColumnNames()).forEach(name -> columns.add(new ColumnInfo(name)));
+ AdditionalInitColumns();
+ }
+ protected void AdditionalInitColumns() {
+ //уточнение инфы по столбцам.
+ }
+ @SuppressWarnings("unchecked")
+ @Override
+ public void CreateControl() {
+ CreateColumnsInfo();
+ GridAnchestor table_data_model = new GridAnchestor(getHeaders(), dataSource.getVisibleKeys()) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ Object key = data.get(rowIndex);
+ if (columnIndex == 0)
+ return key;
+ DBObject object = getDataSource().get((key));
+ if ((columnIndex == 1) && hasCheckBox())
+ return object.isSelected();
+ return getDataSource().getFieldAt(object, columnIndex);
+ }
+ @Override
+ public boolean isCellEditable(int row, int col) {
+ return columns.get(col).isEditable();
+ }
+ //------------------------------------------------------------------------------------
+ @Override
+ public void setValueAt(Object value, int row, int col) {
+ fireTableCellUpdated(row, col);
+ }
+ };
+ control = new DataTable(table_data_model) {
+ @Override
+ public TableMenu CreateMenu() {
+ return new TableMenu(this);
+ }
+ //строго говоря эта штука нужна только для рендереров и едиторов клеток.
+ @Override
+ public DBObject getRowObject(int rowIndex) {
+ //вот так делать НЕЛЬЗЯ. модель только для внутреннего пользования
+ // Object key = table_data_model.data.get(rowIndex);
+ //из таблицы можно пользоваться только getValueAt
+ //иначе сортировка не будет работать.
+ Object key = getValueAt(rowIndex, 0);
+ return getDataSource().get(key);
+ }
+ //-----------------------------NEW-------------------------------------
+ @Override
+ public void CorrectColumnsSizes() {
+ if ((Global.db != null) && CurrentName() != Current.Undefined && Global.db.grids.containsKey(CurrentName())) {
+ //Undefined может оказаться в таблице, например если енум устарел. Поэтому надо проверять.
+ if (!getColumnsProfile().equalsIgnoreCase(colNamesAndSizes)) {
+ Grid grid = Global.db.grids.get(CurrentName());
+ String[] data = grid.sizes.split("\\|");
+ for (int i = 0; i < columns.size(); ++i) {
+ if (i <= (data.length - 1)) {
+ int width = Integer.parseInt(data[i]);
+ getColumnModel().getColumn(i).setPreferredWidth(width);
+ getColumnModel().getColumn(i).setWidth(width);
+ }
+ }
+ }
+ } else
+ super.CorrectColumnsSizes(); //обычный авторазмер.
+ }
+ public String getColumnsProfile() {
+ String res = "";
+ for (int i = 0; i < getColumnModel().getColumnCount(); i++) {
+ if (i > 0) res += ",";
+ TableColumn column = getColumnModel().getColumn(i);
+ res += column.getHeaderValue();
+ res += ":";
+ res += column.getWidth();
+ }
+ return res;
+ }
+ @Override
+ public void Init() {
+ for (int i = 0; i < columns.size(); i++) {
+ ColumnInfo columnInfo = columns.get(i);
+ if (columnInfo.isVisible()) {
+ if (columnInfo.hasRenderer())
+ getColumnModel().getColumn(i).setCellRenderer(UI.TableRenderers.get(columnInfo.getRenderer()));
+ if (columnInfo.hasEditor())
+ getColumnModel().getColumn(i).setCellEditor(UI.TableEditors.get(columnInfo.getEditor()));
+ if (columnInfo.hasMaxWidth())
+ getColumnModel().getColumn((i)).setMaxWidth(columnInfo.getMaxWidth());
+ if (columnInfo.hasMinWidth())
+ getColumnModel().getColumn((i)).setMinWidth(columnInfo.getMinWidth());
+ } else {
+ getColumnModel().getColumn(i).setMinWidth(0);
+ getColumnModel().getColumn(i).setMaxWidth(0);
+ }
+ }
+ //обновление в БД при ручном изменении размера столбиков.--------->>
+ getTableHeader().addMouseListener(new MouseAdapter() {
+ public void mouseReleased(MouseEvent arg0) {
+ System.out.println("Header mouse released");
+ String new_colNamesAndSizes = getColumnsProfile();
+ // check if changed, if yes, persist...
+ if (!colNamesAndSizes.equals(new_colNamesAndSizes)) {
+ colNamesAndSizes = new_colNamesAndSizes;
+ SaveColumns();
+ System.out.println("columns updated");
+ }
+ }
+ });
+ //------------------------->>
+ }
+ };
+ if (CurrentName() != Current.Undefined) {
+ current_row_i = Utils.Nan;
+ ListSelectionModel selModel = control.getSelectionModel();
+ selModel.addListSelectionListener(e -> {
+ int row = control.getSelectedRow();
+ if ((row >= 0)) {
+ if (row != current_row_i) {
+ current_row_i = row;
+ // System.out.println("current row_i="+current_row_i);
+ getDataSource().setCurrent(control.getRowObject(row));
+ if (events_on) {
+ try {
+ ShowCurrentObject();
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ }
+ }
+ } else {
+ current_row_i = Utils.Nan;
+ // System.out.println("no current row_i="+current_row_i);
+ getDataSource().dropCurrent();
+ if (events_on) {
+ try {
+ ShowNoCurrentObject();
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ }
+ }
+ });
+ //двойной клик мыши.------------------------------------------------------
+ control.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if ((e.getClickCount() == 2) && (dataSource.getCurrent() != null)) {
+ try {
+ MouseAction2();
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ }
+ }
+ });
+ //----------------------------------------------------------------------------
+ //при переотображении таблицы скидываем текущий объект!!
+ getDataSource().dropCurrent();
+ try {
+ ShowNoCurrentObject();
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ }
+ //---
+ /*
+ if (hasCheckBox()) {
+ TableColumn column = control.getColumnModel().getColumn(1)
+ column.setHeaderRenderer(new TableCellRenderer() {
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+ return null;
+ }
+
+ });
+ }
+ */
+ }
+ @Override
+ protected void refresh() {
+ control.CorrectSizes();
+ }
+ public void Show(Object pk) {
+ Show();
+ Select(pk);
+ }
+ public void Select(Object pk) {
+ if (isShown())
+ control.SelectRowByPK(pk);
+ }
+ public void ClearSelection() {
+ if (isShown())
+ control.clearSelection(); //строка сбросится сама. благодаря сбросу события выбора
+ }
+ public int getRowCount() {
+ return control.getRowCount();
+ }
+ @Override
+ public void ShowCurrentObject() throws Exception {
+ if (dataSource instanceof DBTable) {
+ DBTable table = (DBTable) dataSource;
+ for (Class dep : table.getFKDependencies().keySet()) {
+ FKBehaviour behaviour = table.getFKDependencies().get(dep);
+ switch (behaviour.ui) {
+ case ACTIVE:
+ table.getDb().tables.get(dep).ShowUI();
+ break;
+ case PASSIVE:
+ break;
+ }
+ }
+ }
+ }
+ @Override
+ public void ShowNoCurrentObject() throws Exception {
+ if (dataSource instanceof DBTable) {
+ DBTable table = (DBTable) dataSource;
+ for (Class dep : table.getFKDependencies().keySet()) {
+ FKBehaviour behaviour = table.getFKDependencies().get(dep);
+ switch (behaviour.ui) {
+ case ACTIVE:
+ table.getDb().tables.get(dep).ClearUI();
+ break;
+ case PASSIVE:
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/src/Common/UI/DebugPrintLevel.java b/src/Common/UI/DebugPrintLevel.java
new file mode 100644
index 00000000..63500b6f
--- /dev/null
+++ b/src/Common/UI/DebugPrintLevel.java
@@ -0,0 +1,17 @@
+package Common.UI;
+public enum DebugPrintLevel {
+ Undefined,
+ Passes,
+ Project;
+ public String getDescription() {
+ return toString();
+ }
+ public boolean isEnabled() {
+ switch (this) {
+ case Passes:
+ return true;
+ default:
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Common/UI/DragDrop/ExampleDrop.java b/src/Common/UI/DragDrop/ExampleDrop.java
new file mode 100644
index 00000000..ea726aa0
--- /dev/null
+++ b/src/Common/UI/DragDrop/ExampleDrop.java
@@ -0,0 +1,33 @@
+package Common.UI.DragDrop;
+import javax.swing.*;
+/**
+ * A simple example showing how to use {@link FileDrop}
+ *
+ * @author Robert Harder, rob@iharder.net
+ */
+public class ExampleDrop {
+ /*
+ /** Runs a sample program that shows dropped files */
+ public static void kek(String[] args) {
+ javax.swing.JFrame frame = new javax.swing.JFrame("FileDrop");
+ //javax.swing.border.TitledBorder dragBorder = new javax.swing.border.TitledBorder( "Drop 'em" );
+ final javax.swing.JTextArea text = new javax.swing.JTextArea();
+ frame.getContentPane().add(
+ new javax.swing.JScrollPane(text),
+ java.awt.BorderLayout.CENTER);
+ new FileDrop(System.out, text, /*dragBorder,*/ new FileDrop.Listener() {
+ public void filesDropped(java.io.File[] files) {
+ for (int i = 0; i < files.length; i++) {
+ try {
+ text.append(files[i].getCanonicalPath() + "\n");
+ } // end try
+ catch (java.io.IOException e) {
+ }
+ } // end for: through each dropped file
+ } // end filesDropped
+ }); // end FileDrop.Listener
+ frame.setBounds(100, 100, 300, 400);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ } // end main
+}
diff --git a/src/Common/UI/DragDrop/FileDrop.java b/src/Common/UI/DragDrop/FileDrop.java
new file mode 100644
index 00000000..4d68ce8d
--- /dev/null
+++ b/src/Common/UI/DragDrop/FileDrop.java
@@ -0,0 +1,792 @@
+package Common.UI.DragDrop;
+import Common.Global;
+
+import java.awt.datatransfer.DataFlavor;
+import java.io.*;
+/**
+ * This class makes it easy to drag and drop files from the operating
+ * system to a Java program. Any java.awt.Component can be
+ * dropped onto, but only javax.swing.JComponents will indicate
+ * the drop event with a changed border.
+ *
+ * To use this class, construct a new FileDrop by passing
+ * it the target component and a Listener to receive notification
+ * when file(s) have been dropped. Here is an example:
+ *
+ *
+ * JPanel myPanel = new JPanel();
+ * new FileDrop( myPanel, new FileDrop.Listener()
+ * { public void filesDropped( java.io.File[] files )
+ * {
+ * // handle file drop
+ * ...
+ * } // end filesDropped
+ * }); // end FileDrop.Listener
+ *
+ *
+ * You can specify the border that will appear when files are being dragged by
+ * calling the constructor with a javax.swing.border.Border. Only
+ * JComponents will show any indication with a border.
+ *
+ * You can turn on some debugging features by passing a PrintStream
+ * object (such as System.out) into the full constructor. A null
+ * value will result in no extra debugging information being output.
+ *
+ *
+ *
I'm releasing this code into the Public Domain. Enjoy.
+ *
+ *
Original author: Robert Harder, rharder@usa.net
+ *
2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added.
+ *
+ * @author Robert Harder
+ * @author rharder@users.sf.net
+ * @version 1.0.1
+ */
+public class FileDrop {
+ // Default border color
+ private static final java.awt.Color defaultBorderColor = new java.awt.Color(0f, 0f, 1f, 0.25f);
+ // BEGIN 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added.
+ private static final String ZERO_CHAR_STRING = "" + (char) 0;
+ /**
+ * Discover if the running JVM is modern enough to have drag and drop.
+ */
+ private static Boolean supportsDnD;
+ private transient javax.swing.border.Border normalBorder;
+ private transient java.awt.dnd.DropTargetListener dropListener;
+ /**
+ * Constructs a {@link FileDrop} with a default light-blue border
+ * and, if c is a {@link java.awt.Container}, recursively
+ * sets all elements contained within as drop targets, though only
+ * the top level container will change borders.
+ *
+ * @param c Component on which files will be dropped.
+ * @param listener Listens for filesDropped.
+ * @since 1.0
+ */
+ public FileDrop(
+ final java.awt.Component c,
+ final Listener listener) {
+ this(null, // Logging stream
+ c, // Drop target
+ javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, defaultBorderColor), // Drag border
+ true, // Recursive
+ listener);
+ } // end constructor
+ /**
+ * Constructor with a default border and the option to recursively set drop targets.
+ * If your component is a java.awt.Container, then each of its children
+ * database.Objects.components will also listen for drops, though only the parent will change borders.
+ *
+ * @param c Component on which files will be dropped.
+ * @param recursive Recursively set children as drop targets.
+ * @param listener Listens for filesDropped.
+ * @since 1.0
+ */
+ public FileDrop(
+ final java.awt.Component c,
+ final boolean recursive,
+ final Listener listener) {
+ this(null, // Logging stream
+ c, // Drop target
+ javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, defaultBorderColor), // Drag border
+ recursive, // Recursive
+ listener);
+ } // end constructor
+ /**
+ * Constructor with a default border and debugging optionally turned on.
+ * With Debugging turned on, more status messages will be displayed to
+ * out. A common way to use this constructor is with
+ * System.out or System.err. A null value for
+ * the parameter out will result in no debugging output.
+ *
+ * @param out PrintStream to record debugging info or null for no debugging.
+ * @param out
+ * @param c Component on which files will be dropped.
+ * @param listener Listens for filesDropped.
+ * @since 1.0
+ */
+ public FileDrop(
+ final PrintStream out,
+ final java.awt.Component c,
+ final Listener listener) {
+ this(out, // Logging stream
+ c, // Drop target
+ javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, defaultBorderColor),
+ false, // Recursive
+ listener);
+ } // end constructor
+ /**
+ * Constructor with a default border, debugging optionally turned on
+ * and the option to recursively set drop targets.
+ * If your component is a java.awt.Container, then each of its children
+ * database.Objects.components will also listen for drops, though only the parent will change borders.
+ * With Debugging turned on, more status messages will be displayed to
+ * out. A common way to use this constructor is with
+ * System.out or System.err. A null value for
+ * the parameter out will result in no debugging output.
+ *
+ * @param out PrintStream to record debugging info or null for no debugging.
+ * @param out
+ * @param c Component on which files will be dropped.
+ * @param recursive Recursively set children as drop targets.
+ * @param listener Listens for filesDropped.
+ * @since 1.0
+ */
+ public FileDrop(
+ final PrintStream out,
+ final java.awt.Component c,
+ final boolean recursive,
+ final Listener listener) {
+ this(out, // Logging stream
+ c, // Drop target
+ javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, defaultBorderColor), // Drag border
+ recursive, // Recursive
+ listener);
+ } // end constructor
+ /**
+ * Constructor with a specified border
+ *
+ * @param c Component on which files will be dropped.
+ * @param dragBorder Border to use on JComponent when dragging occurs.
+ * @param listener Listens for filesDropped.
+ * @since 1.0
+ */
+ public FileDrop(
+ final java.awt.Component c,
+ final javax.swing.border.Border dragBorder,
+ final Listener listener) {
+ this(
+ null, // Logging stream
+ c, // Drop target
+ dragBorder, // Drag border
+ false, // Recursive
+ listener);
+ } // end constructor
+ /**
+ * Constructor with a specified border and the option to recursively set drop targets.
+ * If your component is a java.awt.Container, then each of its children
+ * database.Objects.components will also listen for drops, though only the parent will change borders.
+ *
+ * @param c Component on which files will be dropped.
+ * @param dragBorder Border to use on JComponent when dragging occurs.
+ * @param recursive Recursively set children as drop targets.
+ * @param listener Listens for filesDropped.
+ * @since 1.0
+ */
+ public FileDrop(
+ final java.awt.Component c,
+ final javax.swing.border.Border dragBorder,
+ final boolean recursive,
+ final Listener listener) {
+ this(
+ null,
+ c,
+ dragBorder,
+ recursive,
+ listener);
+ } // end constructor
+ /**
+ * Constructor with a specified border and debugging optionally turned on.
+ * With Debugging turned on, more status messages will be displayed to
+ * out. A common way to use this constructor is with
+ * System.out or System.err. A null value for
+ * the parameter out will result in no debugging output.
+ *
+ * @param out PrintStream to record debugging info or null for no debugging.
+ * @param c Component on which files will be dropped.
+ * @param dragBorder Border to use on JComponent when dragging occurs.
+ * @param listener Listens for filesDropped.
+ * @since 1.0
+ */
+ public FileDrop(
+ final PrintStream out,
+ final java.awt.Component c,
+ final javax.swing.border.Border dragBorder,
+ final Listener listener) {
+ this(
+ out, // Logging stream
+ c, // Drop target
+ dragBorder, // Drag border
+ false, // Recursive
+ listener);
+ } // end constructor
+ /**
+ * Full constructor with a specified border and debugging optionally turned on.
+ * With Debugging turned on, more status messages will be displayed to
+ * out. A common way to use this constructor is with
+ * System.out or System.err. A null value for
+ * the parameter out will result in no debugging output.
+ *
+ * @param out PrintStream to record debugging info or null for no debugging.
+ * @param c Component on which files will be dropped.
+ * @param dragBorder Border to use on JComponent when dragging occurs.
+ * @param recursive Recursively set children as drop targets.
+ * @param listener Listens for filesDropped.
+ * @since 1.0
+ */
+ public FileDrop(
+ final PrintStream out,
+ final java.awt.Component c,
+ final javax.swing.border.Border dragBorder,
+ final boolean recursive,
+ final Listener listener) {
+ if (supportsDnD()) { // Make a drop listener
+ dropListener = new java.awt.dnd.DropTargetListener() {
+ public void dragEnter(java.awt.dnd.DropTargetDragEvent evt) {
+ log(out, "FileDrop: dragEnter event.");
+ // Is this an acceptable drag event?
+ if (isDragOk(out, evt)) {
+ // If it's a Swing component, set its border
+ if (c instanceof javax.swing.JComponent) {
+ javax.swing.JComponent jc = (javax.swing.JComponent) c;
+ normalBorder = jc.getBorder();
+ log(out, "FileDrop: normal border saved.");
+ jc.setBorder(dragBorder);
+ log(out, "FileDrop: drag border set.");
+ } // end if: JComponent
+ // Acknowledge that it's okay to enter
+ //evt.acceptDrag( java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE );
+ evt.acceptDrag(java.awt.dnd.DnDConstants.ACTION_COPY);
+ log(out, "FileDrop: event accepted.");
+ } // end if: drag ok
+ else { // Reject the drag event
+ evt.rejectDrag();
+ log(out, "FileDrop: event rejected.");
+ } // end else: drag not ok
+ } // end dragEnter
+ public void dragOver(java.awt.dnd.DropTargetDragEvent evt) { // This is called continually as long as the mouse is
+ // over the drag target.
+ } // end dragOver
+ public void drop(java.awt.dnd.DropTargetDropEvent evt) {
+ log(out, "FileDrop: drop event.");
+ try { // Get whatever was dropped
+ java.awt.datatransfer.Transferable tr = evt.getTransferable();
+ // Is it a file list?
+ if (tr.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
+ // Say we'll take it.
+ //evt.acceptDrop ( java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE );
+ evt.acceptDrop(java.awt.dnd.DnDConstants.ACTION_COPY);
+ log(out, "FileDrop: file list accepted.");
+ // Get a useful list
+ java.util.List fileList = (java.util.List)
+ tr.getTransferData(DataFlavor.javaFileListFlavor);
+ java.util.Iterator iterator = fileList.iterator();
+ // Convert list to array
+ File[] filesTemp = new File[fileList.size()];
+ fileList.toArray(filesTemp);
+ final File[] files = filesTemp;
+ // Alert listener to drop.
+ if (listener != null)
+ listener.filesDropped(files);
+ // Mark that drop is completed.
+ evt.getDropTargetContext().dropComplete(true);
+ log(out, "FileDrop: drop complete.");
+ } // end if: file list
+ else // this section will check for a reader flavor.
+ {
+ // Thanks, Nathan!
+ // BEGIN 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added.
+ DataFlavor[] flavors = tr.getTransferDataFlavors();
+ boolean handled = false;
+ for (int zz = 0; zz < flavors.length; zz++) {
+ if (flavors[zz].isRepresentationClassReader()) {
+ // Say we'll take it.
+ //evt.acceptDrop ( java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE );
+ evt.acceptDrop(java.awt.dnd.DnDConstants.ACTION_COPY);
+ log(out, "FileDrop: reader accepted.");
+ Reader reader = flavors[zz].getReaderForText(tr);
+ BufferedReader br = new BufferedReader(reader);
+ if (listener != null)
+ listener.filesDropped(createFileArray(br, out));
+ // Mark that drop is completed.
+ evt.getDropTargetContext().dropComplete(true);
+ log(out, "FileDrop: drop complete.");
+ handled = true;
+ break;
+ }
+ }
+ if (!handled) {
+ log(out, "FileDrop: not a file list or reader - abort.");
+ evt.rejectDrop();
+ }
+ // END 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added.
+ } // end else: not a file list
+ } // end try
+ catch (IOException io) {
+ log(out, "FileDrop: IOException - abort:");
+ Global.Log.PrintException(io);
+ evt.rejectDrop();
+ } // end catch IOException
+ catch (java.awt.datatransfer.UnsupportedFlavorException ufe) {
+ log(out, "FileDrop: UnsupportedFlavorException - abort:");
+ Global.Log.PrintException(ufe);
+ evt.rejectDrop();
+ } // end catch: UnsupportedFlavorException
+ finally {
+ // If it's a Swing component, reset its border
+ if (c instanceof javax.swing.JComponent) {
+ javax.swing.JComponent jc = (javax.swing.JComponent) c;
+ jc.setBorder(normalBorder);
+ log(out, "FileDrop: normal border restored.");
+ } // end if: JComponent
+ } // end finally
+ } // end drop
+ public void dragExit(java.awt.dnd.DropTargetEvent evt) {
+ log(out, "FileDrop: dragExit event.");
+ // If it's a Swing component, reset its border
+ if (c instanceof javax.swing.JComponent) {
+ javax.swing.JComponent jc = (javax.swing.JComponent) c;
+ jc.setBorder(normalBorder);
+ log(out, "FileDrop: normal border restored.");
+ } // end if: JComponent
+ } // end dragExit
+ public void dropActionChanged(java.awt.dnd.DropTargetDragEvent evt) {
+ log(out, "FileDrop: dropActionChanged event.");
+ // Is this an acceptable drag event?
+ if (isDragOk(out, evt)) { //evt.acceptDrag( java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE );
+ evt.acceptDrag(java.awt.dnd.DnDConstants.ACTION_COPY);
+ log(out, "FileDrop: event accepted.");
+ } // end if: drag ok
+ else {
+ evt.rejectDrag();
+ log(out, "FileDrop: event rejected.");
+ } // end else: drag not ok
+ } // end dropActionChanged
+ }; // end DropTargetListener
+ // Make the component (and possibly children) drop targets
+ makeDropTarget(out, c, recursive);
+ } // end if: supports dnd
+ else {
+ log(out, "FileDrop: Drag and drop is not supported with this JVM");
+ } // end else: does not support DnD
+ } // end constructor
+ private static boolean supportsDnD() { // Static Boolean
+ if (supportsDnD == null) {
+ boolean support = false;
+ try {
+ Class arbitraryDndClass = Class.forName("java.awt.dnd.DnDConstants");
+ support = true;
+ } // end try
+ catch (Exception e) {
+ support = false;
+ } // end catch
+ supportsDnD = new Boolean(support);
+ } // end if: first time through
+ return supportsDnD.booleanValue();
+ } // end supportsDnD
+ private static File[] createFileArray(BufferedReader bReader, PrintStream out) {
+ try {
+ java.util.List list = new java.util.ArrayList();
+ String line = null;
+ while ((line = bReader.readLine()) != null) {
+ try {
+ // kde seems to append a 0 char to the end of the reader
+ if (ZERO_CHAR_STRING.equals(line)) continue;
+ File file = new File(new java.net.URI(line));
+ list.add(file);
+ } catch (Exception ex) {
+ log(out, "Error with " + line + ": " + ex.getMessage());
+ }
+ }
+ return (File[]) list.toArray(new File[list.size()]);
+ } catch (IOException ex) {
+ log(out, "FileDrop: IOException");
+ }
+ return new File[0];
+ }
+ /**
+ * Outputs message to out if it's not null.
+ */
+ private static void log(PrintStream out, String message) { // Log message if requested
+ // if (out != null)
+ // UI.Print(DebugPrintLevel.DragDrop, message);
+ } // end log
+ /**
+ * Removes the drag-and-drop hooks from the component and optionally
+ * from the all children. You should call this if you add and remove
+ * database.Objects.components after you've set up the drag-and-drop.
+ * This will recursively unregister all database.Objects.components contained within
+ * c if c is a {@link java.awt.Container}.
+ *
+ * @param c The component to unregister as a drop target
+ * @since 1.0
+ */
+ public static boolean remove(java.awt.Component c) {
+ return remove(null, c, true);
+ } // end remove
+ /**
+ * Removes the drag-and-drop hooks from the component and optionally
+ * from the all children. You should call this if you add and remove
+ * database.Objects.components after you've set up the drag-and-drop.
+ *
+ * @param out Optional {@link PrintStream} for logging drag and drop messages
+ * @param c The component to unregister
+ * @param recursive Recursively unregister database.Objects.components within a container
+ * @since 1.0
+ */
+ public static boolean remove(PrintStream out, java.awt.Component c, boolean recursive) { // Make sure we support dnd.
+ if (supportsDnD()) {
+ log(out, "FileDrop: Removing drag-and-drop hooks.");
+ c.setDropTarget(null);
+ if (recursive && (c instanceof java.awt.Container)) {
+ java.awt.Component[] comps = ((java.awt.Container) c).getComponents();
+ for (int i = 0; i < comps.length; i++)
+ remove(out, comps[i], recursive);
+ return true;
+ } // end if: recursive
+ else return false;
+ } // end if: supports DnD
+ else return false;
+ } // end remove
+ // END 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added.
+ private void makeDropTarget(final PrintStream out, final java.awt.Component c, boolean recursive) {
+ // Make drop target
+ final java.awt.dnd.DropTarget dt = new java.awt.dnd.DropTarget();
+ try {
+ dt.addDropTargetListener(dropListener);
+ } // end try
+ catch (java.util.TooManyListenersException e) {
+ Global.Log.PrintException(e);
+ log(out, "FileDrop: Drop will not work due to previous error. Do you have another listener attached?");
+ } // end catch
+ // Listen for hierarchy changes and remove the drop target when the parent gets cleared out.
+ c.addHierarchyListener(new java.awt.event.HierarchyListener() {
+ public void hierarchyChanged(java.awt.event.HierarchyEvent evt) {
+ log(out, "FileDrop: Hierarchy changed.");
+ java.awt.Component parent = c.getParent();
+ if (parent == null) {
+ c.setDropTarget(null);
+ log(out, "FileDrop: Drop target cleared from component.");
+ } // end if: null parent
+ else {
+ new java.awt.dnd.DropTarget(c, dropListener);
+ log(out, "FileDrop: Drop target added to component.");
+ } // end else: parent not null
+ } // end hierarchyChanged
+ }); // end hierarchy listener
+ if (c.getParent() != null)
+ new java.awt.dnd.DropTarget(c, dropListener);
+ if (recursive && (c instanceof java.awt.Container)) {
+ // Get the container
+ java.awt.Container cont = (java.awt.Container) c;
+ // Get it's database.Objects.components
+ java.awt.Component[] comps = cont.getComponents();
+ // Set it's database.Objects.components as listeners also
+ for (int i = 0; i < comps.length; i++)
+ makeDropTarget(out, comps[i], recursive);
+ } // end if: recursively set database.Objects.components as listener
+ } // end dropListener
+ /**
+ * Determine if the dragged data is a file list.
+ */
+ private boolean isDragOk(final PrintStream out, final java.awt.dnd.DropTargetDragEvent evt) {
+ boolean ok = false;
+ // Get data flavors being dragged
+ DataFlavor[] flavors = evt.getCurrentDataFlavors();
+ // See if any of the flavors are a file list
+ int i = 0;
+ while (!ok && i < flavors.length) {
+ // BEGIN 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added.
+ // Is the flavor a file list?
+ final DataFlavor curFlavor = flavors[i];
+ if (curFlavor.equals(DataFlavor.javaFileListFlavor) ||
+ curFlavor.isRepresentationClassReader()) {
+ ok = true;
+ }
+ // END 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added.
+ i++;
+ } // end while: through flavors
+ // If logging is enabled, show data flavors
+ if (out != null) {
+ if (flavors.length == 0)
+ log(out, "FileDrop: no data flavors.");
+ for (i = 0; i < flavors.length; i++)
+ log(out, flavors[i].toString());
+ } // end if: logging enabled
+ return ok;
+ } // end isDragOk
+
+
+
+
+ /* ******** I N N E R I N T E R F A C E L I S T E N E R ******** */
+ /**
+ * Implement this inner interface to listen for when files are dropped. For example
+ * your class declaration may begin like this:
+ *
+ * public class MyClass implements FileDrop.Listener
+ * ...
+ * public void filesDropped( java.io.File[] files )
+ * {
+ * ...
+ * } // end filesDropped
+ * ...
+ *
+ *
+ * @since 1.1
+ */
+ public interface Listener {
+ /**
+ * This method is called when files have been successfully dropped.
+ *
+ * @param files An array of Files that were dropped.
+ * @since 1.0
+ */
+ void filesDropped(File[] files);
+ } // end inner-interface Listener
+
+
+ /* ******** I N N E R C L A S S ******** */
+ /**
+ * This is the event that is passed to the
+ * {@link FileDropListener#filesDropped filesDropped(...)} method in
+ * your {@link FileDropListener} when files are dropped onto
+ * a registered drop target.
+ *
+ *
I'm releasing this code into the Public Domain. Enjoy.
+ *
+ * @author Robert Harder
+ * @author rob@iharder.net
+ * @version 1.2
+ */
+ public static class Event extends java.util.EventObject {
+ private final File[] files;
+ /**
+ * Constructs an {@link Event} with the array
+ * of files that were dropped and the
+ * {@link FileDrop} that initiated the event.
+ *
+ * @param files The array of files that were dropped
+ * @source The event source
+ * @since 1.1
+ */
+ public Event(File[] files, Object source) {
+ super(source);
+ this.files = files;
+ } // end constructor
+ /**
+ * Returns an array of files that were dropped on a
+ * registered drop target.
+ *
+ * @return array of files that were dropped
+ * @since 1.1
+ */
+ public File[] getFiles() {
+ return files;
+ } // end getFiles
+ } // end inner class Event
+
+
+
+ /* ******** I N N E R C L A S S ******** */
+ /**
+ * At last an easy way to encapsulate your custom objects for dragging and dropping
+ * in your Java programs!
+ * When you need to create a {@link java.awt.datatransfer.Transferable} object,
+ * use this class to wrap your object.
+ * For example:
+ *
+ * Or if you need to know when the data was actually dropped, like when you're
+ * moving data out of a list, say, you can use the {@link Fetcher}
+ * inner class to return your object Just in Time.
+ * For example:
+ *
+ * ...
+ * final MyCoolClass myObj = new MyCoolClass();
+ *
+ * TransferableObject.Fetcher fetcher = new TransferableObject.Fetcher()
+ * { public Object getObject(){ return myObj; }
+ * }; // end fetcher
+ *
+ * Transferable xfer = new TransferableObject( fetcher );
+ * ...
+ *
+ *
+ * The {@link DataFlavor} associated with
+ * {@link TransferableObject} has the representation class
+ * net.iharder.dnd.TransferableObject.class and MIME type
+ * application/x-net.iharder.dnd.TransferableObject.
+ * This data flavor is accessible via the static
+ * {@link #DATA_FLAVOR} property.
+ *
+ *
+ *
I'm releasing this code into the Public Domain. Enjoy.
+ *
+ * @author Robert Harder
+ * @author rob@iharder.net
+ * @version 1.2
+ */
+ public static class TransferableObject implements java.awt.datatransfer.Transferable {
+ /**
+ * The MIME type for {@link #DATA_FLAVOR} is
+ * application/x-net.iharder.dnd.TransferableObject.
+ *
+ * @since 1.1
+ */
+ public final static String MIME_TYPE = "application/x-net.iharder.dnd.TransferableObject";
+ /**
+ * The default {@link DataFlavor} for
+ * {@link TransferableObject} has the representation class
+ * net.iharder.dnd.TransferableObject.class
+ * and the MIME type
+ * application/x-net.iharder.dnd.TransferableObject.
+ *
+ * @since 1.1
+ */
+ public final static DataFlavor DATA_FLAVOR =
+ new DataFlavor(TransferableObject.class, MIME_TYPE);
+ private Fetcher fetcher;
+ private Object data;
+ private DataFlavor customFlavor;
+ /**
+ * Creates a new {@link TransferableObject} that wraps data.
+ * Along with the {@link #DATA_FLAVOR} associated with this class,
+ * this creates a custom data flavor with a representation class
+ * determined from data.getClass() and the MIME type
+ * application/x-net.iharder.dnd.TransferableObject.
+ *
+ * @param data The data to transfer
+ * @since 1.1
+ */
+ public TransferableObject(Object data) {
+ this.data = data;
+ this.customFlavor = new DataFlavor(data.getClass(), MIME_TYPE);
+ } // end constructor
+ /**
+ * Creates a new {@link TransferableObject} that will return the
+ * object that is returned by fetcher.
+ * No custom data flavor is set other than the default
+ * {@link #DATA_FLAVOR}.
+ *
+ * @param fetcher The {@link Fetcher} that will return the data object
+ * @see Fetcher
+ * @since 1.1
+ */
+ public TransferableObject(Fetcher fetcher) {
+ this.fetcher = fetcher;
+ } // end constructor
+ /**
+ * Creates a new {@link TransferableObject} that will return the
+ * object that is returned by fetcher.
+ * Along with the {@link #DATA_FLAVOR} associated with this class,
+ * this creates a custom data flavor with a representation class dataClass
+ * and the MIME type
+ * application/x-net.iharder.dnd.TransferableObject.
+ *
+ * @param dataClass The {@link Class} to use in the custom data flavor
+ * @param fetcher The {@link Fetcher} that will return the data object
+ * @see Fetcher
+ * @since 1.1
+ */
+ public TransferableObject(Class dataClass, Fetcher fetcher) {
+ this.fetcher = fetcher;
+ this.customFlavor = new DataFlavor(dataClass, MIME_TYPE);
+ } // end constructor
+ /**
+ * Returns the custom {@link DataFlavor} associated
+ * with the encapsulated object or null if the {@link Fetcher}
+ * constructor was used without passing a {@link Class}.
+ *
+ * @return The custom data flavor for the encapsulated object
+ * @since 1.1
+ */
+ public DataFlavor getCustomDataFlavor() {
+ return customFlavor;
+ } // end getCustomDataFlavor
+
+
+ /* ******** T R A N S F E R A B L E M E T H O D S ******** */
+ /**
+ * Returns a two- or three-element array containing first
+ * the custom data flavor, if one was created in the constructors,
+ * second the default {@link #DATA_FLAVOR} associated with
+ * {@link TransferableObject}, and third the
+ * {@link DataFlavor.stringFlavor}.
+ *
+ * @return An array of supported data flavors
+ * @since 1.1
+ */
+ public DataFlavor[] getTransferDataFlavors() {
+ if (customFlavor != null)
+ return new DataFlavor[]
+ {customFlavor,
+ DATA_FLAVOR,
+ DataFlavor.stringFlavor
+ }; // end flavors array
+ else
+ return new DataFlavor[]
+ {DATA_FLAVOR,
+ DataFlavor.stringFlavor
+ }; // end flavors array
+ } // end getTransferDataFlavors
+ /**
+ * Returns the data encapsulated in this {@link TransferableObject}.
+ * If the {@link Fetcher} constructor was used, then this is when
+ * the {@link Fetcher#getObject getObject()} method will be called.
+ * If the requested data flavor is not supported, then the
+ * {@link Fetcher#getObject getObject()} method will not be called.
+ *
+ * @param flavor The data flavor for the data to return
+ * @return The dropped data
+ * @since 1.1
+ */
+ public Object getTransferData(DataFlavor flavor)
+ throws java.awt.datatransfer.UnsupportedFlavorException, IOException {
+ // Native object
+ if (flavor.equals(DATA_FLAVOR))
+ return fetcher == null ? data : fetcher.getObject();
+ // String
+ if (flavor.equals(DataFlavor.stringFlavor))
+ return fetcher == null ? data.toString() : fetcher.getObject().toString();
+ // We can't do anything else
+ throw new java.awt.datatransfer.UnsupportedFlavorException(flavor);
+ } // end getTransferData
+ /**
+ * Returns true if flavor is one of the supported
+ * flavors. Flavors are supported using the equals(...) method.
+ *
+ * @param flavor The data flavor to check
+ * @return Whether or not the flavor is supported
+ * @since 1.1
+ */
+ public boolean isDataFlavorSupported(DataFlavor flavor) {
+ // Native object
+ if (flavor.equals(DATA_FLAVOR))
+ return true;
+ // String
+ return flavor.equals(DataFlavor.stringFlavor);
+ // We can't do anything else
+ } // end isDataFlavorSupported
+
+
+ /* ******** I N N E R I N T E R F A C E F E T C H E R ******** */
+ /**
+ * Instead of passing your data directly to the {@link TransferableObject}
+ * constructor, you may want to know exactly when your data was received
+ * in case you need to remove it from its source (or do anyting else to it).
+ * When the {@link #getTransferData getTransferData(...)} method is called
+ * on the {@link TransferableObject}, the {@link Fetcher}'s
+ * {@link #getObject getObject()} method will be called.
+ *
+ * @author Robert Harder
+ * @version 1.1
+ * @copyright 2001
+ * @since 1.1
+ */
+ public interface Fetcher {
+ /**
+ * Return the object being encapsulated in the
+ * {@link TransferableObject}.
+ *
+ * @return The dropped object
+ * @since 1.1
+ */
+ Object getObject();
+ } // end inner interface Fetcher
+ } // end class TransferableObject
+} // end class FileDrop
diff --git a/src/Common/UI/Editor/BaseEditor.java b/src/Common/UI/Editor/BaseEditor.java
new file mode 100644
index 00000000..83c03109
--- /dev/null
+++ b/src/Common/UI/Editor/BaseEditor.java
@@ -0,0 +1,154 @@
+package Common.UI.Editor;
+import Common.Current;
+import Common.Global;
+import Common.UI.Menus.StyledPopupMenu;
+import Common.UI.Menus.TextEditorMenu;
+import Common.UI.Themes.ThemeElement;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.DialogFields;
+import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
+
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import java.awt.*;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.net.URI;
+public class BaseEditor extends RSyntaxTextArea implements ThemeElement, DialogFields {
+ private final StyledPopupMenu menu;
+ // protected int changesCount = 0;
+ // protected int insertsCount = 0;
+ // protected int removesCount = 0;
+ // protected boolean ctrlZ = false;
+ protected String startText = "";
+ private boolean search_enabled = true;
+ public BaseEditor() {
+ setTabSize(6);
+ setPaintTabLines(true);
+ setCodeFoldingEnabled(true);
+ addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.isControlDown()) {
+ switch (e.getKeyCode()) {
+ case KeyEvent.VK_ADD: //num lock +
+ case KeyEvent.VK_EQUALS: //+
+ FontUp();
+ break;
+ case KeyEvent.VK_SUBTRACT: //num lock -
+ case KeyEvent.VK_MINUS: //-
+ FontDown();
+ break;
+ case KeyEvent.VK_S:
+ saveText();
+ break;
+ //todo переход в нужную строку по ctrl+g?
+ case KeyEvent.VK_Z:
+ if (getText().equals(startText)) {
+ UI.Info("Начальная версия текста достигнута.");
+ e.consume();
+ }
+ break;
+ }
+ }
+ }
+ });
+ setPopupMenu(menu = createMenu());
+ applyTheme();
+ //-
+ this.setHyperlinksEnabled(true);
+ HyperlinkListener listener = new HyperlinkListener() {
+ @Override
+ public void hyperlinkUpdate(HyperlinkEvent event) {
+ if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
+ try {
+ Desktop.getDesktop().browse(new URI(event.getURL().toString()));
+ } catch (Exception ioe) {
+ System.err.println("Error loading url from link: " + ioe);
+ }
+ }
+ }
+ };
+ this.addHyperlinkListener(listener);
+ }
+ @Override
+ public void setText(String t) {
+ super.setText(t);
+ startText = t;
+ }
+ public void setSearchEnabled(boolean f_in) {
+ search_enabled = f_in;
+ }
+ protected StyledPopupMenu createMenu() {
+ return new TextEditorMenu(this);
+ }
+ private void changeFont(int size) {
+ if ((size > 1) && (size < 48)) {
+ setFont(getFont().deriveFont((float) size));
+ saveFont();
+ }
+ }
+ protected void saveFont() {
+ }
+ protected void saveText() {
+ }
+ public void ClearSelection() {
+ setSelectionStart(0);
+ setSelectionEnd(0);
+ }
+ public void gotoLine(int LineNum) {
+ gotoLine_(LineNum - 1);
+ }
+ //без вычитания.
+ public void gotoLine_(int LineNum) {
+ //requestFocus();
+ try {
+ //особеннсть контрола.
+ //нельзя полностью скинуть текущую позицию. пэтому если надо
+ //освежить 0 строку, передергиваем до последней.
+ if (LineNum == 0)
+ setCaretPosition(getLineStartOffset(getLineCount() - 1));
+ ClearSelection();
+ if (LineNum > 0) {
+ setCaretPosition(getLineStartOffset(LineNum));
+ setSelectionStart(getLineStartOffset(LineNum));
+ setSelectionEnd(getLineStartOffset(LineNum));
+ }
+ } catch (Exception ex) {
+ Global.Log.Print("Не удалось перейти на строку " + LineNum);
+ Global.Log.PrintException(ex);
+ }
+ }
+ //------------------------------------------
+ public void FontUp() {
+ changeFont(getFont().getSize() + 1);
+ }
+ public void FontDown() {
+ changeFont(getFont().getSize() - 1);
+ }
+ @Override
+ public void applyTheme() {
+ float font_size = (float) getFont().getSize();
+ Current.getTheme().getEditorTheme().apply(this);
+ setFont(getFont().deriveFont(font_size));
+ menu.applyTheme();
+ //меню связано с редактором. поэтому тема меняется только вместе с ним.
+ }
+ @Override
+ public Component getContent() {
+ return this;
+ }
+ public void ShowBegin() {
+ setCaretPosition(0);
+ }
+ public boolean lineIsVisible(int lineNum) {
+ boolean res = false;
+ Rectangle rectangle = this.getVisibleRect();
+ try {
+ res = rectangle.contains(rectangle.x, yForLine(lineNum));
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ return res;
+ }
+}
diff --git a/src/Common/UI/Editor/CaretInfo.java b/src/Common/UI/Editor/CaretInfo.java
new file mode 100644
index 00000000..4c66e1bf
--- /dev/null
+++ b/src/Common/UI/Editor/CaretInfo.java
@@ -0,0 +1,30 @@
+package Common.UI.Editor;
+import Common.Global;
+import ProjectData.Files.UI.Editor.SPFEditor;
+import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
+public class CaretInfo {
+ public String current_line = ""; //полный текст текущей строки
+ public String before = ""; //кусок строки перед кареткой
+ public String after = ""; //кусок строки после каретки
+ public String prefix_word = ""; //слово перед кареткой
+ public String suffix_word = ""; //слово после каретки
+ public CaretInfo(RSyntaxTextArea Body) {
+ try {
+ int start = Body.getLineStartOffset(Body.getCaretLineNumber());
+ int before_length = Body.getCaretOffsetFromLineStart();
+ int end = Body.getLineEndOffset(Body.getCaretLineNumber());
+ int after_length = end - start - before_length;
+ before = Body.getText(start, before_length).toUpperCase();
+ after = Body.getText(start + before_length, after_length).toUpperCase();
+ //нужно чтобы перевод строки не влезал
+ after = after.replace("\n", "");
+ current_line = (before + after);
+ prefix_word = SPFEditor.getLastWord(before, ' ', ',', ':', '.', '(', ')');
+ suffix_word = SPFEditor.getFirstWord(after, ' ', ',', ':', '.', '(', ')');
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ }
+ public CaretInfo() {
+ }
+}
diff --git a/src/Common/UI/Editor/Viewer.java b/src/Common/UI/Editor/Viewer.java
new file mode 100644
index 00000000..c16ee08b
--- /dev/null
+++ b/src/Common/UI/Editor/Viewer.java
@@ -0,0 +1,8 @@
+package Common.UI.Editor;
+public class Viewer extends BaseEditor {
+ public Viewer() {
+ setLineWrap(true);
+ setWrapStyleWord(true);
+ setEditable(false);
+ }
+}
diff --git a/src/Common/UI/EmptyDialogFields.form b/src/Common/UI/EmptyDialogFields.form
new file mode 100644
index 00000000..5695f05c
--- /dev/null
+++ b/src/Common/UI/EmptyDialogFields.form
@@ -0,0 +1,11 @@
+
+
diff --git a/src/Common/UI/EmptyDialogFields.java b/src/Common/UI/EmptyDialogFields.java
new file mode 100644
index 00000000..1da1c1b7
--- /dev/null
+++ b/src/Common/UI/EmptyDialogFields.java
@@ -0,0 +1,12 @@
+package Common.UI;
+import Common.UI.Windows.Dialog.DialogFields;
+
+import javax.swing.*;
+import java.awt.*;
+public class EmptyDialogFields implements DialogFields {
+ private JPanel content;
+ @Override
+ public Component getContent() {
+ return content;
+ }
+}
diff --git a/src/Common/UI/Label/ShortLabel.java b/src/Common/UI/Label/ShortLabel.java
new file mode 100644
index 00000000..f0f8b3f1
--- /dev/null
+++ b/src/Common/UI/Label/ShortLabel.java
@@ -0,0 +1,15 @@
+package Common.UI.Label;
+import javax.swing.*;
+public class ShortLabel extends JLabel {
+ int max = 0;
+ public ShortLabel(int max_in) {
+ max = max_in;
+ }
+ @Override
+ public void setText(String text_in) {
+ if ((max > 0) && (text_in.length() > max)) {
+ super.setText(text_in.substring(0, max - 1) + "...");
+ } else super.setText(text_in);
+ setToolTipText(text_in);
+ }
+}
diff --git a/src/Common/UI/List/HyperlinksStyledList.java b/src/Common/UI/List/HyperlinksStyledList.java
new file mode 100644
index 00000000..903f3880
--- /dev/null
+++ b/src/Common/UI/List/HyperlinksStyledList.java
@@ -0,0 +1,10 @@
+package Common.UI.List;
+import Common.Current;
+import Common.UI.Themes.VisualiserFonts;
+public class HyperlinksStyledList extends StyledList {
+ @Override
+ public void applyTheme() {
+ super.applyTheme();
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Hyperlink));
+ }
+}
diff --git a/src/Common/UI/List/StyledList.java b/src/Common/UI/List/StyledList.java
new file mode 100644
index 00000000..c6abc6cb
--- /dev/null
+++ b/src/Common/UI/List/StyledList.java
@@ -0,0 +1,17 @@
+package Common.UI.List;
+import Common.Current;
+import Common.UI.Themes.ThemeElement;
+import Common.UI.Themes.VisualiserFonts;
+
+import javax.swing.*;
+public class StyledList extends JList implements ThemeElement {
+ public StyledList() {
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreePlain));
+ applyTheme();
+ }
+ @Override
+ public void applyTheme() {
+ setBackground(Current.getTheme().table_background);
+ setForeground(Current.getTheme().foreground);
+ }
+}
diff --git a/src/Common/UI/Menus/AttachementsMenu.java b/src/Common/UI/Menus/AttachementsMenu.java
new file mode 100644
index 00000000..1957206a
--- /dev/null
+++ b/src/Common/UI/Menus/AttachementsMenu.java
@@ -0,0 +1,30 @@
+package Common.UI.Menus;
+import Common.Current;
+import Common.Global;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+public class AttachementsMenu extends StyledPopupMenu {
+ JMenuItem mscreenshot;
+ JMenuItem mExplorer;
+ public AttachementsMenu() {
+ add(mscreenshot = Pass_2021.passes.get(PassCode_2021.MakeScreenShot).createMenuItem());
+ addSeparator();
+ mExplorer = new VisualiserMenuItem("Открыть вложения в проводнике...", "/icons/Explorer.png");
+ mExplorer.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ try {
+ Desktop.getDesktop().open(Current.getProject().getAttachmentsDirectory());
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ }
+ });
+ add(mExplorer);
+ }
+}
diff --git a/src/Common/UI/Menus/FileStyleMenu.java b/src/Common/UI/Menus/FileStyleMenu.java
new file mode 100644
index 00000000..d7b73c08
--- /dev/null
+++ b/src/Common/UI/Menus/FileStyleMenu.java
@@ -0,0 +1,24 @@
+package Common.UI.Menus;
+import Common.Current;
+import ProjectData.Files.LanguageStyle;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+public class FileStyleMenu extends StyledPopupMenu {
+ public FileStyleMenu() {
+ for (LanguageStyle s : LanguageStyle.values()) {
+ JMenuItem m = new VisualiserMenuItem(s.getDescription());
+ m.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (Current.getFile().UpdateStyle(s)) {
+ Current.getSapfor().ResetAllAnalyses();
+ Current.getFile().form.ShowStyle();
+ }
+ }
+ });
+ add(m);
+ }
+ }
+}
diff --git a/src/Common/UI/Menus/GraphMenu.java b/src/Common/UI/Menus/GraphMenu.java
new file mode 100644
index 00000000..055c12f4
--- /dev/null
+++ b/src/Common/UI/Menus/GraphMenu.java
@@ -0,0 +1,35 @@
+package Common.UI.Menus;
+import Common.UI.Trees.StyledTree;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
+public class GraphMenu extends StyledPopupMenu {
+ public T tree;
+ public GraphMenu(T tree_in, String branches_name) {
+ tree = tree_in;
+ JMenuItem m = null;
+ m = new VisualiserMenuItem("Свернуть все " + branches_name);
+ m.addActionListener(new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ tree.CollapseAll();
+ }
+ });
+ add(m);
+ m = new VisualiserMenuItem("Развернуть все " + branches_name);
+ m.addActionListener(new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ tree.ExpandAll();
+ }
+ });
+ add(m);
+ }
+ public GraphMenu(T tree) {
+ this(tree, tree.getBranchesName());
+ }
+ public void Show(MouseEvent mouseEvent) {
+ show(tree, mouseEvent.getX(), mouseEvent.getY());
+ }
+}
diff --git a/src/Common/UI/Menus/MainEditorMenu.java b/src/Common/UI/Menus/MainEditorMenu.java
new file mode 100644
index 00000000..0c61f235
--- /dev/null
+++ b/src/Common/UI/Menus/MainEditorMenu.java
@@ -0,0 +1,342 @@
+package Common.UI.Menus;
+import Common.Current;
+import Common.Global;
+import Common.UI.Editor.CaretInfo;
+import Common.Utils.Utils;
+import ProjectData.Files.DBProjectFile;
+import ProjectData.Files.UI.Editor.SPFEditor;
+import ProjectData.SapforData.Functions.FuncCall;
+import ProjectData.SapforData.Functions.FuncInfo;
+import ProjectData.SapforData.Functions.FunctionType;
+import ProjectData.SapforData.Loops.Loop;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+public class MainEditorMenu extends TextEditorMenu {
+ FuncCall call = null;
+ FuncInfo decl = null;
+ Loop loop = null;
+ DBProjectFile header = null;
+ //------------------
+ JMenuItem m_comment;
+ JMenuItem m_uncomment;
+ JMenuItem m_inline;
+ JMenuItem m_add_lines_to_region;
+ JMenuItem m_remove_lines_from_region;
+ JMenuItem m_loop_union;
+ JMenuItem m_undo;
+ JMenuItem m_gotoFunction;
+ JMenuItem m_gotoHeader;
+ //-----------------
+ public MainEditorMenu(RSyntaxTextArea editor_in) {
+ super(editor_in);
+ addSeparator();
+ m_gotoHeader = new VisualiserMenuItem("Перейти к заголовочному файлу", "/icons/Transformations/SPF_InsertIncludesPass.png");
+ m_gotoHeader.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Pass_2021.passes.get(PassCode_2021.OpenCurrentFile).Do(header);
+ }
+ });
+ add(m_gotoHeader);
+ addSeparator();
+ m_gotoFunction = new VisualiserMenuItem("Перейти к объявлению процедуры", "/icons/versions/currentVersion.png");
+ m_gotoFunction.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ decl.Show(true);
+ }
+ });
+ add(m_gotoFunction);
+ m_inline = new VisualiserMenuItem("Подставить вызов процедуры", "/icons/Transformations/SPF_InlineProcedures.png");
+ m_inline.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Pass_2021.passes.get(PassCode_2021.SPF_InlineProcedure).Do(call);
+ }
+ });
+ add(m_inline);
+ addSeparator();
+ m_loop_union = new VisualiserMenuItem("Объединить цикл со следующим", "/icons/Transformations/SPF_LoopUnion.png");
+ m_loop_union.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Pass_2021.passes.get(PassCode_2021.SPF_LoopUnionCurrent).Do();
+ }
+ });
+ add(m_loop_union);
+ m_add_lines_to_region = new VisualiserMenuItem("Добавить строки в область", "/icons/Menu/AddLines.png");
+ m_add_lines_to_region.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ try {
+ Pass_2021.passes.get(PassCode_2021.SPF_ChangeSpfIntervals).Do(
+ ((RSyntaxTextArea) editor).getLineOfOffset(editor.getSelectionStart()) + 1,
+ ((RSyntaxTextArea) editor).getLineOfOffset(editor.getSelectionEnd()) + 1,
+ 1
+ );
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ }
+ });
+ add(m_add_lines_to_region);
+ m_remove_lines_from_region = new VisualiserMenuItem("Удалить строки из области", "/icons/Menu/RemoveLines.png");
+ m_remove_lines_from_region.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ try {
+ Pass_2021.passes.get(PassCode_2021.SPF_ChangeSpfIntervals).Do(
+ ((RSyntaxTextArea) editor).getLineOfOffset(editor.getSelectionStart()) + 1,
+ ((RSyntaxTextArea) editor).getLineOfOffset(editor.getSelectionEnd()) + 1,
+ 0
+ );
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ }
+ });
+ add(m_remove_lines_from_region);
+ addSeparator();
+ m_comment = new VisualiserMenuItem("Закомментировать блок", "/icons/Editor/Comment.png");
+ m_comment.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String new_ = "";
+ String[] data = selectedText.split("\n");
+ int i = 0;
+ switch (Current.getFile().languageName) {
+ case fortran:
+ for (String line : data) {
+ if (!line.startsWith("!")) {
+ new_ += "!" + line;
+ } else new_ += line;
+ if (i < data.length - 1) new_ += "\n";
+ ++i;
+ }
+ break;
+ case c:
+ case cpp:
+ for (String line : data) {
+ if (!line.startsWith("//")) {
+ new_ += "//" + line;
+ } else new_ += line;
+ if (i < data.length - 1) new_ += "\n";
+ ++i;
+ }
+ break;
+ default:
+ new_ = selectedText;
+ break;
+ }
+ editor.replaceSelection(new_);
+ }
+ });
+ add(m_comment);
+ m_uncomment = new VisualiserMenuItem("Раскомментировать блок", "/icons/Editor/Uncomment.png");
+ m_uncomment.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String new_ = "";
+ String[] data = selectedText.split("\n");
+ int i = 0;
+ switch (Current.getFile().languageName) {
+ case fortran:
+ for (String line : data) {
+ if (line.startsWith("!")) {
+ new_ += line.substring(1);
+ } else new_ += line;
+ if (i < data.length - 1) new_ += "\n";
+ ++i;
+ }
+ break;
+ case c:
+ case cpp:
+ for (String line : data) {
+ if (line.startsWith("//")) {
+ new_ += line.substring(2);
+ } else new_ += line;
+ if (i < data.length - 1) new_ += "\n";
+ ++i;
+ }
+ break;
+ default:
+ new_ = selectedText;
+ break;
+ }
+ //todo. возможно, изменить концепцию на выделенные строки?
+ editor.replaceSelection(new_);
+ }
+ });
+ add(m_uncomment);
+ addSeparator();
+ m_undo = new VisualiserMenuItem("Отменить последнюю модификацию", "/icons/Menu/Undo.png");
+ m_undo.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ try {
+ Current.getSapfor().UpdateProjectFiles(false);
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ }
+ });
+ add(m_undo);
+ }
+ private void checkFunction() {
+ call = null;
+ decl = null;
+ //--
+ m_inline.setEnabled(false);
+ m_gotoFunction.setEnabled(false);
+ //--
+ m_inline.setToolTipText("");
+ m_gotoFunction.setToolTipText("");
+ //--
+ if (selectedText == null) {
+ m_inline.setText("Невозможно подставить вызов процедуры. Не выделено имя процедуры.");
+ m_gotoFunction.setText("Невозможно перейти к объявлению процедуры. Не выделено имя процедуры");
+ return;
+ }
+ if (selectedText.contains("\n")) {
+ m_inline.setText("Невозможно подставить вызов процедуры. Выделено несколько строк");
+ m_gotoFunction.setText("Невозможно перейти к объявлению процедуры. Выделено несколько строк.");
+ return;
+ }
+ if (!Utils.isFunctionName(selectedText)) {
+ String tip = "Имя процедуры может содержать только английские буквы, цифры и подчеркивания, и не может начинаться с цифры.";
+ //-
+ m_inline.setText("Невозможно подставить вызов процедуры " + Utils.Brackets(selectedText) +
+ " . Выделено некорректное имя.");
+ m_gotoFunction.setText("Невозможно перейти к объявлению процедуры " + Utils.Brackets(selectedText) +
+ " . Выделено некорректное имя.");
+ //-
+ m_inline.setToolTipText(tip);
+ m_gotoFunction.setToolTipText(tip);
+ return;
+ }
+ if (!Pass_2021.passes.get(PassCode_2021.SPF_GetGraphFunctions).isDone()) {
+ m_inline.setText("Невозможно подставить вызов процедуры " + Utils.Brackets(selectedText) +
+ " . Выполните проход \"Граф процедур \".");
+ m_gotoFunction.setText("Невозможно перейти к объявлению процедуры " + Utils.Brackets(selectedText) +
+ " . Выполните проход \"Граф процедур \"");
+ return;
+ }
+ if (Current.getSapfor().isIntrinsic(selectedText)) {
+ m_inline.setText("Невозможно подставить вызов процедуры " + Utils.Brackets(selectedText) +
+ " . Процедура является стандартной.");
+ m_gotoFunction.setText("Невозможно перейти к объявлению процедуры " + Utils.Brackets(selectedText) +
+ " . Процедура является стандартной.");
+ return;
+ }
+ call = Current.getFile().find_func_call(selectedText);
+ if (call == null) {
+ m_inline.setText("Невозможно подставить вызов процедуры " + Utils.Brackets(selectedText) +
+ " . Вызов не найден в текущей строке.");
+ m_gotoFunction.setText("Невозможно перейти к объявлению процедуры " + Utils.Brackets(selectedText) +
+ " . Объявление процедуры уже находится в текущей строке.");
+ return;
+ }
+ decl = Current.getProject().allFunctions.get(call.funcName);
+ if (decl.type.equals(FunctionType.NotFound)) {
+ m_inline.setText("Невозможно подставить вызов процедуры " + Utils.Brackets(selectedText) +
+ " . Объявление процедуры не найдено в проекте.");
+ m_gotoFunction.setText("Невозможно перейти к объявлению процедуры " + Utils.Brackets(selectedText) +
+ " . Объявление процедуры не найдено в проекте.");
+ return;
+ }
+ //---
+ m_inline.setEnabled(true);
+ m_gotoFunction.setEnabled(true);
+ m_inline.setText("Подставить вызов процедуры " + Utils.Brackets(selectedText));
+ m_gotoFunction.setText("Перейти к объявлению процедуры " + Utils.Brackets(selectedText));
+ //--
+ }
+ private void checkHeader() {
+ header = null;
+ m_gotoHeader.setEnabled(false);
+ //--
+ CaretInfo caretInfo = ((SPFEditor) editor).getCaretInfo();
+ if (caretInfo != null) {
+ String header_ = Utils.extractHeaderName(caretInfo.current_line);
+ if (header_ == null) {
+ m_gotoHeader.setText("Невозможно перейти к заголовочному файлу. В текущей строке не найдено включений.");
+ return;
+ }
+ if (!Pass_2021.passes.get(PassCode_2021.SPF_GetIncludeDependencies).isDone()) {
+ m_gotoHeader.setText("Невозможно перейти к заголовочному файлу. Выполните проход \"Поиск зависимостей по включению\"");
+ return;
+ }
+ if (!Current.getFile().relativeHeaders.containsKey(header_)) {
+ m_gotoHeader.setText("Невозможно перейти к заголовочному файлу " + Utils.Brackets(header_) + " . Файл не найден среди включений текущего файла.");
+ return;
+ }
+ header = Current.getFile().relativeHeaders.get(header_);
+ m_gotoHeader.setText("Переход к заголовочному файлу " + Utils.Brackets(header_));
+ m_gotoHeader.setEnabled(true);
+ }
+ }
+ private void checkLoop() {
+ loop = null;
+ m_loop_union.setEnabled(false);
+ if (!Pass_2021.passes.get(PassCode_2021.SPF_GetGraphLoops).isDone()) {
+ m_loop_union.setText("Невозможно объединить цикл в текущей строке со следующим. " +
+ "Выполните проход \"Граф циклов\"");
+ return;
+ }
+ loop = Current.getFile().find_current_loop();
+ if (loop == null) {
+ m_loop_union.setText("Невозможно объединить цикл в текущей строке со следующим. Не найдено циклов в текущей строке.");
+ return;
+ }
+ m_loop_union.setEnabled(true);
+ m_loop_union.setText("Объединить цикл в строке " + Utils.Brackets(loop.line) + " со следующим");
+ }
+ @Override
+ public void CheckElementsVisibility() {
+ super.CheckElementsVisibility();
+ m_strike.setVisible(false);
+ m_unstrike.setVisible(false);
+ checkFunction();
+ checkHeader();
+ checkLoop();
+ if (selectedText == null) {
+ m_comment.setEnabled(false);
+ m_uncomment.setEnabled(false);
+ m_add_lines_to_region.setEnabled(false);
+ m_remove_lines_from_region.setEnabled(false);
+ m_comment.setText("Невозможно закомментировать блок. Не выделено ни одной строки.");
+ m_uncomment.setText("Невозможно раскомментировать блок. Не выделено ни одной строки.");
+ m_add_lines_to_region.setText("Невозможно добавить строки в область. Не выделено ни одной строки.");
+ m_remove_lines_from_region.setText("Невозможно удалить строки из области. Не выделено ни одной строки.");
+ } else {
+ m_comment.setEnabled(true);
+ m_uncomment.setEnabled(true);
+ m_add_lines_to_region.setEnabled(true);
+ m_remove_lines_from_region.setEnabled(true);
+ m_comment.setText("Закомментировать блок");
+ m_uncomment.setText("Раскомментировать блок");
+ m_add_lines_to_region.setText("Добавить строки в область");
+ m_remove_lines_from_region.setText("Удалить строки из области");
+ }
+ if (Current.getSapfor().OldFiles.isEmpty()) {
+ m_undo.setEnabled(false);
+ m_undo.setText("Невозможно отменить последнюю модификацию. Модификации отсутствуют.");
+ } else {
+ m_undo.setEnabled(true);
+ m_undo.setText("Отменить последнюю модификацию.");
+ }
+ }
+}
diff --git a/src/Common/UI/Menus/PassesSubMenu.java b/src/Common/UI/Menus/PassesSubMenu.java
new file mode 100644
index 00000000..abd1e915
--- /dev/null
+++ b/src/Common/UI/Menus/PassesSubMenu.java
@@ -0,0 +1,18 @@
+package Common.UI.Menus;
+import Common.Current;
+import Common.UI.Themes.VisualiserFonts;
+import Common.Utils.Utils;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+
+import javax.swing.*;
+public class PassesSubMenu extends JMenu {
+ public PassesSubMenu(String title, String icon, PassCode_2021... passes) {
+ super(title);
+ setIcon(Utils.getIcon(icon));
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Menu));
+ for (PassCode_2021 code : passes) {
+ add(Pass_2021.passes.get(code).createMenuItem());
+ }
+ }
+}
diff --git a/src/Common/UI/Menus/ProjectFilesMenu.java b/src/Common/UI/Menus/ProjectFilesMenu.java
new file mode 100644
index 00000000..a102e60c
--- /dev/null
+++ b/src/Common/UI/Menus/ProjectFilesMenu.java
@@ -0,0 +1,135 @@
+package Common.UI.Menus;
+import Common.Current;
+import Common.Global;
+import Common.UI.Menus_2023.LanguagesSubmenu;
+import Common.UI.Menus_2023.StableMenuItem;
+import Common.UI.Menus_2023.StylesSubmenu;
+import Common.UI.Menus_2023.TypesSubmenu;
+import Common.UI.Trees.StyledTree;
+import Common.UI.UI;
+import Common.Utils.Utils;
+import ProjectData.Files.FileType;
+import ProjectData.Files.LanguageStyle;
+import ProjectData.LanguageName;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+public class ProjectFilesMenu extends GraphMenu {
+ VisualiserMenuItem m_select_all;
+ VisualiserMenuItem m_unselect_all;
+ VisualiserMenuItem m_multiselection;
+ JMenu mLanguage;
+ JMenu mStyle;
+ JMenu mType;
+ public ProjectFilesMenu(StyledTree tree) {
+ super(tree, "подпапки");
+ addSeparator();
+ JMenuItem m = new VisualiserMenuItem("Открыть в проводнике...", "/icons/Explorer.png");
+ m.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ try {
+ Desktop.getDesktop().open(Current.getProject().Home);
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ }
+ });
+ add(m);
+ addSeparator();
+ add(new PassesSubMenu("Добавить", "/icons/RedAdd.png",
+ PassCode_2021.AddFile,
+ PassCode_2021.CreateEmptyDirectory,
+ PassCode_2021.ImportFiles));
+ addSeparator();
+ add(new PassesSubMenu("Переименовать", "/icons/Menu/Rename.png",
+ PassCode_2021.RenameFile,
+ PassCode_2021.RenameDirectory));
+ add(new VisualiserMenuItem("Удалить текущий проект", "/icons/Delete.png") {
+ {
+ addActionListener(e -> {
+ if (Current.HasProject()) {
+ UI.getVersionsWindow().getVersionsForm().getTree().SelectNode(Current.getProject().node);
+ Pass_2021.passes.get(PassCode_2021.DeleteVersion).Do();
+ }
+ });
+ }
+ });
+ addSeparator();
+ m_multiselection = new VisualiserMenuItem("Массовый режим работы с файлами");
+ m_multiselection.setIcon(Utils.getIcon(Global.files_multiselection ? "/icons/Pick.png" : "/icons/NotPick.png"));
+ m_multiselection.addActionListener(e -> {
+ Global.files_multiselection = !Global.files_multiselection;
+ m_multiselection.setIcon(Utils.getIcon(Global.files_multiselection ? "/icons/Pick.png" : "/icons/NotPick.png"));
+ Current.getProject().SelectAllFiles(false);
+ UI.getMainWindow().getProjectWindow().RefreshProjectFiles();
+
+ //-
+ });
+ add(m_multiselection);
+ addSeparator();
+ //-
+ m_select_all = new StableMenuItem("Выбрать всё", "/icons/SelectAll.png");
+ m_select_all.addActionListener(e -> {
+ Current.getProject().SelectAllFiles(true);
+ tree.updateUI();
+ });
+ add(m_select_all);
+ m_unselect_all = new StableMenuItem("Отменить всё", "/icons/UnselectAll.png");
+ m_unselect_all.addActionListener(e -> {
+ Current.getProject().SelectAllFiles(false);
+ tree.updateUI();
+ });
+ add(m_unselect_all);
+ //--------------------------------------------------
+ add(mLanguage = new LanguagesSubmenu(PassCode_2021.SetSelectedFilesLanguage.getDescription()) {
+ @Override
+ public void action(LanguageName languageName) {
+ Pass_2021.passes.get(PassCode_2021.SetSelectedFilesLanguage).Do(languageName);
+ }
+ });
+ add(mStyle = new StylesSubmenu(PassCode_2021.SetSelectedFilesStyle.getDescription()) {
+ @Override
+ public void action(LanguageStyle languageStyle) {
+ Pass_2021.passes.get(PassCode_2021.SetSelectedFilesStyle).Do(languageStyle);
+ }
+ });
+ add(mType = new TypesSubmenu(PassCode_2021.SetSelectedFilesType.getDescription()) {
+ @Override
+ public void action(FileType fileType) {
+ Pass_2021.passes.get(PassCode_2021.SetSelectedFilesType).Do(fileType);
+ }
+ });
+ //--------------------------------------------------
+ add(Pass_2021.passes.get(PassCode_2021.ExcludeSelectedFiles).createMenuItem());
+ add(Pass_2021.passes.get(PassCode_2021.IncludeSelectedFiles).createMenuItem());
+ add(Pass_2021.passes.get(PassCode_2021.ExcludeFile).createMenuItem());
+ add(Pass_2021.passes.get(PassCode_2021.IncludeFile).createMenuItem());
+ add(Pass_2021.passes.get(PassCode_2021.DeleteFile).createMenuItem());
+ add(Pass_2021.passes.get(PassCode_2021.DeleteDirectory).createMenuItem());
+ add(Pass_2021.passes.get(PassCode_2021.DeleteSelectedFiles).createMenuItem());
+ }
+ @Override
+ public void CheckElementsVisibility() {
+ m_select_all.setVisible(Global.files_multiselection);
+ m_unselect_all.setVisible(Global.files_multiselection);
+ mLanguage.setVisible(Global.files_multiselection);
+ mStyle.setVisible(Global.files_multiselection);
+ mType.setVisible(Global.files_multiselection);
+ //-
+ Pass_2021.passes.get(PassCode_2021.ExcludeFile).setControlsVisible(!Global.files_multiselection);
+ Pass_2021.passes.get(PassCode_2021.IncludeFile).setControlsVisible(!Global.files_multiselection);
+ //-
+ Pass_2021.passes.get(PassCode_2021.DeleteFile).setControlsVisible(!Global.files_multiselection);
+ Pass_2021.passes.get(PassCode_2021.DeleteDirectory).setControlsVisible(!Global.files_multiselection);
+ //--
+ Pass_2021.passes.get(PassCode_2021.ExcludeSelectedFiles).setControlsVisible(Global.files_multiselection);
+ Pass_2021.passes.get(PassCode_2021.IncludeSelectedFiles).setControlsVisible(Global.files_multiselection);
+ Pass_2021.passes.get(PassCode_2021.DeleteSelectedFiles).setControlsVisible(Global.files_multiselection);
+ }
+}
+
diff --git a/src/Common/UI/Menus/PropertiesSubmenu.java b/src/Common/UI/Menus/PropertiesSubmenu.java
new file mode 100644
index 00000000..9e5a0e08
--- /dev/null
+++ b/src/Common/UI/Menus/PropertiesSubmenu.java
@@ -0,0 +1,18 @@
+package Common.UI.Menus;
+import Common.Current;
+import Common.Global;
+import Common.UI.Themes.VisualiserFonts;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+public class PropertiesSubmenu extends JMenu {
+ public PropertiesSubmenu(String title, String icon, String... settings) {
+ super(title);
+ if (icon != null)
+ setIcon(Utils.getIcon(icon));
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Menu));
+ for (String name : settings) {
+ Global.properties.addFlagMenuItem(this, name);
+ }
+ }
+}
diff --git a/src/Common/UI/Menus/SelectionTreeMenu.java b/src/Common/UI/Menus/SelectionTreeMenu.java
new file mode 100644
index 00000000..3726d65e
--- /dev/null
+++ b/src/Common/UI/Menus/SelectionTreeMenu.java
@@ -0,0 +1,86 @@
+package Common.UI.Menus;
+import Common.Current;
+import Common.UI.Menus_2023.StableMenuItem;
+import Common.UI.Selectable;
+import Common.UI.Trees.DataTree;
+import Common.UI.Trees.SelectableTree;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+public abstract class SelectionTreeMenu extends GraphMenu {
+ VisualiserMenuItem m_select_for_current;
+ VisualiserMenuItem m_unselect_for_current;
+ VisualiserMenuItem m_select_all;
+ VisualiserMenuItem m_unselect_all;
+ public SelectionTreeMenu(SelectableTree tree_in) {
+ super(tree_in, "");
+ addSeparator();
+ //-
+ m_select_all = new StableMenuItem("Выбрать всё", "/icons/SelectAll.png");
+ m_select_all.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ SelectAll(true);
+ tree.updateUI();
+ }
+ });
+ add(m_select_all);
+ m_unselect_all = new StableMenuItem("Отменить всё", "/icons/UnselectAll.png");
+ m_unselect_all.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ SelectAll(false);
+ tree.updateUI();
+ }
+ });
+ add(m_unselect_all);
+ addSeparator();
+ m_select_for_current = new VisualiserMenuItem("");
+ m_select_for_current.addActionListener(new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Object o = Current.get(tree.getCurrent());
+ if (o instanceof Selectable) {
+ ((Selectable) o).SelectAllChildren(true);
+ }
+ tree.updateUI();
+ }
+ });
+ add(m_select_for_current);
+ //--------
+ m_unselect_for_current = new VisualiserMenuItem("");
+ m_unselect_for_current.addActionListener(new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Object o = Current.get(tree.getCurrent());
+ if (o instanceof Selectable) {
+ ((Selectable) o).SelectAllChildren(false);
+ }
+ tree.updateUI();
+ }
+ });
+ //-------
+ add(m_unselect_for_current);
+ }
+ public abstract Class getTargetClass(); //для кого позволяется выбирать всех потомков.
+ public abstract void SelectAll(boolean select);
+ @Override
+ public void CheckElementsVisibility() {
+ Object current = Current.get(tree.getCurrent());
+ if ((current != null) && (current.getClass().equals(getTargetClass()))) {
+ String name = ((Selectable) current).getSelectionText();
+ m_select_for_current.setText("Выбрать всё для " +
+ Utils.Brackets(name));
+ m_unselect_for_current.setText("Отменить выбор всех для " +
+ Utils.Brackets(name));
+ //-
+ m_select_for_current.setVisible(true);
+ m_unselect_for_current.setVisible(true);
+ } else {
+ m_select_for_current.setVisible(false);
+ m_unselect_for_current.setVisible(false);
+ }
+ }
+}
diff --git a/src/Common/UI/Menus/StyledPopupMenu.java b/src/Common/UI/Menus/StyledPopupMenu.java
new file mode 100644
index 00000000..e03a6daa
--- /dev/null
+++ b/src/Common/UI/Menus/StyledPopupMenu.java
@@ -0,0 +1,38 @@
+package Common.UI.Menus;
+import Common.Current;
+import Common.UI.Themes.ThemeElement;
+
+import javax.swing.*;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+public class StyledPopupMenu extends JPopupMenu implements ThemeElement {
+ public StyledPopupMenu() {
+ addPopupMenuListener(new PopupMenuListener() {
+ @Override
+ public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
+ CheckElementsVisibility();
+ }
+ @Override
+ public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
+ }
+ @Override
+ public void popupMenuCanceled(PopupMenuEvent e) {
+ }
+ });
+ }
+ private void refreshTheme_r(MenuElement element) {
+ element.getComponent().setBackground(Current.getTheme().background);
+ element.getComponent().setForeground(Current.getTheme().foreground);
+ for (MenuElement se : element.getSubElements())
+ refreshTheme_r(se);
+ }
+ @Override
+ public void applyTheme() {
+ setBackground(Current.getTheme().background);
+ setForeground(Current.getTheme().foreground);
+ refreshTheme_r(this);
+ }
+ public void CheckElementsVisibility() {
+ applyTheme();
+ }
+}
diff --git a/src/Common/UI/Menus/TableMenu.java b/src/Common/UI/Menus/TableMenu.java
new file mode 100644
index 00000000..ab171596
--- /dev/null
+++ b/src/Common/UI/Menus/TableMenu.java
@@ -0,0 +1,29 @@
+package Common.UI.Menus;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+public class TableMenu extends StyledPopupMenu {
+ int row = Utils.Nan;
+ int column = Utils.Nan;
+ Object target = null;
+ //-
+ JTable owner = null;
+ VisualiserMenuItem mcopy;
+ public TableMenu(JTable owner_in) {
+ owner = owner_in;
+ mcopy = new VisualiserMenuItem("Копировать текст текущей ячейки", "/icons/Editor/Copy.png");
+ //если удалось нажать значит все условия выполнены
+ mcopy.addActionListener(e -> Utils.CopyToClipboard(target.toString()));
+ add(mcopy);
+ }
+ @Override
+ public void CheckElementsVisibility() {
+ row = owner.getSelectedRow();
+ column = owner.getSelectedColumn();
+ if ((row >= 0) && (column >= 0)) {
+ target = owner.getValueAt(row, column);
+ mcopy.setVisible(true);
+ } else mcopy.setVisible(false);
+ super.CheckElementsVisibility();
+ }
+}
diff --git a/src/Common/UI/Menus/TestsCompilationFilterMenu.java b/src/Common/UI/Menus/TestsCompilationFilterMenu.java
new file mode 100644
index 00000000..b414a8d8
--- /dev/null
+++ b/src/Common/UI/Menus/TestsCompilationFilterMenu.java
@@ -0,0 +1,28 @@
+package Common.UI.Menus;
+import GlobalData.Tasks.TaskState;
+
+import javax.swing.*;
+import java.awt.event.ActionListener;
+public class TestsCompilationFilterMenu extends StyledPopupMenu{
+ public void CreateStateItem(TaskState state, ActionListener listener){
+ JMenuItem m = new VisualiserMenuItem(state.getDescription());
+ m.addActionListener(listener);
+ add(m);
+ }
+ public TestsCompilationFilterMenu(){
+ for (TaskState taskState: TaskState.values()){
+ switch (taskState){
+ case Queued:
+ case FailedToQueue:
+ case NoSuchTask:
+ case AbortingByUser:
+ break;
+ case Waiting:
+ CreateStateItem(taskState, e -> {
+
+ });
+ break;
+ }
+ }
+ }
+}
diff --git a/src/Common/UI/Menus/TextComboBoxMenu.java b/src/Common/UI/Menus/TextComboBoxMenu.java
new file mode 100644
index 00000000..ba966f64
--- /dev/null
+++ b/src/Common/UI/Menus/TextComboBoxMenu.java
@@ -0,0 +1,42 @@
+package Common.UI.Menus;
+import Common.UI.UI;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+public class TextComboBoxMenu extends StyledPopupMenu {
+ protected JComboBox box;
+ protected String selectedText = null;
+ //-------------------------------------------------
+ JMenuItem m_copy;
+ JMenuItem m_paste;
+ //-------------------------------------------------
+ public TextComboBoxMenu(JComboBox box_in) {
+ box = box_in;
+ m_copy = new VisualiserMenuItem("Копировать", "/icons/Editor/Copy.png");
+ m_copy.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Utils.CopyToClipboard(box.getSelectedItem().toString());
+ }
+ });
+ add(m_copy);
+ m_paste = new VisualiserMenuItem("Вставить", "/icons/Editor/Paste.png");
+ m_paste.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ UI.TrySelect(box, Utils.getFromClipboard());
+ }
+ });
+ add(m_paste);
+ }
+ @Override
+ public void CheckElementsVisibility() {
+ boolean visible_ = box.getSelectedIndex() >= 0;
+ m_paste.setVisible(visible_);
+ m_copy.setVisible(visible_);
+ super.CheckElementsVisibility();
+ }
+}
diff --git a/src/Common/UI/Menus/TextEditorMenu.java b/src/Common/UI/Menus/TextEditorMenu.java
new file mode 100644
index 00000000..119f7501
--- /dev/null
+++ b/src/Common/UI/Menus/TextEditorMenu.java
@@ -0,0 +1,86 @@
+package Common.UI.Menus;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+import javax.swing.text.JTextComponent;
+import java.awt.event.ActionEvent;
+import java.util.Vector;
+public class TextEditorMenu extends StyledPopupMenu {
+ protected JTextComponent editor;
+ protected String selectedText = null;
+ //-------------------------------------------------
+ JMenuItem m_cut;
+ JMenuItem m_copy;
+ JMenuItem m_paste;
+ protected JMenuItem m_strike;
+ protected JMenuItem m_unstrike;
+ //-------------------------------------------------
+ public TextEditorMenu(JTextComponent editor_in) {
+ editor = editor_in;
+ m_cut = new VisualiserMenuItem("Вырезать", "/icons/Editor/Cut.png");
+ m_cut.addActionListener(new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ editor.cut();
+ }
+ });
+ add(m_cut);
+ m_copy = new VisualiserMenuItem("Копировать", "/icons/Editor/Copy.png");
+ m_copy.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ editor.copy();
+ }
+ });
+ add(m_copy);
+ m_paste = new VisualiserMenuItem("Вставить", "/icons/Editor/Paste.png");
+ m_paste.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ editor.paste();
+ }
+ });
+ add(m_paste);
+ //--
+ m_strike = new VisualiserMenuItem("Вычеркнуть","/icons/Editor/Strikethrough.png");
+ m_strike.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String[] data = selectedText.split("\n");
+ Vector new_data = new Vector<>();
+ for (String line: data){
+ new_data.add(Utils.strikeThrough(line));
+ }
+ editor.replaceSelection(String.join("\n", new_data));
+ }
+ });
+ add(m_strike);
+ m_unstrike = new VisualiserMenuItem("Отменить вычёркивание","/icons/Editor/NoStrike.png");
+ m_unstrike.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String[] data = selectedText.split("\n");
+ Vector new_data = new Vector<>();
+ for (String line: data){
+ new_data.add(Utils.noStrikeThrough(line));
+ }
+ editor.replaceSelection(String.join("\n", new_data));
+ }
+ });
+ add(m_unstrike);
+ }
+ @Override
+ public void CheckElementsVisibility() {
+ selectedText = editor.getSelectedText();
+ m_cut.setVisible(editor.isEditable() && (selectedText != null));
+ m_paste.setVisible(editor.isEditable());
+ m_copy.setVisible(selectedText != null);
+ m_strike.setVisible(editor.isEditable() && (selectedText != null));
+ m_unstrike.setVisible(editor.isEditable() && (selectedText != null));
+ super.CheckElementsVisibility();
+ }
+}
diff --git a/src/Common/UI/Menus/VersionsMenu.java b/src/Common/UI/Menus/VersionsMenu.java
new file mode 100644
index 00000000..ee93ecc4
--- /dev/null
+++ b/src/Common/UI/Menus/VersionsMenu.java
@@ -0,0 +1,53 @@
+package Common.UI.Menus;
+import Common.Current;
+import Common.Global;
+import Common.UI.Menus_2023.StableMenuItem;
+import Common.UI.Trees.DataTree;
+import Common.UI.UI;
+import Common.Utils.Utils;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+public class VersionsMenu extends GraphMenu {
+ VisualiserMenuItem m_select_all;
+ VisualiserMenuItem m_unselect_all;
+ VisualiserMenuItem m_multiselection;
+ public VersionsMenu(DataTree tree) {
+ super(tree, "подверсии");
+ add(Pass_2021.passes.get(PassCode_2021.DeleteSubversions).createMenuItem());
+ add(Pass_2021.passes.get(PassCode_2021.DeleteLonelyM).createMenuItem());
+ addSeparator();
+ m_multiselection = new VisualiserMenuItem("Массовый режим работы с версиями");
+ m_multiselection.setIcon(Utils.getIcon(Global.versions_multiselection ? "/icons/Pick.png" : "/icons/NotPick.png"));
+ m_multiselection.addActionListener(e -> {
+ Global.versions_multiselection = !Global.versions_multiselection;
+ m_multiselection.setIcon(Utils.getIcon(Global.versions_multiselection ? "/icons/Pick.png" : "/icons/NotPick.png"));
+ Current.getRoot().SelectAllVersions(false);
+ UI.getVersionsWindow().getVersionsForm().getTree().updateUI();
+ });
+ add(m_multiselection);
+ addSeparator();
+ add(Pass_2021.passes.get(PassCode_2021.DeleteVersion).createMenuItem());
+ //-
+ m_select_all = new StableMenuItem("Выбрать всё, кроме резервных копий","/icons/SelectAll.png");
+ m_select_all.addActionListener(e -> {
+ Current.getRoot().SelectAllVersions(true);
+ tree.updateUI();
+ });
+ add(m_select_all);
+ m_unselect_all = new StableMenuItem("Отменить всё","/icons/UnselectAll.png");
+ m_unselect_all.addActionListener(e -> {
+ Current.getRoot().SelectAllVersions(false);
+ tree.updateUI();
+ });
+ add(m_unselect_all);
+ add(Pass_2021.passes.get(PassCode_2021.DeleteSelectedVersions).createMenuItem());
+ }
+ @Override
+ public void CheckElementsVisibility() {
+ Pass_2021.passes.get(PassCode_2021.DeleteSelectedVersions).setControlsVisible(!Global.versions_multiselection);
+ Pass_2021.passes.get(PassCode_2021.DeleteSelectedVersions).setControlsVisible(Global.versions_multiselection);
+ Pass_2021.passes.get(PassCode_2021.DeleteVersion).setControlsVisible(!Global.versions_multiselection);
+ m_select_all.setVisible(Global.versions_multiselection);
+ m_unselect_all.setVisible(Global.versions_multiselection);
+ }
+}
diff --git a/src/Common/UI/Menus/VisualiserMenuItem.java b/src/Common/UI/Menus/VisualiserMenuItem.java
new file mode 100644
index 00000000..9e35d957
--- /dev/null
+++ b/src/Common/UI/Menus/VisualiserMenuItem.java
@@ -0,0 +1,21 @@
+package Common.UI.Menus;
+import Common.Current;
+import Common.UI.Themes.VisualiserFonts;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+public class VisualiserMenuItem extends JMenuItem {
+ public VisualiserMenuItem(String text) {
+ super(text, null);
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Menu));
+ }
+ public VisualiserMenuItem(String text, String icon_path) {
+ super(text);
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Menu));
+ if (icon_path != null)
+ setIcon(Utils.getIcon(icon_path));
+ }
+ public VisualiserMenuItem(){
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Menu));
+ }
+}
diff --git a/src/Common/UI/Menus_2023/BugReportsMenuBar/BugReportsMenuBar.java b/src/Common/UI/Menus_2023/BugReportsMenuBar/BugReportsMenuBar.java
new file mode 100644
index 00000000..74e69199
--- /dev/null
+++ b/src/Common/UI/Menus_2023/BugReportsMenuBar/BugReportsMenuBar.java
@@ -0,0 +1,17 @@
+package Common.UI.Menus_2023.BugReportsMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class BugReportsMenuBar extends DataMenuBar {
+ public BugReportsMenuBar() {
+ super("отчёты об ошибках",
+ PassCode_2021.SynchronizeBugReports,
+ PassCode_2021.DownloadAllBugReportsArchives,
+ PassCode_2021.AddBugReport,
+ PassCode_2021.PublishBugReport,
+ PassCode_2021.OpenBugReportTestProject,
+ PassCode_2021.OpenBugReport,
+ PassCode_2021.UpdateBugReportProgress,
+ PassCode_2021.CloseBugReport,
+ PassCode_2021.DeleteBugReport);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/CompilersMenuBar/CompilersMenuBar.java b/src/Common/UI/Menus_2023/CompilersMenuBar/CompilersMenuBar.java
new file mode 100644
index 00000000..96adb6d1
--- /dev/null
+++ b/src/Common/UI/Menus_2023/CompilersMenuBar/CompilersMenuBar.java
@@ -0,0 +1,13 @@
+package Common.UI.Menus_2023.CompilersMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class CompilersMenuBar extends DataMenuBar {
+ public CompilersMenuBar() {
+ super("компиляторы",
+ PassCode_2021.AddCompiler,
+ PassCode_2021.EditCompiler,
+ PassCode_2021.DeleteCompiler,
+ PassCode_2021.ShowCompilerVersion,
+ PassCode_2021.ShowCompilerHelp);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/ComponentsMenuBar/ComponentsMenuBar.java b/src/Common/UI/Menus_2023/ComponentsMenuBar/ComponentsMenuBar.java
new file mode 100644
index 00000000..a979cefc
--- /dev/null
+++ b/src/Common/UI/Menus_2023/ComponentsMenuBar/ComponentsMenuBar.java
@@ -0,0 +1,27 @@
+package Common.UI.Menus_2023.ComponentsMenuBar;
+import Common.Current;
+import Common.UI.Menus_2023.DataMenuBar;
+import Common.UI.Menus_2023.VisualiserMenu;
+import Common.UI.Themes.VisualiserFonts;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+public class ComponentsMenuBar extends DataMenuBar {
+ public ComponentsMenuBar() {
+ super("компоненты");
+ addMenus(
+ new VisualiserMenu(
+ "Восстановление предыдущей версии компонента", "/icons/Resurrect.png") {
+ {
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Menu));
+ add(Pass_2021.passes.get(PassCode_2021.ResurrectComponent).createMenuItem());
+ add(Pass_2021.passes.get(PassCode_2021.ResurrectComponentFromServer).createMenuItem());
+ }
+ }
+ );
+ addPasses(PassCode_2021.InstallComponentFromFolder,
+ PassCode_2021.UpdateSelectedComponents,
+ PassCode_2021.PublishComponent,
+ PassCode_2021.ShowComponentChangesLog);
+ Pass_2021.passes.get(PassCode_2021.PublishComponent).setControlsVisible(false);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/ConfigurationsMenuBar/ConfigurationsMenuBar.java b/src/Common/UI/Menus_2023/ConfigurationsMenuBar/ConfigurationsMenuBar.java
new file mode 100644
index 00000000..054ab9d1
--- /dev/null
+++ b/src/Common/UI/Menus_2023/ConfigurationsMenuBar/ConfigurationsMenuBar.java
@@ -0,0 +1,33 @@
+package Common.UI.Menus_2023.ConfigurationsMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class ConfigurationsMenuBar extends DataMenuBar {
+ public ConfigurationsMenuBar() {
+ super("конфигурации");
+ /*
+ add(new MenuBarButton() {
+ {
+ setText("Оповещение по email");
+ setToolTipText("Оповещение о прогрессе выполнения пакета тестов");
+ Mark();
+ addActionListener(e -> {
+ email = !email;
+ Mark();
+ });
+ }
+ public void Mark() {
+ setIcon(Utils.getIcon(email ? "/icons/Pick.png" : "/icons/NotPick.png"));
+ }
+
+ });
+ */
+ addPasses(
+ PassCode_2021.EditMachineKernels,
+ PassCode_2021.StartTests,
+ PassCode_2021.PublishConfiguration,
+ PassCode_2021.CopyConfigurations,
+ PassCode_2021.EditConfiguration,
+ PassCode_2021.DeleteSelectedConfigurations
+ );
+ }
+}
diff --git a/src/Common/UI/Menus_2023/DVMParametersMenuBar/DVMParametersMenuBar.java b/src/Common/UI/Menus_2023/DVMParametersMenuBar/DVMParametersMenuBar.java
new file mode 100644
index 00000000..142234aa
--- /dev/null
+++ b/src/Common/UI/Menus_2023/DVMParametersMenuBar/DVMParametersMenuBar.java
@@ -0,0 +1,11 @@
+package Common.UI.Menus_2023.DVMParametersMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class DVMParametersMenuBar extends DataMenuBar {
+ public DVMParametersMenuBar() {
+ super("параметры",
+ PassCode_2021.AddDVMParameter,
+ PassCode_2021.EditDVMParameter,
+ PassCode_2021.DeleteDVMParameter);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/DataMenuBar.java b/src/Common/UI/Menus_2023/DataMenuBar.java
new file mode 100644
index 00000000..99de7d41
--- /dev/null
+++ b/src/Common/UI/Menus_2023/DataMenuBar.java
@@ -0,0 +1,54 @@
+package Common.UI.Menus_2023;
+import Common.Database.DataSet;
+import Visual_DVM_2021.Passes.PassCode_2021;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionListener;
+public class DataMenuBar extends VisualiserMenuBar {
+ public JLabel countLabel = null;
+ JButton selectAllButton = null;
+ JButton unselectAllButton = null;
+ //-
+ public ActionListener selectAllListener = null;
+ public ActionListener unselectAllListener = null;
+ //-
+ public DataMenuBar(String dataName, PassCode_2021... passes) {
+ // Font font = Current.getTheme().Fonts.get(VisualiserFonts.TreeBoldItalic).deriveFont(12.0F);
+ add(new JLabel(dataName + " "));
+ add(countLabel = new JLabel("?"));
+ addPasses(passes);
+ }
+ public void createSelectionButtons(DataSet dataSet) {
+ java.awt.Dimension d = new Dimension(25, 25);
+ if (selectAllButton == null) {
+ add(selectAllButton = new MenuBarButton() {
+ {
+ setIcon("/icons/SelectAll.png");
+ setToolTipText("Выбрать всё");
+ setPreferredSize(d);
+ setMinimumSize(d);
+ setMaximumSize(d);
+ }
+ }, 0);
+ }
+ if (unselectAllButton == null) {
+ add(unselectAllButton = new MenuBarButton() {
+ {
+ setIcon("/icons/UnselectAll.png");
+ setToolTipText("Отменить всё");
+ setPreferredSize(d);
+ setMinimumSize(d);
+ setMaximumSize(d);
+ }
+ }, 1);
+ }
+ if (selectAllListener != null) {
+ selectAllButton.removeActionListener(selectAllListener); }
+ selectAllButton.addActionListener(selectAllListener = e -> dataSet.CheckAll(true));
+ if (unselectAllListener != null) {
+ unselectAllButton.removeActionListener(unselectAllListener);
+ }
+ unselectAllButton.addActionListener(unselectAllListener = e -> dataSet.CheckAll(false));
+ }
+}
diff --git a/src/Common/UI/Menus_2023/EnvironmentValuesMenuBar/EnvironmentValuesMenuBar.java b/src/Common/UI/Menus_2023/EnvironmentValuesMenuBar/EnvironmentValuesMenuBar.java
new file mode 100644
index 00000000..463c8c23
--- /dev/null
+++ b/src/Common/UI/Menus_2023/EnvironmentValuesMenuBar/EnvironmentValuesMenuBar.java
@@ -0,0 +1,12 @@
+package Common.UI.Menus_2023.EnvironmentValuesMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class EnvironmentValuesMenuBar extends DataMenuBar {
+ public EnvironmentValuesMenuBar() {
+ super("переменные окружения", PassCode_2021.AddEnvironmentValue,
+ PassCode_2021.EditEnvironmentValue,
+ PassCode_2021.DeleteEnvironmentValue,
+ PassCode_2021.PickCompilerEnvironments
+ );
+ }
+}
diff --git a/src/Common/UI/Menus_2023/FastAccessMenuBar/FastAccessMenuBar.java b/src/Common/UI/Menus_2023/FastAccessMenuBar/FastAccessMenuBar.java
new file mode 100644
index 00000000..40c31d1d
--- /dev/null
+++ b/src/Common/UI/Menus_2023/FastAccessMenuBar/FastAccessMenuBar.java
@@ -0,0 +1,49 @@
+package Common.UI.Menus_2023.FastAccessMenuBar;
+import Common.Global;
+import Common.UI.Menus_2023.VisualiserMenuBar;
+import Common.UI.UI;
+import GlobalData.Settings.SettingName;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.LinkedHashMap;
+public class FastAccessMenuBar extends VisualiserMenuBar {
+ LinkedHashMap passesButtons = new LinkedHashMap<>();
+ public FastAccessMenuBar() {
+ Refresh();
+ }
+ @Override
+ public void setSizeLimits() {
+ //если задавать PreffredSize 0, скролл НЕ РАБОТАЕТ. Магия!
+ }
+ public void showPass(Pass_2021 pass) {
+ JButton button = null;
+ if (passesButtons.containsKey(pass.code()))
+ button = passesButtons.get((pass.code()));
+ else {
+ button = pass.createButton();
+ passesButtons.put(pass.code(), button);
+ }
+ add(button);
+ Dimension d = button.getPreferredSize();
+ button.setPreferredSize(new Dimension(d.width, 30));
+ revalidate();
+ repaint();
+ }
+ public void Refresh() {
+ UI.Clear(this);
+ int i = 1;
+ for (Pass_2021 pass : Pass_2021.FAPasses) {
+ if (pass.stats.HasUsages()) {
+ showPass(pass);
+ ++i;
+ if (i > (Global.db.settings.get(SettingName.FastAccessPassesCount).toInt32())) break;
+ }
+ }
+ }
+ public void Drop(){
+ UI.Clear(this);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/FileMenuBar/FileMenuBar.java b/src/Common/UI/Menus_2023/FileMenuBar/FileMenuBar.java
new file mode 100644
index 00000000..2ea937c8
--- /dev/null
+++ b/src/Common/UI/Menus_2023/FileMenuBar/FileMenuBar.java
@@ -0,0 +1,84 @@
+package Common.UI.Menus_2023.FileMenuBar;
+import Common.UI.Menus_2023.MenuBarButton;
+import Common.UI.Menus_2023.VisualiserMenuBar;
+import Common.UI.UI;
+import ProjectData.Files.UI.Editor.SPFEditor;
+import Visual_DVM_2021.Passes.PassCode_2021;
+
+import javax.swing.*;
+import java.awt.*;
+public class FileMenuBar extends VisualiserMenuBar {
+ public JSpinner sToGo;
+ JLabel LineCountLabel;
+ public JLabel CurrentSymbolLabel;
+ SPFEditor editor;
+ FileSettingsMenu fileSettingsMenu;
+ public FileMenuBar(SPFEditor editor_in) {
+ editor = editor_in;
+ add(new MenuBarButton() {
+ {
+ setToolTipText("Поиск(Ctrl+F)");
+ setIcon("/icons/LastOpened.png");
+ addActionListener(e -> UI.ShowSearchForm());
+ }
+ });
+ addPasses(PassCode_2021.Save);
+ add(new MenuBarButton() {
+ {
+ setToolTipText("Увеличить шрифт(Ctrl+'+')");
+ setIcon("/icons/Editor/Font+.png");
+ addActionListener(e -> editor.FontUp());
+ }
+ });
+ add(new MenuBarButton() {
+ {
+ setToolTipText("Уменьшить шрифт(Ctrl+'-')");
+ setIcon("/icons/Editor/Font-.png");
+ addActionListener(e -> editor.FontDown());
+ }
+ });
+ add(new MenuBarButton() {
+ boolean isOn = false;
+ {
+ setToolTipText("Отображать спецсимволы");
+ setIcon("/icons/Editor/ShowNoSigns.png");
+ addActionListener(e-> {
+ isOn = !isOn;
+ if (isOn) {
+ setIcon("/icons/Editor/ShowAllSigns.png");
+ setToolTipText("Скрыть спецсимволы");
+ editor.setWhitespaceVisible(true);
+ editor.setEOLMarkersVisible(true);
+ } else {
+ setIcon("/icons/Editor/ShowNoSigns.png");
+ setToolTipText("Отображать спецсимволы");
+ editor.setWhitespaceVisible(false);
+ editor.setEOLMarkersVisible(false);
+ }
+ });
+ }
+ });
+ add(new JLabel(" Строка "));
+ add(sToGo = new JSpinner());
+ sToGo.setPreferredSize(new Dimension(60, 25));
+ sToGo.setMaximumSize(new Dimension(60, 25));
+ add(new JLabel(" из "));
+ add(LineCountLabel = new JLabel("?"));
+ add(new JLabel(" | "));
+ add(new JLabel("Позиция "));
+ add(CurrentSymbolLabel = new JLabel());
+ add(new JSeparator());
+ addMenus(fileSettingsMenu = new FileSettingsMenu());
+ //--
+ // addPasses(PassCode_2021.CloseCurrentFile);
+ //-
+ setPreferredSize(new Dimension(0, 30));
+ }
+ public void ShowLinesCount() {
+ LineCountLabel.setText(String.valueOf(editor.getLineCount()));
+ }
+ //-
+ public void ShowLanguage(){fileSettingsMenu.ShowLanguage();}
+ public void ShowType(){fileSettingsMenu.ShowType();}
+ public void ShowStyle(){fileSettingsMenu.ShowStyle();}
+}
diff --git a/src/Common/UI/Menus_2023/FileMenuBar/FileSettingsMenu.java b/src/Common/UI/Menus_2023/FileMenuBar/FileSettingsMenu.java
new file mode 100644
index 00000000..3ab9069e
--- /dev/null
+++ b/src/Common/UI/Menus_2023/FileMenuBar/FileSettingsMenu.java
@@ -0,0 +1,63 @@
+package Common.UI.Menus_2023.FileMenuBar;
+import Common.Current;
+import Common.UI.Menus_2023.LanguagesSubmenu;
+import Common.UI.Menus_2023.StylesSubmenu;
+import Common.UI.Menus_2023.TypesSubmenu;
+import Common.UI.Menus_2023.VisualiserMenu;
+import Common.UI.UI;
+import ProjectData.Files.FileType;
+import ProjectData.Files.LanguageStyle;
+import ProjectData.LanguageName;
+
+import javax.swing.*;
+public class FileSettingsMenu extends VisualiserMenu {
+ JMenu mLanguage;
+ JMenu mStyle;
+ JMenu mType;
+ public FileSettingsMenu() {
+ super("Настройки файла", "/icons/Settings.png");
+ add(mLanguage = new LanguagesSubmenu() {
+ @Override
+ public void action(LanguageName languageName) {
+ if (Current.getFile().UpdateLanguage(languageName)) {
+ Current.getSapfor().ResetAllAnalyses();
+ Current.getFile().form.ShowLanguage();
+ UI.getMainWindow().getProjectWindow().getFilesTreeForm().getTree().RefreshNode(Current.getFile().node);
+ }
+ }
+ });
+ ShowLanguage();
+ //--
+ add(mStyle = new StylesSubmenu() {
+ @Override
+ public void action(LanguageStyle languageStyle) {
+ if (Current.getFile().UpdateStyle(languageStyle)) {
+ Current.getSapfor().ResetAllAnalyses();
+ Current.getFile().form.ShowStyle();
+ }
+ }
+ });
+ ShowStyle();
+ //--
+ add(mType = new TypesSubmenu() {
+ @Override
+ public void action(FileType fileType) {
+ if (Current.getFile().UpdateType(fileType)) {
+ Current.getSapfor().ResetAllAnalyses();
+ UI.getMainWindow().getProjectWindow().getFilesTreeForm().getTree().RefreshNode(Current.getFile().node);
+ Current.getFile().form.ShowType();
+ }
+ }
+ });
+ ShowType();
+ }
+ public void ShowLanguage() {
+ mLanguage.setText("Язык: " + Current.getFile().languageName.getDescription());
+ }
+ public void ShowStyle() {
+ mStyle.setText("Стиль: " + Current.getFile().style.getDescription());
+ }
+ public void ShowType() {
+ mType.setText("Тип: " + Current.getFile().fileType.getDescription());
+ }
+}
diff --git a/src/Common/UI/Menus_2023/GroupsMenuBar/GroupsMenuBar.java b/src/Common/UI/Menus_2023/GroupsMenuBar/GroupsMenuBar.java
new file mode 100644
index 00000000..2dbc22cc
--- /dev/null
+++ b/src/Common/UI/Menus_2023/GroupsMenuBar/GroupsMenuBar.java
@@ -0,0 +1,42 @@
+package Common.UI.Menus_2023.GroupsMenuBar;
+import Common.Global;
+import Common.UI.Menus_2023.DataMenuBar;
+import Common.UI.Menus_2023.MenuBarButton;
+import Common.Utils.Utils;
+import TestingSystem.Group.GroupInterface;
+import Visual_DVM_2021.Passes.PassCode_2021;
+
+import javax.swing.*;
+public class GroupsMenuBar extends DataMenuBar {
+ public GroupsMenuBar() {
+ super("группы", PassCode_2021.SynchronizeTests, PassCode_2021.DownloadGroup, PassCode_2021.ConvertCorrectnessTests, PassCode_2021.PublishGroup, PassCode_2021.CopyGroups, PassCode_2021.EditGroup, PassCode_2021.DeleteSelectedGroups);
+ add(new JSeparator());
+ add(new MenuBarButton() {
+ {
+ setText("Свои");
+ setToolTipText("Отображать только группы тестов авторства пользователя");
+ Mark();
+ addActionListener(e -> {
+ GroupInterface.filterMyOnly = !GroupInterface.filterMyOnly;
+ Mark();
+ Global.testingServer.db.groups.ShowUI();
+ });
+ }
+ public void Mark() {
+ setIcon(Utils.getIcon(GroupInterface.filterMyOnly ? "/icons/Pick.png" : "/icons/NotPick.png"));
+ }
+ });
+ }
+ public void addFilters(JMenu typesFilterMenu, JMenu languagesFilterMenu) {
+ filters = addMenus(typesFilterMenu, languagesFilterMenu);
+ }
+ JMenuBar filters= null;
+ public void DropFilters() {
+ if (filters != null) {
+ remove(filters);
+ filters = null;
+ }
+ revalidate();
+ repaint();
+ }
+}
diff --git a/src/Common/UI/Menus_2023/LanguagesSubmenu.java b/src/Common/UI/Menus_2023/LanguagesSubmenu.java
new file mode 100644
index 00000000..710a1e23
--- /dev/null
+++ b/src/Common/UI/Menus_2023/LanguagesSubmenu.java
@@ -0,0 +1,34 @@
+package Common.UI.Menus_2023;
+import Common.Utils.Utils;
+import ProjectData.LanguageName;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+public abstract class LanguagesSubmenu extends VisualiserMenu {
+ public LanguagesSubmenu() {
+ this("Язык");
+ }
+ public LanguagesSubmenu(String text) {
+ super(text, "/icons/Language.png", true);
+ for (LanguageName languageName : LanguageName.values()) {
+ if (languageName.equals(LanguageName.fortran) ||
+ (languageName.equals(LanguageName.c) ||
+ (languageName.equals(LanguageName.cpp)))) {
+
+ JMenuItem languageItem = new StableMenuItem(languageName.getDescription());
+ String li = languageName.getIcon();
+ if (!li.isEmpty())
+ languageItem.setIcon(Utils.getIcon(li));
+ languageItem.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ action(languageName);
+ }
+ });
+ add(languageItem);
+ }
+ }
+ }
+ public abstract void action(LanguageName languageName);
+}
diff --git a/src/Common/UI/Menus_2023/MachinesMenuBar/MachinesMenuBar.java b/src/Common/UI/Menus_2023/MachinesMenuBar/MachinesMenuBar.java
new file mode 100644
index 00000000..1eadd19d
--- /dev/null
+++ b/src/Common/UI/Menus_2023/MachinesMenuBar/MachinesMenuBar.java
@@ -0,0 +1,11 @@
+package Common.UI.Menus_2023.MachinesMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class MachinesMenuBar extends DataMenuBar {
+ public MachinesMenuBar() {
+ super("машины",
+ PassCode_2021.AddMachine,
+ PassCode_2021.EditMachine,
+ PassCode_2021.DeleteMachine);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/MainMenuBar/AnalysesMenu.java b/src/Common/UI/Menus_2023/MainMenuBar/AnalysesMenu.java
new file mode 100644
index 00000000..bc997d69
--- /dev/null
+++ b/src/Common/UI/Menus_2023/MainMenuBar/AnalysesMenu.java
@@ -0,0 +1,14 @@
+package Common.UI.Menus_2023.MainMenuBar;
+import Common.UI.Menus_2023.VisualiserMenu;
+import Repository.Component.Sapfor.Sapfor;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+public class AnalysesMenu extends VisualiserMenu {
+ public AnalysesMenu() {
+ super("Анализаторы","/icons/Analyses.png" );
+ for (PassCode_2021 code : Sapfor.getAnalysesCodes())
+ add(Pass_2021.passes.get(code).createMenuItem());
+ addSeparator();
+ add(Pass_2021.passes.get(PassCode_2021.SPF_GetGCovInfo).createMenuItem());
+ }
+}
diff --git a/src/Common/UI/Menus_2023/MainMenuBar/GlobalCleaningMenu.java b/src/Common/UI/Menus_2023/MainMenuBar/GlobalCleaningMenu.java
new file mode 100644
index 00000000..5d6d8aa4
--- /dev/null
+++ b/src/Common/UI/Menus_2023/MainMenuBar/GlobalCleaningMenu.java
@@ -0,0 +1,20 @@
+package Common.UI.Menus_2023.MainMenuBar;
+import Common.UI.Menus_2023.VisualiserMenu;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+public class GlobalCleaningMenu extends VisualiserMenu {
+ public GlobalCleaningMenu() {
+ super("Очистка", "/icons/Clean.png", false);
+ add(Pass_2021.passes.get(PassCode_2021.DropLastProjects).createMenuItem());
+ add(Pass_2021.passes.get(PassCode_2021.DropFastAccess).createMenuItem());
+ addSeparator();
+ add(Pass_2021.passes.get(PassCode_2021.DeleteDownloadedBugReports).createMenuItem());
+ addSeparator();
+ add(Pass_2021.passes.get(PassCode_2021.DropAnalyses).createMenuItem());
+ add(Pass_2021.passes.get(PassCode_2021.CleanAnalyses).createMenuItem());
+ add(Pass_2021.passes.get(PassCode_2021.DropSavedArrays).createMenuItem());
+ add(Pass_2021.passes.get(PassCode_2021.DeleteDebugResults).createMenuItem());
+ addSeparator();
+ add(Pass_2021.passes.get(PassCode_2021.ResetCurrentProject).createMenuItem());
+ }
+}
diff --git a/src/Common/UI/Menus_2023/MainMenuBar/LastOpenedProjectsMenu.java b/src/Common/UI/Menus_2023/MainMenuBar/LastOpenedProjectsMenu.java
new file mode 100644
index 00000000..1f4e8d1d
--- /dev/null
+++ b/src/Common/UI/Menus_2023/MainMenuBar/LastOpenedProjectsMenu.java
@@ -0,0 +1,48 @@
+package Common.UI.Menus_2023.MainMenuBar;
+import Common.Global;
+import Common.UI.Menus.VisualiserMenuItem;
+import Common.UI.Menus_2023.VisualiserMenu;
+import GlobalData.DBLastProject.DBLastProject;
+import GlobalData.Settings.SettingName;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+
+import javax.swing.*;
+import javax.swing.event.MenuEvent;
+import javax.swing.event.MenuListener;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.util.Vector;
+public class LastOpenedProjectsMenu extends VisualiserMenu {
+ public LastOpenedProjectsMenu() {
+ super("Недавние проекты", "/icons/LastOpened.png");
+ addMenuListener(new MenuListener() {
+ @Override
+ public void menuSelected(MenuEvent e) {
+ removeAll();
+ Vector projects = Global.db.lastProjects.getOrdered();
+ int k = 1;
+ for (DBLastProject p : projects) {
+ if (new File(p.HomePath).exists() && p.lastOpened != 0) {
+ VisualiserMenuItem i = new VisualiserMenuItem(p.HomePath);
+ i.addActionListener(new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Pass_2021.passes.get(PassCode_2021.OpenCurrentProject).Do(new File(p.HomePath));
+ }
+ });
+ add(i);
+ ++k;
+ if (k > (Global.db.settings.get(SettingName.LastOpenedProjectsCount).toInt32())) break;
+ }
+ }
+ }
+ @Override
+ public void menuDeselected(MenuEvent e) {
+ }
+ @Override
+ public void menuCanceled(MenuEvent e) {
+ }
+ });
+ }
+}
diff --git a/src/Common/UI/Menus_2023/MainMenuBar/MainMenuBar.java b/src/Common/UI/Menus_2023/MainMenuBar/MainMenuBar.java
new file mode 100644
index 00000000..a38dfcce
--- /dev/null
+++ b/src/Common/UI/Menus_2023/MainMenuBar/MainMenuBar.java
@@ -0,0 +1,87 @@
+package Common.UI.Menus_2023.MainMenuBar;
+import Common.Global;
+import Common.UI.Menus_2023.MenuBarButton;
+import Common.UI.Menus_2023.VisualiserMenuBar;
+import Common.UI.UI;
+import Repository.Component.PerformanceAnalyzer.PerformanceAnalyzer;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+
+import javax.swing.*;
+import java.awt.*;
+public class MainMenuBar extends VisualiserMenuBar {
+ JMenu analyses;
+ JMenu transformations;
+ MenuBarButton components;
+ public MainMenuBar() {
+ addMenus(new LastOpenedProjectsMenu());
+ addPasses(PassCode_2021.OpenCurrentProject, PassCode_2021.CreateEmptyProject);
+ addMenus(
+ analyses = new AnalysesMenu(),
+ transformations = new TransformationsMenu(),
+ new GlobalCleaningMenu(),
+ new VisualiserSettingsMenu()
+ );
+ add(components = new MenuBarButton() {
+ {
+ setToolTipText("Компоненты");
+ setIcon("/icons/ComponentsActual.png");
+ addActionListener(e -> {
+ if (PerformanceAnalyzer.isActive) {
+ UI.Info("Перед работой с компонентами закройте анализатор производительности!");
+ } else {
+ Pass_2021.passes.get(PassCode_2021.GetComponentsActualVersions).Do();
+ Global.RefreshUpdatesStatus();
+ UI.ShowComponentsWindow();
+ }
+ });
+ }
+ });
+ add(new MenuBarButton() {
+ {
+ setIcon("/icons/Comparsion.png");
+ setToolTipText("Анализатор статистик");
+ addActionListener(e -> {
+ Global.performanceAnalyzer.Start();
+ });
+ }
+ });
+ addPasses(PassCode_2021.ShowInstruction);
+ //-
+ setPreferredSize(new Dimension(0, 30));
+ //---
+ /*
+ add(new MenuBarButton() {
+ {
+ setIcon("/icons/Apply.png");
+ setToolTipText("Test");
+ addActionListener(e -> {
+ Current.getProject().hasSubdirectories();
+ });
+ }
+ });
+ */
+ //---
+ ShowProject(false);
+ }
+ public void ShowUpdatesIcon() {
+ components.setIcon(
+ (Global.need_update > 0) || (Global.bad_state > 0)
+ ? "/icons/ComponentsNeedUpdate.gif"
+ : (Global.need_publish > 0 ? "/icons/ComponentsNeedPublish_2023.gif" : "/icons/ComponentsActual.png"));
+ }
+ public void ShowProject(boolean flag) {
+ analyses.setEnabled(flag);
+ transformations.setEnabled(flag);
+ Pass_2021[] cleaningPasses = new Pass_2021[]{
+ Pass_2021.passes.get(PassCode_2021.DropAnalyses),
+ Pass_2021.passes.get(PassCode_2021.DropSavedArrays),
+ Pass_2021.passes.get(PassCode_2021.CleanAnalyses),
+ Pass_2021.passes.get(PassCode_2021.DeleteDebugResults),
+ Pass_2021.passes.get(PassCode_2021.ResetCurrentProject)
+ };
+ for (Pass_2021 pass: cleaningPasses){
+ pass.setControlsEnabled(flag);
+ }
+ }
+}
diff --git a/src/Common/UI/Menus_2023/MainMenuBar/MainWindow.java b/src/Common/UI/Menus_2023/MainMenuBar/MainWindow.java
new file mode 100644
index 00000000..e16ccfb6
--- /dev/null
+++ b/src/Common/UI/Menus_2023/MainMenuBar/MainWindow.java
@@ -0,0 +1,19 @@
+package Common.UI.Menus_2023.MainMenuBar;
+import Visual_DVM_2021.UI.Interface.CallbackWindow;
+import Visual_DVM_2021.UI.Interface.ProjectWindow;
+import Visual_DVM_2021.UI.Interface.TestingWindow;
+public interface MainWindow {
+ void Show();
+ void ShowProject();
+ void ShowNoProject();
+ ProjectWindow getProjectWindow();
+ CallbackWindow getCallbackWindow();
+ //-
+ void ShowUpdatesIcon();
+ void FocusProject();
+ void FocusCallback();
+ void FocusTesting();
+ TestingWindow getTestingWindow();
+ void ShowTestingTab();
+ void HideTestingTab();
+}
diff --git a/src/Common/UI/Menus_2023/MainMenuBar/TransformationsMenu.java b/src/Common/UI/Menus_2023/MainMenuBar/TransformationsMenu.java
new file mode 100644
index 00000000..4a1b45f5
--- /dev/null
+++ b/src/Common/UI/Menus_2023/MainMenuBar/TransformationsMenu.java
@@ -0,0 +1,36 @@
+package Common.UI.Menus_2023.MainMenuBar;
+import Common.UI.Menus.PassesSubMenu;
+import Common.UI.Menus_2023.VisualiserMenu;
+import Repository.Component.Sapfor.Sapfor;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+public class TransformationsMenu extends VisualiserMenu {
+ public TransformationsMenu() {
+ super("Преобразования", "/icons/Transformations.png");
+ add(new PassesSubMenu("Циклы", "/icons/Menu/Loops.png",
+ Sapfor.getLoopsTransformationsCodes()));
+ addSeparator();
+ add(new PassesSubMenu("Приватные переменные", "/icons/Menu/Privates.png",
+ Sapfor.getPrivatesTransformationsCodes()));
+ addSeparator();
+ add(new PassesSubMenu("Процедуры", "/icons/Menu/Functions.png",
+ Sapfor.getProceduresTransformationsCodes()));
+ addSeparator();
+ add(new PassesSubMenu("DVM директивы", "/icons/Menu/Dvm.png",
+ Sapfor.getDVMTransformationsCodes()));
+ addSeparator();
+ add(new PassesSubMenu("Интервалы", "/icons/Menu/Intervals.png",
+ Sapfor.getIntervalsTransformationsCodes()
+ ));
+ addSeparator();
+ add(new PassesSubMenu("Области распараллеливания", "/icons/Menu/Regions.png",
+ Sapfor.getRegionsTransformationsCodes()
+ ));
+ addSeparator();
+ add(new PassesSubMenu("Предобработка проекта", "/icons/Menu/Preprocessing.png",
+ Sapfor.getPreparationTransformationsCodes()
+ )
+ );
+ add(Pass_2021.passes.get(PassCode_2021.SPF_SharedMemoryParallelization).createMenuItem());
+ }
+}
\ No newline at end of file
diff --git a/src/Common/UI/Menus_2023/MainMenuBar/VisualiserSettingsMenu.java b/src/Common/UI/Menus_2023/MainMenuBar/VisualiserSettingsMenu.java
new file mode 100644
index 00000000..cb3905ab
--- /dev/null
+++ b/src/Common/UI/Menus_2023/MainMenuBar/VisualiserSettingsMenu.java
@@ -0,0 +1,47 @@
+package Common.UI.Menus_2023.MainMenuBar;
+import Common.Global;
+import Common.UI.Menus.PropertiesSubmenu;
+import Common.UI.Menus_2023.SettingsSubmenu;
+import Common.UI.Menus_2023.VisualiserMenu;
+import GlobalData.Settings.SettingName;
+public class VisualiserSettingsMenu extends VisualiserMenu {
+ public VisualiserSettingsMenu() {
+ super("Настройки визуализатора", "/icons/Settings.png");
+ //-
+ add(new PropertiesSubmenu("Подтверждения и уведомления", null,
+ "ShowPassesDone",
+ "ConfirmPassesStart",
+ "FocusPassesResult"
+ ));
+ add(new SettingsSubmenu("Компактность отображения", null,
+ SettingName.SmallScreen,
+ SettingName.ShowFullTabsNames,
+ SettingName.ShowFullArraysDeclarations,
+ SettingName.FastAccessPassesCount,
+ SettingName.LastOpenedProjectsCount
+ ));
+ if (Global.isWindows) {
+ add(new SettingsSubmenu("Компиляция на локальной машине", null,
+ SettingName.LocalMakePathWindows,
+ SettingName.Kernels
+ ));
+ } else {
+ add(new SettingsSubmenu("Компиляция на локальной машине", null,
+ SettingName.Kernels
+ ));
+ }
+ add(new SettingsSubmenu("Синхронизация", null,
+ SettingName.AutoBugReportsLoad,
+ SettingName.AutoTestsLoad
+ ));
+ add(new SettingsSubmenu("Сравнение", null,
+ SettingName.ExtensionsOn,
+ SettingName.RegisterOn,
+ SettingName.SpacesOn,
+ SettingName.EmptyLinesOn,
+ SettingName.FortranWrapsOn,
+ SettingName.ComparsionDiffMergeOn
+ ));
+ add(Global.db.settings.get(SettingName.Workspace).getMenuItem());
+ }
+}
diff --git a/src/Common/UI/Menus_2023/MakefilesMenuBar/MakefilesMenuBar.java b/src/Common/UI/Menus_2023/MakefilesMenuBar/MakefilesMenuBar.java
new file mode 100644
index 00000000..4dc80800
--- /dev/null
+++ b/src/Common/UI/Menus_2023/MakefilesMenuBar/MakefilesMenuBar.java
@@ -0,0 +1,14 @@
+package Common.UI.Menus_2023.MakefilesMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class MakefilesMenuBar extends DataMenuBar {
+ public MakefilesMenuBar() {
+ super("мейкфайлы",
+ PassCode_2021.Compile,
+ PassCode_2021.AddMakefile,
+ PassCode_2021.EditMakefile,
+ PassCode_2021.DeleteMakefile);
+ addSeparator();
+ addPasses(PassCode_2021.ShowMakefilePreview, PassCode_2021.EditProjectCompilationMaxtime);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/MenuBarButton.java b/src/Common/UI/Menus_2023/MenuBarButton.java
new file mode 100644
index 00000000..5edf9d10
--- /dev/null
+++ b/src/Common/UI/Menus_2023/MenuBarButton.java
@@ -0,0 +1,32 @@
+package Common.UI.Menus_2023;
+import Common.Current;
+import Common.UI.Themes.VisualiserFonts;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+import java.awt.*;
+//https://java-online.ru/swing-jbutton.xhtml
+public class MenuBarButton extends JButton {
+ public MenuBarButton() {
+ super();
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Menu));
+ //
+ setBorderPainted(false);
+ setContentAreaFilled(false);
+ setOpaque(false);
+ //setFocusPainted(false);
+ //-
+ setMinimumSize(new Dimension(38, 30)); //иначе сужаются вертикально.
+ }
+ @Override
+ protected void paintComponent(Graphics g) {
+ if (getModel().isPressed()) {
+ g.setColor(new Color(163, 184, 204));
+ g.fillRect(0, 0, getWidth(), getHeight());
+ }
+ super.paintComponent(g);
+ }
+ public void setIcon(String icon_path) {
+ setIcon(Utils.getIcon(icon_path));
+ }
+}
diff --git a/src/Common/UI/Menus_2023/ModulesMenuBar/ModulesMenuBar.java b/src/Common/UI/Menus_2023/ModulesMenuBar/ModulesMenuBar.java
new file mode 100644
index 00000000..bca2de3b
--- /dev/null
+++ b/src/Common/UI/Menus_2023/ModulesMenuBar/ModulesMenuBar.java
@@ -0,0 +1,8 @@
+package Common.UI.Menus_2023.ModulesMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class ModulesMenuBar extends DataMenuBar {
+ public ModulesMenuBar() {
+ super("языковые модули", PassCode_2021.EditModule);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/PassButton.java b/src/Common/UI/Menus_2023/PassButton.java
new file mode 100644
index 00000000..43f05d35
--- /dev/null
+++ b/src/Common/UI/Menus_2023/PassButton.java
@@ -0,0 +1,25 @@
+package Common.UI.Menus_2023;
+import Visual_DVM_2021.Passes.Pass_2021;
+
+import java.awt.*;
+public class PassButton extends MenuBarButton implements PassControl {
+ public PassButton(Pass_2021 pass, boolean tab) {
+ setText(pass.getButtonText());
+ setToolTipText(pass.getDescription());
+ if (pass.getIconPath() != null) {
+ if (tab) {
+ setIcon(pass.getTabIcon());
+ setPreferredSize(new Dimension(18,18));
+ setMaximumSize(new Dimension(18,18));
+ setMinimumSize(new Dimension(18,18));
+ }
+ else
+ setIcon(pass.getIconPath());
+ }
+ addActionListener(pass.getControlAction());
+ pass.controls.add(this);
+ }
+ public PassButton(Pass_2021 pass) {
+ this(pass, false);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/PassControl.java b/src/Common/UI/Menus_2023/PassControl.java
new file mode 100644
index 00000000..7aae17b9
--- /dev/null
+++ b/src/Common/UI/Menus_2023/PassControl.java
@@ -0,0 +1,7 @@
+package Common.UI.Menus_2023;
+public interface PassControl {
+ void setIcon(String icon_path);
+ void setEnabled(boolean flag);
+ void setVisible(boolean flag);
+ void setToolTipText(String text);
+}
diff --git a/src/Common/UI/Menus_2023/PassMenuItem.java b/src/Common/UI/Menus_2023/PassMenuItem.java
new file mode 100644
index 00000000..15a2c5c1
--- /dev/null
+++ b/src/Common/UI/Menus_2023/PassMenuItem.java
@@ -0,0 +1,17 @@
+package Common.UI.Menus_2023;
+import Common.UI.Menus.VisualiserMenuItem;
+import Common.Utils.Utils;
+import Visual_DVM_2021.Passes.Pass_2021;
+public class PassMenuItem extends VisualiserMenuItem implements PassControl {
+ @Override
+ public void setIcon(String icon_path) {
+ setIcon(Utils.getIcon(icon_path));
+ }
+ public PassMenuItem(Pass_2021 pass) {
+ setText(pass.getDescription());
+ setToolTipText(pass.getDescription());
+ if (pass.getIconPath() != null) setIcon(pass.getIconPath());
+ addActionListener(pass.getControlAction());
+ pass.controls.add(this);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/ProjectMenuBar/FilesOperationsMenu.java b/src/Common/UI/Menus_2023/ProjectMenuBar/FilesOperationsMenu.java
new file mode 100644
index 00000000..f3dada3d
--- /dev/null
+++ b/src/Common/UI/Menus_2023/ProjectMenuBar/FilesOperationsMenu.java
@@ -0,0 +1,7 @@
+package Common.UI.Menus_2023.ProjectMenuBar;
+import Common.UI.Menus_2023.VisualiserMenu;
+public class FilesOperationsMenu extends VisualiserMenu {
+ public FilesOperationsMenu() {
+ super("Массовые операции над файлами","/icons/MassFiles.png" );
+ }
+}
diff --git a/src/Common/UI/Menus_2023/ProjectMenuBar/ProjectMenuBar.java b/src/Common/UI/Menus_2023/ProjectMenuBar/ProjectMenuBar.java
new file mode 100644
index 00000000..3fd5036a
--- /dev/null
+++ b/src/Common/UI/Menus_2023/ProjectMenuBar/ProjectMenuBar.java
@@ -0,0 +1,33 @@
+package Common.UI.Menus_2023.ProjectMenuBar;
+import Common.UI.Menus_2023.MenuBarButton;
+import Common.UI.Menus_2023.VisualiserMenuBar;
+import Common.UI.UI;
+
+import javax.swing.*;
+import java.awt.*;
+public class ProjectMenuBar extends VisualiserMenuBar {
+ public ProjectViewMenu projectViewMenu;
+ public ProjectMenuBar() {
+ addMenus(projectViewMenu = new ProjectViewMenu());
+ add(new JSeparator());
+ addMenus(
+ new ProjectSettingsMenu()
+ );
+ add(new MenuBarButton() {
+ {
+ setToolTipText("Профили");
+ setIcon("/icons/Profiles.png");
+ addActionListener(e -> {
+ UI.ShowProfilesWindow();
+ });
+ }
+ });
+ }
+ public ProjectViewMenu getProjectViewMenu() {
+ return projectViewMenu;
+ }
+ @Override
+ public void setSizeLimits() {
+ setPreferredSize(new Dimension(0, 32));
+ }
+}
diff --git a/src/Common/UI/Menus_2023/ProjectMenuBar/ProjectSettingsMenu.java b/src/Common/UI/Menus_2023/ProjectMenuBar/ProjectSettingsMenu.java
new file mode 100644
index 00000000..475c8026
--- /dev/null
+++ b/src/Common/UI/Menus_2023/ProjectMenuBar/ProjectSettingsMenu.java
@@ -0,0 +1,73 @@
+package Common.UI.Menus_2023.ProjectMenuBar;
+import Common.Current;
+import Common.Global;
+import Common.UI.Menus_2023.LanguagesSubmenu;
+import Common.UI.Menus_2023.SettingsSubmenu;
+import Common.UI.Menus_2023.StylesSubmenu;
+import Common.UI.Menus_2023.VisualiserMenu;
+import GlobalData.Settings.SettingName;
+import ProjectData.Files.LanguageStyle;
+import ProjectData.LanguageName;
+
+import javax.swing.*;
+public class ProjectSettingsMenu extends VisualiserMenu {
+ JMenu mLanguage;
+ JMenu mStyle;
+ public ProjectSettingsMenu() {
+ super("Настройки проекта", "/icons/Settings.png");
+ add(mLanguage = new LanguagesSubmenu() {
+ @Override
+ public void action(LanguageName languageName) {
+ if (Current.getProject().UpdateLanguage(languageName)) {
+ Current.getSapfor().ResetAllAnalyses();
+ ShowLanguage();
+ }
+ }
+ });
+ ShowLanguage();
+ //--
+ add(mStyle = new StylesSubmenu() {
+ @Override
+ public void action(LanguageStyle languageStyle) {
+ if (Current.getProject().UpdateStyle(languageStyle))
+ ShowStyle();
+ }
+ });
+ ShowStyle();
+ addSeparator();
+ add(new SettingsSubmenu("Анализ", null,
+ SettingName.Precompilation,
+ SettingName.STATIC_SHADOW_ANALYSIS,
+ SettingName.KEEP_DVM_DIRECTIVES,
+ SettingName.IGNORE_IO_SAPFOR,
+ SettingName.MPI_PROGRAM,
+ SettingName.ANALYSIS_OPTIONS,
+ SettingName.PARALLELIZE_FREE_LOOPS
+ ));
+ addSeparator();
+ add(new SettingsSubmenu("Построение системы интервалов", null,
+ SettingName.KEEP_LOOPS_CLOSE_NESTING,
+ SettingName.KEEP_GCOV
+ ));
+ addSeparator();
+ add(new SettingsSubmenu("Построение версий", null,
+ SettingName.FREE_FORM,
+ SettingName.KEEP_SPF_DIRECTIVES,
+ SettingName.KEEP_SPF_DIRECTIVES_AMONG_TRANSFORMATIONS,
+ SettingName.OUTPUT_UPPER,
+ SettingName.MAX_SHADOW_WIDTH,
+ SettingName.DVMConvertationOptions,
+ SettingName.SaveModifications
+ ));
+ addSeparator();
+ add(Global.db.settings.get(SettingName.TRANSLATE_MESSAGES).getMenuItem());
+ add(Global.db.settings.get(SettingName.DEBUG_PRINT_ON).getMenuItem());
+ add(Global.db.settings.get(SettingName.GCOVLimit).getMenuItem());
+ }
+ public void ShowLanguage() {
+ mLanguage.setText("Язык: " + Current.getProject().languageName.getDescription());
+ }
+ public void ShowStyle() {
+ mStyle.setText("Стиль: " + Current.getProject().style.getDescription());
+ }
+}
diff --git a/src/Common/UI/Menus_2023/ProjectMenuBar/ProjectViewMenu.java b/src/Common/UI/Menus_2023/ProjectMenuBar/ProjectViewMenu.java
new file mode 100644
index 00000000..36f20823
--- /dev/null
+++ b/src/Common/UI/Menus_2023/ProjectMenuBar/ProjectViewMenu.java
@@ -0,0 +1,34 @@
+package Common.UI.Menus_2023.ProjectMenuBar;
+import Common.Current;
+import Common.UI.Menus_2023.VisualiserMenu;
+import Common.UI.Themes.VisualiserFonts;
+import Common.UI.UI;
+import Common.Utils.Utils;
+import ProjectData.ProjectView;
+
+import javax.swing.*;
+import java.util.LinkedHashMap;
+public class ProjectViewMenu extends VisualiserMenu {
+ LinkedHashMap views;
+ public ProjectViewMenu() {
+ super("", "");
+ views = new LinkedHashMap<>();
+ for (ProjectView view : ProjectView.values()) {
+ JMenuItem m = new JMenuItem(view.getDescription()) {
+ {
+ setIcon(Utils.getIcon(view.getIcon()));
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreeItalic));
+ addActionListener(e -> {
+ Current.set(Current.ProjectView, view);
+ UI.getMainWindow().getProjectWindow().ShowProjectView();
+ });
+ }
+ };
+ add(m);
+ views.put(view, m);
+ }
+ }
+ public void SelectView(ProjectView view){
+ views.get(view).doClick();
+ }
+}
diff --git a/src/Common/UI/Menus_2023/RemoteSapforsMenuBar/RemoteSapforsMenuBar.java b/src/Common/UI/Menus_2023/RemoteSapforsMenuBar/RemoteSapforsMenuBar.java
new file mode 100644
index 00000000..c3fa2b96
--- /dev/null
+++ b/src/Common/UI/Menus_2023/RemoteSapforsMenuBar/RemoteSapforsMenuBar.java
@@ -0,0 +1,11 @@
+package Common.UI.Menus_2023.RemoteSapforsMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class RemoteSapforsMenuBar extends DataMenuBar {
+ public RemoteSapforsMenuBar() {
+ super("SAPFOR", PassCode_2021.InstallRemoteSapfor,
+ PassCode_2021.AddSapfor,
+ PassCode_2021.EditSapfor,
+ PassCode_2021.DeleteSapfor);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/RunConfigurationsMenuBar/RunConfigurationsMenuBar.java b/src/Common/UI/Menus_2023/RunConfigurationsMenuBar/RunConfigurationsMenuBar.java
new file mode 100644
index 00000000..c8689e12
--- /dev/null
+++ b/src/Common/UI/Menus_2023/RunConfigurationsMenuBar/RunConfigurationsMenuBar.java
@@ -0,0 +1,13 @@
+package Common.UI.Menus_2023.RunConfigurationsMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+
+import javax.swing.*;
+public class RunConfigurationsMenuBar extends DataMenuBar {
+ public RunConfigurationsMenuBar() {
+ super("конфигурации запуска", PassCode_2021.Run,
+ PassCode_2021.AddRunConfiguration, PassCode_2021.EditRunConfiguration, PassCode_2021.DeleteRunConfiguration);
+ add(new JSeparator());
+ addPasses(PassCode_2021.EditProjectRunMaxtime);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/SapforConfigurationCommandsMenuBar/SapforConfigurationCommandsMenuBar.java b/src/Common/UI/Menus_2023/SapforConfigurationCommandsMenuBar/SapforConfigurationCommandsMenuBar.java
new file mode 100644
index 00000000..ae1e7cd1
--- /dev/null
+++ b/src/Common/UI/Menus_2023/SapforConfigurationCommandsMenuBar/SapforConfigurationCommandsMenuBar.java
@@ -0,0 +1,12 @@
+package Common.UI.Menus_2023.SapforConfigurationCommandsMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class SapforConfigurationCommandsMenuBar extends DataMenuBar {
+ public SapforConfigurationCommandsMenuBar() {
+ super("команды",
+ PassCode_2021.PublishSapforConfigurationCommand,
+ PassCode_2021.EditSapforConfigurationCommand,
+ PassCode_2021.DeleteSapforConfigurationCommand
+ );
+ }
+}
diff --git a/src/Common/UI/Menus_2023/SapforConfigurationsMenuBar/SapforConfigurationsMenuBar.java b/src/Common/UI/Menus_2023/SapforConfigurationsMenuBar/SapforConfigurationsMenuBar.java
new file mode 100644
index 00000000..abb7aa17
--- /dev/null
+++ b/src/Common/UI/Menus_2023/SapforConfigurationsMenuBar/SapforConfigurationsMenuBar.java
@@ -0,0 +1,12 @@
+package Common.UI.Menus_2023.SapforConfigurationsMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class SapforConfigurationsMenuBar extends DataMenuBar {
+ public SapforConfigurationsMenuBar() {
+ super("конфигурации", PassCode_2021.StartSapforTests,
+ PassCode_2021.PublishSapforConfiguration,
+ PassCode_2021.EditSapforConfiguration,
+ PassCode_2021.DeleteSapforConfiguration
+ );
+ }
+}
diff --git a/src/Common/UI/Menus_2023/SapforTasksMenuBar/SapforTasksMenuBar.java b/src/Common/UI/Menus_2023/SapforTasksMenuBar/SapforTasksMenuBar.java
new file mode 100644
index 00000000..537d5cb6
--- /dev/null
+++ b/src/Common/UI/Menus_2023/SapforTasksMenuBar/SapforTasksMenuBar.java
@@ -0,0 +1,8 @@
+package Common.UI.Menus_2023.SapforTasksMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class SapforTasksMenuBar extends DataMenuBar {
+ public SapforTasksMenuBar() {
+ super("задачи", PassCode_2021.OpenSapforTest);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/SapforTasksPackagesBar/SapforTasksPackagesBar.java b/src/Common/UI/Menus_2023/SapforTasksPackagesBar/SapforTasksPackagesBar.java
new file mode 100644
index 00000000..56ad5fda
--- /dev/null
+++ b/src/Common/UI/Menus_2023/SapforTasksPackagesBar/SapforTasksPackagesBar.java
@@ -0,0 +1,8 @@
+package Common.UI.Menus_2023.SapforTasksPackagesBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class SapforTasksPackagesBar extends DataMenuBar {
+ public SapforTasksPackagesBar() {
+ super("пакеты задач", PassCode_2021.DeleteSapforTasksPackage);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/SettingsSubmenu.java b/src/Common/UI/Menus_2023/SettingsSubmenu.java
new file mode 100644
index 00000000..eeccb752
--- /dev/null
+++ b/src/Common/UI/Menus_2023/SettingsSubmenu.java
@@ -0,0 +1,19 @@
+package Common.UI.Menus_2023;
+import Common.Current;
+import Common.Global;
+import Common.UI.Themes.VisualiserFonts;
+import Common.Utils.Utils;
+import GlobalData.Settings.SettingName;
+
+import javax.swing.*;
+public class SettingsSubmenu extends JMenu {
+ public SettingsSubmenu(String title, String icon, SettingName... settings) {
+ super(title);
+ if (icon != null)
+ setIcon(Utils.getIcon(icon));
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Menu));
+ for (SettingName c : settings) {
+ add(Global.db.settings.get(c).getMenuItem());
+ }
+ }
+}
diff --git a/src/Common/UI/Menus_2023/StableMenuItem.java b/src/Common/UI/Menus_2023/StableMenuItem.java
new file mode 100644
index 00000000..8bac9d47
--- /dev/null
+++ b/src/Common/UI/Menus_2023/StableMenuItem.java
@@ -0,0 +1,41 @@
+package Common.UI.Menus_2023;
+import Common.UI.Menus.VisualiserMenuItem;
+import Common.UI.UI;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.basic.BasicMenuItemUI;
+//неичезающий меню итем. нужен для настроек
+//https://translated.turbopages.org/proxy_u/en-ru.ru.64537f6c-6460c460-8e74a1ab-74722d776562/https/tips4java.wordpress.com/2010/09/12/keeping-menus-open/
+class StableItemUI extends BasicMenuItemUI {
+ public static ComponentUI createUI(JComponent c) {
+ return new StableItemUI();
+ }
+ @Override
+ protected void doClick(MenuSelectionManager msm) {
+ menuItem.doClick(0);
+ if (UI.last_menu_path != null)
+ MenuSelectionManager.defaultManager().setSelectedPath(UI.last_menu_path);
+ }
+}
+public class StableMenuItem extends VisualiserMenuItem {
+ {
+ getModel().addChangeListener(e -> {
+ if (getModel().isArmed() && isShowing())
+ UI.last_menu_path = MenuSelectionManager.defaultManager().getSelectedPath();
+ });
+ }
+ public StableMenuItem(String text) {
+ super(text);
+ setUI(new StableItemUI());
+ }
+ public StableMenuItem(String text, String icon_path) {
+ super(text);
+ setIcon(Utils.getIcon(icon_path));
+ setUI(new StableItemUI());
+ }
+ public StableMenuItem() {
+ setUI(new StableItemUI());
+ }
+}
diff --git a/src/Common/UI/Menus_2023/StablePassMenuItem.java b/src/Common/UI/Menus_2023/StablePassMenuItem.java
new file mode 100644
index 00000000..1474b20e
--- /dev/null
+++ b/src/Common/UI/Menus_2023/StablePassMenuItem.java
@@ -0,0 +1,16 @@
+package Common.UI.Menus_2023;
+import Common.Utils.Utils;
+import Visual_DVM_2021.Passes.Pass_2021;
+public class StablePassMenuItem extends StableMenuItem implements PassControl {
+ @Override
+ public void setIcon(String icon_path) {
+ setIcon(Utils.getIcon(icon_path));
+ }
+ public StablePassMenuItem(Pass_2021 pass) {
+ setText(pass.getDescription());
+ setToolTipText(pass.getDescription());
+ if (pass.getIconPath() != null) setIcon(pass.getIconPath());
+ addActionListener(pass.getControlAction());
+ pass.controls.add(this);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/StylesSubmenu.java b/src/Common/UI/Menus_2023/StylesSubmenu.java
new file mode 100644
index 00000000..0dda3ec0
--- /dev/null
+++ b/src/Common/UI/Menus_2023/StylesSubmenu.java
@@ -0,0 +1,25 @@
+package Common.UI.Menus_2023;
+import ProjectData.Files.LanguageStyle;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+public abstract class StylesSubmenu extends VisualiserMenu {
+ public StylesSubmenu() {
+ this("Стиль");
+ }
+ public StylesSubmenu(String text) {
+ super(text, "/icons/Style.png", true);
+ for (LanguageStyle languageStyle : LanguageStyle.values()) {
+ JMenuItem m = new StableMenuItem(languageStyle.getDescription());
+ m.addActionListener(
+ new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ action(languageStyle);
+ }
+ });
+ add(m);
+ }
+ }
+ public abstract void action(LanguageStyle languageStyle);
+}
diff --git a/src/Common/UI/Menus_2023/SubscribersMenuBar/SubscribersMenuBar.java b/src/Common/UI/Menus_2023/SubscribersMenuBar/SubscribersMenuBar.java
new file mode 100644
index 00000000..0c0edb5e
--- /dev/null
+++ b/src/Common/UI/Menus_2023/SubscribersMenuBar/SubscribersMenuBar.java
@@ -0,0 +1,13 @@
+package Common.UI.Menus_2023.SubscribersMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class SubscribersMenuBar extends DataMenuBar {
+ public SubscribersMenuBar() {
+ super("Адресаты",
+ PassCode_2021.SaveBugReportExecutor,
+ PassCode_2021.SaveBugReportRecipients,
+ PassCode_2021.AddSubscriber,
+ PassCode_2021.EditSubscriber,
+ PassCode_2021.DeleteSubscriber);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/TasksPackagesMenuBar/TasksPackagesMenuBar.java b/src/Common/UI/Menus_2023/TasksPackagesMenuBar/TasksPackagesMenuBar.java
new file mode 100644
index 00000000..b5407024
--- /dev/null
+++ b/src/Common/UI/Menus_2023/TasksPackagesMenuBar/TasksPackagesMenuBar.java
@@ -0,0 +1,51 @@
+package Common.UI.Menus_2023.TasksPackagesMenuBar;
+import Common.Current;
+import Common.UI.Menus_2023.DataMenuBar;
+import Common.UI.Menus_2023.MenuBarButton;
+import Common.UI.Themes.VisualiserFonts;
+import Common.UI.UI;
+import Common.Utils.Utils;
+import TestingSystem.TestingServer;
+import Visual_DVM_2021.Passes.PassCode_2021;
+
+import javax.swing.*;
+import java.awt.*;
+public class TasksPackagesMenuBar extends DataMenuBar {
+ JButton autorefreshButton;
+ JSpinner sCheckTime;
+ public TasksPackagesMenuBar() {
+ super("пакеты задач", PassCode_2021.SynchronizeTestsTasks, PassCode_2021.AbortSelectedPackages);
+ add(autorefreshButton = new MenuBarButton() {
+ {
+ setText("проверка раз в");
+ setToolTipText("автоматическое обновление состояния пакета задач");
+ Mark();
+ addActionListener(e -> {
+ TestingServer.checkTasks = !TestingServer.checkTasks;
+ TestingServer.switchTimer(TestingServer.checkTasks);
+ Mark();
+ });
+ }
+ public void Mark() {
+ setIcon(Utils.getIcon(TestingServer.checkTasks ? "/icons/Pick.png" : "/icons/NotPick.png"));
+ }
+ });
+ add(sCheckTime = new JSpinner());
+ sCheckTime.setPreferredSize(new Dimension(60, 26));
+ sCheckTime.setMaximumSize(new Dimension(60, 26));
+ sCheckTime.setModel(new SpinnerNumberModel(TestingServer.checkIntervalSecond, 10, 3600, 1));
+ UI.MakeSpinnerRapid(sCheckTime, e -> {
+ TestingServer.checkIntervalSecond = (int) sCheckTime.getValue();
+ if (TestingServer.checkTasks) TestingServer.ResetTimer();
+ });
+ add(new JLabel(" сек") {
+ {
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreeItalic));
+ }
+ });
+ }
+
+ public void ShowAutorefresh() {
+ autorefreshButton.setIcon(Utils.getIcon(TestingServer.checkTasks ? "/icons/Pick.png" : "/icons/NotPick.png"));
+ }
+}
diff --git a/src/Common/UI/Menus_2023/TestRunTasksMenuBar/TestRunTasksMenuBar.java b/src/Common/UI/Menus_2023/TestRunTasksMenuBar/TestRunTasksMenuBar.java
new file mode 100644
index 00000000..7aed90cc
--- /dev/null
+++ b/src/Common/UI/Menus_2023/TestRunTasksMenuBar/TestRunTasksMenuBar.java
@@ -0,0 +1,22 @@
+package Common.UI.Menus_2023.TestRunTasksMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+
+import javax.swing.*;
+public class TestRunTasksMenuBar extends DataMenuBar {
+ JMenuBar filters= null;
+ public void DropFilters() {
+ if (filters != null) {
+ remove(filters);
+ filters = null;
+ }
+ revalidate();
+ repaint();
+ }
+ public void addFilters(JMenu cFilterMenu, JMenu rFilterMenu) {
+ filters= addMenus(cFilterMenu, rFilterMenu);
+ }
+ public TestRunTasksMenuBar() {
+ super("задачи", PassCode_2021.DownloadTaskTest);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/TestsMenuBar/TestsMenuBar.java b/src/Common/UI/Menus_2023/TestsMenuBar/TestsMenuBar.java
new file mode 100644
index 00000000..fb782f41
--- /dev/null
+++ b/src/Common/UI/Menus_2023/TestsMenuBar/TestsMenuBar.java
@@ -0,0 +1,12 @@
+package Common.UI.Menus_2023.TestsMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class TestsMenuBar extends DataMenuBar {
+ public TestsMenuBar() {
+ super("тесты",
+ PassCode_2021.DownloadTest,
+ PassCode_2021.PublishTest,
+ PassCode_2021.EditTest,
+ PassCode_2021.DeleteSelectedTests);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/TypesSubmenu.java b/src/Common/UI/Menus_2023/TypesSubmenu.java
new file mode 100644
index 00000000..c81b6ca0
--- /dev/null
+++ b/src/Common/UI/Menus_2023/TypesSubmenu.java
@@ -0,0 +1,26 @@
+package Common.UI.Menus_2023;
+import ProjectData.Files.FileType;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+public abstract class TypesSubmenu extends VisualiserMenu {
+ public TypesSubmenu() {
+ this("Тип");
+ }
+ public TypesSubmenu(String text) {
+ super(text, "/icons/type.png", true);
+ for (FileType fileType : FileType.values()) {
+ if (fileType != FileType.forbidden) {
+ JMenuItem m = new StableMenuItem(fileType.getDescription());
+ m.addActionListener(new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ action(fileType);
+ }
+ });
+ add(m);
+ }
+ }
+ }
+ public abstract void action(FileType fileType);
+}
diff --git a/src/Common/UI/Menus_2023/UsersMenuBar/UsersMenuBar.java b/src/Common/UI/Menus_2023/UsersMenuBar/UsersMenuBar.java
new file mode 100644
index 00000000..d57fb2cf
--- /dev/null
+++ b/src/Common/UI/Menus_2023/UsersMenuBar/UsersMenuBar.java
@@ -0,0 +1,11 @@
+package Common.UI.Menus_2023.UsersMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class UsersMenuBar extends DataMenuBar {
+ public UsersMenuBar() {
+ super("пользователи", PassCode_2021.AddUser,
+ PassCode_2021.EditUser,
+ PassCode_2021.InitialiseUser,
+ PassCode_2021.DeleteUser);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/VariantsMenuBar/VariantsMenuBar.java b/src/Common/UI/Menus_2023/VariantsMenuBar/VariantsMenuBar.java
new file mode 100644
index 00000000..a28bbf92
--- /dev/null
+++ b/src/Common/UI/Menus_2023/VariantsMenuBar/VariantsMenuBar.java
@@ -0,0 +1,28 @@
+package Common.UI.Menus_2023.VariantsMenuBar;
+import Common.UI.Menus.VisualiserMenuItem;
+import Common.UI.Menus_2023.DataMenuBar;
+import Common.UI.Menus_2023.VisualiserMenu;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+public class VariantsMenuBar extends DataMenuBar {
+ public VariantsMenuBar() {
+ super("варианты");
+ addMenus(new VisualiserMenu("Отображение параллельных вариантов",
+ "/icons/ShowPassword.png") {
+ {
+ add(new VisualiserMenuItem("Все варианты") {
+ {
+ addActionListener(e -> Pass_2021.passes.get(PassCode_2021.GenerateParallelVariants).Do(true));
+ }
+ });
+ add(new VisualiserMenuItem("Минимальное покрытие вариантов") {
+ {
+ addActionListener(e -> Pass_2021.passes.get(PassCode_2021.GenerateParallelVariants).Do(false));
+ }
+ });
+ }
+ ;
+ });
+ addPasses(PassCode_2021.PredictParallelVariants, PassCode_2021.CreateParallelVariants);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/VersionsMenuBar/VersionsMenuBar.java b/src/Common/UI/Menus_2023/VersionsMenuBar/VersionsMenuBar.java
new file mode 100644
index 00000000..f436acd1
--- /dev/null
+++ b/src/Common/UI/Menus_2023/VersionsMenuBar/VersionsMenuBar.java
@@ -0,0 +1,8 @@
+package Common.UI.Menus_2023.VersionsMenuBar;
+import Common.UI.Menus_2023.VisualiserMenuBar;
+import Visual_DVM_2021.Passes.PassCode_2021;
+public class VersionsMenuBar extends VisualiserMenuBar {
+ public VersionsMenuBar(){
+ addPasses(PassCode_2021.CreateTestsGroupFromSelectedVersions);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/VisualiserMenu.java b/src/Common/UI/Menus_2023/VisualiserMenu.java
new file mode 100644
index 00000000..e7eae0fa
--- /dev/null
+++ b/src/Common/UI/Menus_2023/VisualiserMenu.java
@@ -0,0 +1,21 @@
+package Common.UI.Menus_2023;
+import Common.Current;
+import Common.UI.Themes.VisualiserFonts;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+import java.awt.*;
+public class VisualiserMenu extends JMenu {
+ public VisualiserMenu(String text, String iconPath, boolean textVisible) {
+ setMinimumSize(new Dimension(38, 30)); //иначе сужаются вертикально.
+ setToolTipText(text);
+ if (textVisible)
+ setText(text);
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreeItalic));
+ if (!iconPath.isEmpty())
+ setIcon(Utils.getIcon(iconPath));
+ }
+ public VisualiserMenu(String text, String iconPath) {
+ this(text, iconPath, false);
+ }
+}
diff --git a/src/Common/UI/Menus_2023/VisualiserMenuBar.java b/src/Common/UI/Menus_2023/VisualiserMenuBar.java
new file mode 100644
index 00000000..036bd01e
--- /dev/null
+++ b/src/Common/UI/Menus_2023/VisualiserMenuBar.java
@@ -0,0 +1,31 @@
+package Common.UI.Menus_2023;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+
+import javax.swing.*;
+import java.awt.*;
+//https://java-online.ru/swing-menu.xhtml
+public class VisualiserMenuBar extends JToolBar {
+ public VisualiserMenuBar() {
+ setFloatable(false);
+ setSizeLimits();
+ }
+ public void addPasses(PassCode_2021... codes) {
+ //- кнопки. связать их с проходами. (!)
+ for (PassCode_2021 code : codes)
+ add(Pass_2021.passes.get(code).createButton());
+ }
+ public JMenuBar addMenus(JMenu... menus) {
+ JMenuBar bar = new JMenuBar() {
+ {
+ for (JMenu menu : menus)
+ add(menu);
+ }
+ };
+ add(bar);
+ return bar;
+ }
+ public void setSizeLimits() {
+ setPreferredSize(new Dimension(0, 30));
+ }
+}
diff --git a/src/Common/UI/ProgressBar/StyledProgressBar.java b/src/Common/UI/ProgressBar/StyledProgressBar.java
new file mode 100644
index 00000000..00895232
--- /dev/null
+++ b/src/Common/UI/ProgressBar/StyledProgressBar.java
@@ -0,0 +1,16 @@
+package Common.UI.ProgressBar;
+import Common.Current;
+import Common.UI.Themes.ThemeElement;
+
+import javax.swing.*;
+public class StyledProgressBar extends JProgressBar implements ThemeElement {
+ public StyledProgressBar() {
+ setStringPainted(true);
+ applyTheme();
+ }
+ @Override
+ public void applyTheme() {
+ setBackground(Current.getTheme().bar_background);
+ setForeground(Current.getTheme().bar_foreground);
+ }
+}
diff --git a/src/Common/UI/Selectable.java b/src/Common/UI/Selectable.java
new file mode 100644
index 00000000..b113c4dd
--- /dev/null
+++ b/src/Common/UI/Selectable.java
@@ -0,0 +1,38 @@
+package Common.UI;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+public interface Selectable {
+ boolean isSelected();
+ default void Select(boolean flag) {
+ if (isSelectionEnabled())
+ select(flag);
+ }
+ void select(boolean flag);
+ //-
+ default ImageIcon GetSelectionIcon() {
+ return
+ isSelectionEnabled() ?
+ Utils.getIcon("/icons/" + (isSelected() ? "Pick" : "NotPick") + ".png") :
+ GetDisabledIcon();
+ }
+ default ImageIcon GetDisabledIcon() {
+ return Utils.getIcon("/icons/Arrays/Unknown.png");
+ }
+ default void SwitchSelection() {
+ Select(!isSelected());
+ }
+ //строчный контент для передачи параметров проходам.
+ default String getSelectionContent() {
+ return toString();
+ }
+ //-
+ default String getSelectionText() {
+ return toString();
+ }
+ default boolean isSelectionEnabled() {
+ return true;
+ }
+ default void SelectAllChildren(boolean select) {
+ }
+}
diff --git a/src/Common/UI/StatusEnum.java b/src/Common/UI/StatusEnum.java
new file mode 100644
index 00000000..e6085209
--- /dev/null
+++ b/src/Common/UI/StatusEnum.java
@@ -0,0 +1,13 @@
+package Common.UI;
+import Common.Current;
+import Common.UI.Themes.VisualiserFonts;
+
+import java.awt.*;
+public interface StatusEnum {
+ default Font getFont() {
+ return Current.getTheme().Fonts.get(VisualiserFonts.UnknownState);
+ }
+ default String getDescription() {
+ return toString();
+ }
+}
diff --git a/src/Common/UI/Tables/ColumnFilter.java b/src/Common/UI/Tables/ColumnFilter.java
new file mode 100644
index 00000000..7b33ba63
--- /dev/null
+++ b/src/Common/UI/Tables/ColumnFilter.java
@@ -0,0 +1,78 @@
+package Common.UI.Tables;
+import Common.Database.DataSet;
+import Common.UI.TextField.StyledTextField;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+import javax.swing.border.MatteBorder;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+public class ColumnFilter {
+ public JTextField textField;
+ public JPopupMenu popup;
+ public ColumnFilter(DataSet dataSet, int columnIndex) {
+ textField = new StyledTextField() {
+ {
+ setBorder(null);
+ addActionListener(e -> {
+ popup.setVisible(false);
+ dataSet.ui_.control.getTableHeader().repaint();
+ });
+ getDocument().addDocumentListener(new DocumentListener() {
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ dataSet.changeColumnFilterValue(columnIndex, getText());
+ dataSet.ShowUI();
+ }
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ dataSet.changeColumnFilterValue(columnIndex, getText());
+ dataSet.ShowUI();
+ }
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ }
+ });
+ }
+ };
+ popup = new JPopupMenu() {
+ {
+ setBorder(new MatteBorder(0, 1, 1, 1, Color.DARK_GRAY));
+ }
+ };
+ popup.add(textField);
+ //--
+ dataSet.getUi().control.getColumnModel().getColumn(columnIndex).setHeaderRenderer((table, value, isSelected, hasFocus, row, column1) -> new JLabel() {
+ {
+ setIcon(Utils.getIcon("/icons/Filter.png"));
+ setForeground(dataSet.getUi().control.getTableHeader().getForeground());
+ setBackground(dataSet.getUi().control.getTableHeader().getBackground());
+ setFont(dataSet.getUi().control.getTableHeader().getFont());
+ setBorder(new MatteBorder(0, 0, 1, 1, Color.DARK_GRAY));
+ setText("текст : "+dataSet.getColumnFilterValue(columnIndex));
+ }
+ });
+ //--
+ dataSet.getUi().control.getTableHeader().addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent event) {
+ if (event.getClickCount() == 1) {
+ int columnIndex = dataSet.getUi().control.getTableHeader().columnAtPoint(event.getPoint());
+ if (dataSet.columnsFilters.containsKey(columnIndex)) {
+ Rectangle columnRectangle = dataSet.getUi().control.getTableHeader().getHeaderRect(columnIndex);
+ Dimension d = new Dimension(columnRectangle.width - 72, columnRectangle.height - 1);
+ popup.setPreferredSize(d);
+ popup.setMaximumSize(d);
+ popup.show(dataSet.getUi().control.getTableHeader(), columnRectangle.x + 72, 0);
+ textField.setText(dataSet.getColumnFilterValue(columnIndex).toString());
+ textField.requestFocusInWindow();
+ textField.selectAll();
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/src/Common/UI/Tables/ColumnInfo.java b/src/Common/UI/Tables/ColumnInfo.java
new file mode 100644
index 00000000..76d2f71a
--- /dev/null
+++ b/src/Common/UI/Tables/ColumnInfo.java
@@ -0,0 +1,94 @@
+package Common.UI.Tables;
+import Common.Utils.Utils;
+public class ColumnInfo {
+ private String Name = "?";
+ private boolean visible = true;
+ private boolean editable = false;
+ private TableRenderers renderer = TableRenderers.RendererDefault;
+ private TableEditors editor = TableEditors.EditorDefault;
+ private int maxWidth = Utils.Nan;
+ private int minWidth = Utils.Nan;
+ //private int lastWidth = Utils.Nan;
+ // public void setLastWidth(int width_in) {
+ // lastWidth = width_in;
+ // }
+ // public int getLastWidth() {
+ // return lastWidth;
+ // }
+ public ColumnInfo(String name_in) {
+ setName(name_in);
+ }
+ public ColumnInfo(String name_in, TableRenderers renderer_in, TableEditors editor_in) {
+ setName(name_in);
+ setRenderer(renderer_in);
+ setEditable(true);
+ setEditor(editor_in);
+ }
+ public ColumnInfo(String name_in, TableRenderers renderer_in) {
+ setName(name_in);
+ setRenderer(renderer_in);
+ }
+ public String getName() {
+ return Name;
+ }
+ public void setName(String name_in) {
+ Name = name_in;
+ }
+ public boolean isVisible() {
+ return visible;
+ }
+ public void setVisible(boolean visible_in) {
+ this.visible = visible_in;
+ }
+ public boolean isEditable() {
+ return editable;
+ }
+ public void setEditable(boolean editable_in) {
+ this.editable = editable_in;
+ }
+ public TableRenderers getRenderer() {
+ return renderer;
+ }
+ public void setRenderer(TableRenderers renderer_in) {
+ this.renderer = renderer_in;
+ }
+ public TableEditors getEditor() {
+ return editor;
+ }
+ public void setEditor(TableEditors editor_in) {
+ this.editor = editor_in;
+ setEditable(editor != TableEditors.EditorDefault);
+ }
+ public boolean hasRenderer() {
+ return getRenderer() != TableRenderers.RendererDefault;
+ }
+ public boolean hasEditor() {
+ return getEditor() != TableEditors.EditorDefault;
+ }
+ public int getMaxWidth() {
+ return maxWidth;
+ }
+ public void setMaxWidth(int maxWidth_in) {
+ this.maxWidth = maxWidth_in;
+ }
+ public boolean hasMaxWidth() {
+ return maxWidth != Utils.Nan;
+ }
+ //-
+ public int getMinWidth() {
+ return minWidth;
+ }
+ public void setMinWidth(int minWidth_in) {
+ this.minWidth = minWidth_in;
+ }
+ public boolean hasMinWidth() {
+ return minWidth != Utils.Nan;
+ }
+
+/*
+ public boolean hasLastWidth() {
+ return lastWidth != Utils.Nan;
+ }
+ */
+ //-
+}
diff --git a/src/Common/UI/Tables/DBObjectEditor.java b/src/Common/UI/Tables/DBObjectEditor.java
new file mode 100644
index 00000000..2aea8d2b
--- /dev/null
+++ b/src/Common/UI/Tables/DBObjectEditor.java
@@ -0,0 +1,88 @@
+package Common.UI.Tables;
+import Common.Database.DBObject;
+import Common.UI.DataControl;
+
+import javax.swing.*;
+import javax.swing.event.CellEditorListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.table.TableCellEditor;
+import java.awt.*;
+import java.util.EventObject;
+import java.util.Objects;
+public abstract class DBObjectEditor extends EditorCell implements TableCellEditor {
+ //задается при редактировании клетки.
+ public T value = null;
+ protected transient ChangeEvent changeEvent;
+ public abstract void Action();
+ public void InitValue(JTable table, Object value_in, int row, int column) {
+ value = (T) ((DataControl) table).getRowObject(row);
+ }
+ @Override
+ public Component getTableCellEditorComponent(
+ JTable table, Object value_in, boolean isSelected, int row, int column) {
+ this.setBackground(table.getSelectionBackground());
+ InitValue(table, value_in, row, column);
+ Action();
+ return this;
+ }
+ //Copied from AbstractCellEditor
+ //protected EventListenerList listenerList = new EventListenerList();
+ @Override
+ public boolean isCellEditable(EventObject e) {
+ return true;
+ }
+ @Override
+ public boolean shouldSelectCell(EventObject anEvent) {
+ return true;
+ }
+ @Override
+ public boolean stopCellEditing() {
+ fireEditingStopped();
+ return true;
+ }
+ @Override
+ public void cancelCellEditing() {
+ fireEditingCanceled();
+ }
+ @Override
+ public void addCellEditorListener(CellEditorListener l) {
+ listenerList.add(CellEditorListener.class, l);
+ }
+ @Override
+ public void removeCellEditorListener(CellEditorListener l) {
+ listenerList.remove(CellEditorListener.class, l);
+ }
+ public CellEditorListener[] getCellEditorListeners() {
+ return listenerList.getListeners(CellEditorListener.class);
+ }
+ protected void fireEditingStopped() {
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length - 2; i >= 0; i -= 2) {
+ if (listeners[i] == CellEditorListener.class) {
+ // Lazily create the event:
+ if (Objects.isNull(changeEvent)) {
+ changeEvent = new ChangeEvent(this);
+ }
+ ((CellEditorListener) listeners[i + 1]).editingStopped(changeEvent);
+ }
+ }
+ }
+ protected void fireEditingCanceled() {
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length - 2; i >= 0; i -= 2) {
+ if (listeners[i] == CellEditorListener.class) {
+ // Lazily create the event:
+ if (Objects.isNull(changeEvent)) {
+ changeEvent = new ChangeEvent(this);
+ }
+ ((CellEditorListener) listeners[i + 1]).editingCanceled(changeEvent);
+ }
+ }
+ }
+}
diff --git a/src/Common/UI/Tables/DBObjectRenderer.java b/src/Common/UI/Tables/DBObjectRenderer.java
new file mode 100644
index 00000000..1af0e5ac
--- /dev/null
+++ b/src/Common/UI/Tables/DBObjectRenderer.java
@@ -0,0 +1,11 @@
+package Common.UI.Tables;
+import Common.Database.DBObject;
+import Common.UI.DataControl;
+
+import javax.swing.*;
+public abstract class DBObjectRenderer extends RendererCell {
+ @Override
+ public DBObject Init(JTable table, Object value, int row, int column) {
+ return ((DataControl) table).getRowObject(row);
+ }
+}
\ No newline at end of file
diff --git a/src/Common/UI/Tables/DBObjectSelectionRenderer.java b/src/Common/UI/Tables/DBObjectSelectionRenderer.java
new file mode 100644
index 00000000..b83afe20
--- /dev/null
+++ b/src/Common/UI/Tables/DBObjectSelectionRenderer.java
@@ -0,0 +1,14 @@
+package Common.UI.Tables;
+public class DBObjectSelectionRenderer extends DBObjectRenderer {
+ /*
+ @Override
+ public Dimension getMinimumSize() {
+ return new Dimension(25,25);
+ }
+ */
+ @Override
+ public void Display() {
+ if (value != null)
+ setIcon(value.GetSelectionIcon());
+ }
+}
diff --git a/src/Common/UI/Tables/DBObjectSelector.java b/src/Common/UI/Tables/DBObjectSelector.java
new file mode 100644
index 00000000..b7c235de
--- /dev/null
+++ b/src/Common/UI/Tables/DBObjectSelector.java
@@ -0,0 +1,13 @@
+package Common.UI.Tables;
+import Common.Database.DBObject;
+public class DBObjectSelector extends DBObjectEditor {
+ @Override
+ public void Action() {
+ value.SwitchSelection();
+ setIcon(value.GetSelectionIcon());
+ }
+ @Override
+ public Object getCellEditorValue() {
+ return value.isSelected();
+ }
+}
diff --git a/src/Common/UI/Tables/DataTable.java b/src/Common/UI/Tables/DataTable.java
new file mode 100644
index 00000000..43b2d0c0
--- /dev/null
+++ b/src/Common/UI/Tables/DataTable.java
@@ -0,0 +1,64 @@
+package Common.UI.Tables;
+import Common.Database.DBObject;
+import Common.UI.DataControl;
+
+import javax.swing.table.AbstractTableModel;
+public abstract class DataTable extends StyledTable implements DataControl {
+ public DataTable(AbstractTableModel model) {
+ super(model);
+ }
+ @Override
+ public void SelectRowByPK(Object pk) {
+ for (int i = 0; i < getRowCount(); ++i) {
+ DBObject o = getRowObject(i);
+ if (o!=null) {
+ if (o.getPK()
+ .equals(pk)) {
+ SelectRow(i);
+ scrollToVisible(i, 0);
+ return;
+ }
+ }
+ }
+ }
+ //-------------------------------
+ /*
+ public void SelectRow(int r) {
+ getSelectionModel().setSelectionInterval(r, r);
+ }
+ public Object getRowKey(int r) {
+ return getValueAt(r, 0);
+ }
+ public DBObject getRowObject(int row) {
+ return (DBObject) getGrid().getDataSource().get(getRowKey(row));
+ }
+ //-------------------------------
+
+ public int getRowByKey(Object key) {
+ for (int i = 0; i < getRowCount(); ++i) {
+ if (getRowKey(i).equals(key)) return i;
+ }
+ return -1;
+ }
+ public void SelectRowByKey(Object key) {
+ int r = getRowByKey(key);
+ if (r >= 0)
+ SelectRow(r);
+ }
+ public void ClearSelectionSync() {
+ events_on = false;
+ getSelectionModel().clearSelection();
+ current_row_i = Utils.Nan;
+ events_on = true;
+ }
+ public void SelectRowByKeySync(Object key) {
+ int r = getRowByKey(key);
+ events_on = false;
+ if (r >= 0)
+ SelectRow(r);
+ events_on = true;
+ current_row_i = r;
+ }
+
+ */
+}
diff --git a/src/Common/UI/Tables/DateRenderer_.java b/src/Common/UI/Tables/DateRenderer_.java
new file mode 100644
index 00000000..6c432062
--- /dev/null
+++ b/src/Common/UI/Tables/DateRenderer_.java
@@ -0,0 +1,18 @@
+package Common.UI.Tables;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+import java.util.Date;
+//название пересекается с встроенным классом поэтому подчеркивание.
+public class DateRenderer_ extends RendererCell {
+ private static final Date zero = new Date(0);
+ @Override
+ public Date Init(JTable table, Object value, int row, int column) {
+ return (Date) value;
+ }
+ @Override
+ public void Display() {
+ if (value != null)
+ setText(value.equals(zero) ? "нет" : Utils.print_date(value));
+ }
+}
diff --git a/src/Common/UI/Tables/EditableHeaderRenderer.java b/src/Common/UI/Tables/EditableHeaderRenderer.java
new file mode 100644
index 00000000..2264a369
--- /dev/null
+++ b/src/Common/UI/Tables/EditableHeaderRenderer.java
@@ -0,0 +1,82 @@
+package Common.UI.Tables;
+import javax.swing.*;
+import javax.swing.table.JTableHeader;
+import javax.swing.table.TableCellRenderer;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+public class EditableHeaderRenderer implements TableCellRenderer {
+ private JTable table = null;
+ private MouseEventReposter reporter = null;
+ private JComponent editor;
+ public EditableHeaderRenderer(JComponent editor) {
+ this.editor = editor;
+ this.editor.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
+ }
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
+ if (table != null && this.table != table) {
+ this.table = table;
+ final JTableHeader header = table.getTableHeader();
+ if (header != null) {
+ this.editor.setForeground(header.getForeground());
+ this.editor.setBackground(header.getBackground());
+ this.editor.setFont(header.getFont());
+ reporter = new MouseEventReposter(header, col, this.editor);
+ header.addMouseListener(reporter);
+ }
+ }
+ if (reporter != null) reporter.setColumn(col);
+ return this.editor;
+ }
+ static public class MouseEventReposter extends MouseAdapter {
+ private Component dispatchComponent;
+ private JTableHeader header;
+ private int column = -1;
+ private Component editor;
+ public MouseEventReposter(JTableHeader header, int column, Component editor) {
+ this.header = header;
+ this.column = column;
+ this.editor = editor;
+ }
+ public void setColumn(int column) {
+ this.column = column;
+ }
+ private void setDispatchComponent(MouseEvent e) {
+ int col = header.getTable().columnAtPoint(e.getPoint());
+ if (col != column || col == -1) return;
+ Point p = e.getPoint();
+ Point p2 = SwingUtilities.convertPoint(header, p, editor);
+ dispatchComponent = SwingUtilities.getDeepestComponentAt(editor, p2.x, p2.y);
+ }
+ private boolean repostEvent(MouseEvent e) {
+ if (dispatchComponent == null) {
+ return false;
+ }
+ MouseEvent e2 = SwingUtilities.convertMouseEvent(header, e, dispatchComponent);
+ dispatchComponent.dispatchEvent(e2);
+ return true;
+ }
+ @Override
+ public void mousePressed(MouseEvent e) {
+ if (header.getResizingColumn() == null) {
+ Point p = e.getPoint();
+ int col = header.getTable().columnAtPoint(p);
+ if (col != column || col == -1) return;
+ int index = header.getColumnModel().getColumnIndexAtX(p.x);
+ if (index == -1) return;
+ editor.setBounds(header.getHeaderRect(index));
+ header.add(editor);
+ editor.validate();
+ setDispatchComponent(e);
+ repostEvent(e);
+ }
+ }
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ repostEvent(e);
+ dispatchComponent = null;
+ header.remove(editor);
+ }
+ }
+}
diff --git a/src/Common/UI/Tables/EditorCell.java b/src/Common/UI/Tables/EditorCell.java
new file mode 100644
index 00000000..85c3b881
--- /dev/null
+++ b/src/Common/UI/Tables/EditorCell.java
@@ -0,0 +1,7 @@
+package Common.UI.Tables;
+import java.awt.*;
+public class EditorCell extends StyledCellLabel {
+ public EditorCell() {
+ setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ }
+}
diff --git a/src/Common/UI/Tables/Grid/GridAnchestor.java b/src/Common/UI/Tables/Grid/GridAnchestor.java
new file mode 100644
index 00000000..05f7c73e
--- /dev/null
+++ b/src/Common/UI/Tables/Grid/GridAnchestor.java
@@ -0,0 +1,28 @@
+package Common.UI.Tables.Grid;
+import javax.swing.table.AbstractTableModel;
+import java.util.Collection;
+import java.util.Vector;
+public abstract class GridAnchestor extends AbstractTableModel {
+ public Vector data = new Vector<>();
+ protected Vector columnNames = new Vector<>(); //массив имен столбцов.
+ public GridAnchestor(Collection columnNames_in, Collection data_in) {
+ columnNames.addAll(columnNames_in);
+ data.addAll(data_in);
+ }
+ @Override
+ public String getColumnName(int col) {
+ return columnNames.get(col);
+ }
+ @Override
+ public int getColumnCount() {
+ return columnNames.size();
+ }
+ @Override
+ public int getRowCount() {
+ return data.size();
+ }
+ @Override
+ public Class getColumnClass(int column) {
+ return getValueAt(0, column).getClass();
+ }
+}
diff --git a/src/Common/UI/Tables/HiddenListRenderer.java b/src/Common/UI/Tables/HiddenListRenderer.java
new file mode 100644
index 00000000..23e185cd
--- /dev/null
+++ b/src/Common/UI/Tables/HiddenListRenderer.java
@@ -0,0 +1,17 @@
+package Common.UI.Tables;
+import Common.Current;
+import Common.UI.Themes.VisualiserFonts;
+
+import javax.swing.*;
+import java.util.Vector;
+public class HiddenListRenderer extends RendererCell> {
+ @Override
+ public Vector Init(JTable table, Object value, int row, int column) {
+ return (Vector) value;
+ }
+ @Override
+ public void Display() {
+ setText(String.join(";", value));
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreePlain));
+ }
+}
diff --git a/src/Common/UI/Tables/HyperlinksRenderer.java b/src/Common/UI/Tables/HyperlinksRenderer.java
new file mode 100644
index 00000000..6856748d
--- /dev/null
+++ b/src/Common/UI/Tables/HyperlinksRenderer.java
@@ -0,0 +1,15 @@
+package Common.UI.Tables;
+import Common.UI.List.HyperlinksStyledList;
+
+import javax.swing.*;
+import javax.swing.table.TableCellRenderer;
+import java.awt.*;
+import java.util.Vector;
+public class HyperlinksRenderer extends HyperlinksStyledList implements TableCellRenderer {
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+ setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
+ setListData((Vector) value);
+ return this;
+ }
+}
diff --git a/src/Common/UI/Tables/MaskedIntegerValueRenderer.java b/src/Common/UI/Tables/MaskedIntegerValueRenderer.java
new file mode 100644
index 00000000..25af520f
--- /dev/null
+++ b/src/Common/UI/Tables/MaskedIntegerValueRenderer.java
@@ -0,0 +1,18 @@
+package Common.UI.Tables;
+import javax.swing.*;
+public class MaskedIntegerValueRenderer extends RendererCell {
+ @Override
+ public Long Init(JTable table, Object value, int row, int column) {
+ return (Long) value;
+ }
+ public long getMask() {
+ return -1;
+ }
+ public String getMaskText() {
+ return " — ";
+ }
+ public void Display() {
+ if (value != null)
+ setText(value.equals((getMask())) ? getMaskText() : String.valueOf(value));
+ }
+}
diff --git a/src/Common/UI/Tables/MultilineRenderer.java b/src/Common/UI/Tables/MultilineRenderer.java
new file mode 100644
index 00000000..e4785f42
--- /dev/null
+++ b/src/Common/UI/Tables/MultilineRenderer.java
@@ -0,0 +1,16 @@
+package Common.UI.Tables;
+import Common.UI.List.StyledList;
+
+import javax.swing.*;
+import javax.swing.table.TableCellRenderer;
+import java.awt.*;
+import java.util.Vector;
+public class MultilineRenderer extends StyledList implements TableCellRenderer {
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+ setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
+ setListData((Vector) value);
+ return this;
+ }
+}
+
diff --git a/src/Common/UI/Tables/ProgressBarRenderer.java b/src/Common/UI/Tables/ProgressBarRenderer.java
new file mode 100644
index 00000000..ad1c44ba
--- /dev/null
+++ b/src/Common/UI/Tables/ProgressBarRenderer.java
@@ -0,0 +1,15 @@
+package Common.UI.Tables;
+import Common.UI.ProgressBar.StyledProgressBar;
+
+import javax.swing.*;
+import javax.swing.table.TableCellRenderer;
+public class ProgressBarRenderer extends StyledProgressBar implements TableCellRenderer {
+ @Override
+ public java.awt.Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+ setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
+ setValue((Integer) value);
+ return this;
+ }
+}
+
+
diff --git a/src/Common/UI/Tables/RendererCell.java b/src/Common/UI/Tables/RendererCell.java
new file mode 100644
index 00000000..5b87d32d
--- /dev/null
+++ b/src/Common/UI/Tables/RendererCell.java
@@ -0,0 +1,16 @@
+package Common.UI.Tables;
+import javax.swing.*;
+import javax.swing.table.TableCellRenderer;
+import java.awt.*;
+public abstract class RendererCell extends StyledCellLabel implements TableCellRenderer {
+ public T value;
+ public abstract T Init(JTable table, Object value, int row, int column); //получить значение
+ public abstract void Display(); //отобразить его.
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value_in, boolean isSelected, boolean hasFocus, int row, int column) {
+ setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
+ value = Init(table, value_in, row, column);
+ Display();
+ return this;
+ }
+}
diff --git a/src/Common/UI/Tables/StatusEnumRenderer.java b/src/Common/UI/Tables/StatusEnumRenderer.java
new file mode 100644
index 00000000..f7ff213b
--- /dev/null
+++ b/src/Common/UI/Tables/StatusEnumRenderer.java
@@ -0,0 +1,17 @@
+package Common.UI.Tables;
+import Common.UI.StatusEnum;
+
+import javax.swing.*;
+public class StatusEnumRenderer extends RendererCell {
+ @Override
+ public StatusEnum Init(JTable table, Object value, int row, int column) {
+ return (StatusEnum) value;
+ }
+ @Override
+ public void Display() {
+ if (value != null) {
+ setText(value.getDescription());
+ setFont(value.getFont());
+ }
+ }
+}
diff --git a/src/Common/UI/Tables/StyledCellLabel.java b/src/Common/UI/Tables/StyledCellLabel.java
new file mode 100644
index 00000000..401e6030
--- /dev/null
+++ b/src/Common/UI/Tables/StyledCellLabel.java
@@ -0,0 +1,21 @@
+package Common.UI.Tables;
+import Common.Current;
+import Common.UI.Themes.ThemeElement;
+import Common.UI.Themes.VisualiserFonts;
+
+import javax.swing.*;
+//наиболее распространенный случай. переотображение текста и/или изображения в ячейке таблицы.
+public class StyledCellLabel extends JLabel implements ThemeElement {
+ public StyledCellLabel() {
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreePlain));
+ setHorizontalAlignment(SwingConstants.LEFT);
+ setVerticalAlignment(SwingConstants.CENTER);
+ setOpaque(true);
+ applyTheme();
+ }
+ @Override
+ public void applyTheme() {
+ setBackground(Current.getTheme().table_background);
+ setForeground(Current.getTheme().foreground);
+ }
+}
diff --git a/src/Common/UI/Tables/StyledTable.java b/src/Common/UI/Tables/StyledTable.java
new file mode 100644
index 00000000..44af8512
--- /dev/null
+++ b/src/Common/UI/Tables/StyledTable.java
@@ -0,0 +1,101 @@
+package Common.UI.Tables;
+import Common.Current;
+import Common.UI.Menus.TableMenu;
+import Common.UI.Themes.ThemeElement;
+import Common.UI.Themes.VisualiserFonts;
+
+import javax.swing.*;
+import javax.swing.table.*;
+import java.awt.*;
+public abstract class StyledTable extends JTable implements ThemeElement {
+ //https://askdev.ru/q/kak-upravlyat-stilem-cvetom-i-razmerom-shrifta-vnutri-jtable-455196/
+ //https://stackoverflow.com/questions/4129666/how-to-convert-hex-to-rgb-using-java цвета
+ public StyledTable(AbstractTableModel model) {
+ super(model);
+ setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+ setFillsViewportHeight(true);
+ setAutoCreateRowSorter(dataModel.getRowCount() > 0);
+ Init();
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreePlain));
+ JTableHeader header = getTableHeader();
+ header.setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreePlain));
+ putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
+ setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ //текущий объет может определяться по первому столбцу. могут быть баги если не запретить
+ getTableHeader().setReorderingAllowed(false);
+ CorrectSizes();
+ setComponentPopupMenu(CreateMenu());
+ applyTheme();
+ }
+ public TableMenu CreateMenu() {
+ return new TableMenu(this);
+ }
+ public void Init() {
+ }
+ private void adjustColumnSizes(int column, int margin) {
+ DefaultTableColumnModel colModel = (DefaultTableColumnModel) getColumnModel();
+ TableColumn col = colModel.getColumn(column);
+ int width;
+ TableCellRenderer renderer = col.getHeaderRenderer();
+ if (renderer == null) {
+ renderer = getTableHeader().getDefaultRenderer();
+ }
+ Component comp = renderer.getTableCellRendererComponent(this, col.getHeaderValue(), false, false, 0, 0);
+ width = comp.getPreferredSize().width;
+ for (int r = 0; r < getRowCount(); r++) {
+ renderer = getCellRenderer(r, column);
+ comp = renderer.getTableCellRendererComponent(this, getValueAt(r, column), false, false, r, column);
+ int currentWidth = comp.getPreferredSize().width;
+ width = Math.max(width, currentWidth);
+ }
+ width += 2 * margin;
+ col.setPreferredWidth(width);
+ col.setWidth(width);
+ }
+ private void adjustJTableRowSizes() {
+ for (int row = 0; row < getRowCount(); row++) {
+ int maxHeight = 0;
+ for (int column = 0; column < getColumnCount(); column++) {
+ TableCellRenderer cellRenderer = getCellRenderer(row, column);
+ Object valueAt = getValueAt(row, column);
+ Component tableCellRendererComponent = cellRenderer.getTableCellRendererComponent(this, valueAt, false, false, row, column);
+ int heightPreferable = tableCellRendererComponent.getPreferredSize().height;
+ maxHeight = Math.max(heightPreferable, maxHeight);
+ }
+ setRowHeight(row, maxHeight);
+ }
+ }
+ public void CorrectSizes() {
+ adjustJTableRowSizes();
+ CorrectColumnsSizes();
+ this.removeEditor();//отлючение редактирования клеток если таковые были.
+ }
+ public void CorrectColumnsSizes() {
+ for (int i = 0; i < getColumnCount(); i++) {
+ adjustColumnSizes(i, 2);
+ }
+ }
+ @Override
+ public void applyTheme() {
+ setBackground(Current.getTheme().table_background);
+ setForeground(Current.getTheme().foreground);
+ setSelectionBackground(Current.getTheme().selection_background);
+ setSelectionForeground(Current.getTheme().foreground);
+ }
+ public void SelectRow(int r) {
+ getSelectionModel().setSelectionInterval(r, r);
+ }
+ public void scrollToVisible(int rowIndex, int vColIndex) {
+ if (!(getParent() instanceof JViewport)) {
+ return;
+ }
+ JViewport viewport = (JViewport) getParent();
+ Rectangle rect = getCellRect(rowIndex, vColIndex, true);
+ Point pt = viewport.getViewPosition();
+ rect.setLocation(rect.x - pt.x, rect.y - pt.y);
+ viewport.scrollRectToVisible(rect);
+ }
+ public void scrollToLastRow() {
+ scrollToVisible(getRowCount() - 1, 0);
+ }
+}
diff --git a/src/Common/UI/Tables/TableEditors.java b/src/Common/UI/Tables/TableEditors.java
new file mode 100644
index 00000000..090c6751
--- /dev/null
+++ b/src/Common/UI/Tables/TableEditors.java
@@ -0,0 +1,8 @@
+package Common.UI.Tables;
+public enum TableEditors {
+ EditorDefault,
+ EditorSelect,
+ EditorHyperlinks,
+ EditorDimension,
+ EditorCompilerEnvironmentValue, EditorCompilerOptionParameterValue
+}
diff --git a/src/Common/UI/Tables/TableRenderers.java b/src/Common/UI/Tables/TableRenderers.java
new file mode 100644
index 00000000..82598e50
--- /dev/null
+++ b/src/Common/UI/Tables/TableRenderers.java
@@ -0,0 +1,19 @@
+package Common.UI.Tables;
+public enum TableRenderers {
+ RendererDefault,
+ RendererDate,
+ RendererProgress,
+ RendererSelect,
+ RendererDimension,
+ RendererMultiline,
+ RendererHyperlinks,
+ RendererTopLeft,
+ RendererMaskedInt,
+ RendererVariantRank,
+ RendererHiddenList,
+ RendererWrapText,
+ RendererCompilerOptionParameterValue,
+ RendererCompilerEnvironmentValue,
+ RendererCompilerOptionParameterName,
+ RendererStatusEnum
+}
diff --git a/src/Common/UI/Tables/TopLeftRenderer.java b/src/Common/UI/Tables/TopLeftRenderer.java
new file mode 100644
index 00000000..e866714a
--- /dev/null
+++ b/src/Common/UI/Tables/TopLeftRenderer.java
@@ -0,0 +1,13 @@
+package Common.UI.Tables;
+import javax.swing.*;
+public class TopLeftRenderer extends RendererCell {
+ @Override
+ public Object Init(JTable table, Object value, int row, int column) {
+ return value;
+ }
+ @Override
+ public void Display() {
+ if (value != null)
+ setText(value.toString());
+ }
+}
diff --git a/src/Common/UI/Tables/VectorEditor.java b/src/Common/UI/Tables/VectorEditor.java
new file mode 100644
index 00000000..d7882867
--- /dev/null
+++ b/src/Common/UI/Tables/VectorEditor.java
@@ -0,0 +1,89 @@
+package Common.UI.Tables;
+import ProjectData.Files.UI.FilesHyperlinksPanel;
+
+import javax.swing.*;
+import javax.swing.event.CellEditorListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.table.TableCellEditor;
+import java.awt.*;
+import java.util.EventObject;
+import java.util.Objects;
+import java.util.Vector;
+public class VectorEditor extends FilesHyperlinksPanel implements TableCellEditor {
+ protected transient ChangeEvent changeEvent;
+ @Override
+ public Component getTableCellEditorComponent(
+ JTable table, Object value, boolean isSelected, int row, int column) {
+ if (value instanceof Vector) {
+ UpdateByCell((Vector) value);
+ this.Hyperlinks.setBackground(table.getSelectionBackground());
+ Hyperlinks.setSelectionBackground(table.getSelectionBackground());
+ Hyperlinks.setSelectionForeground(table.getSelectionForeground());
+ }
+ return this;
+ }
+ @Override
+ public Object getCellEditorValue() {
+ return links;
+ }
+ //Copied from AbstractCellEditor
+ //protected EventListenerList listenerList = new EventListenerList();
+ @Override
+ public boolean isCellEditable(EventObject e) {
+ return true;
+ }
+ @Override
+ public boolean shouldSelectCell(EventObject anEvent) {
+ return true;
+ }
+ @Override
+ public boolean stopCellEditing() {
+ fireEditingStopped();
+ return true;
+ }
+ @Override
+ public void cancelCellEditing() {
+ fireEditingCanceled();
+ }
+ @Override
+ public void addCellEditorListener(CellEditorListener l) {
+ listenerList.add(CellEditorListener.class, l);
+ }
+ @Override
+ public void removeCellEditorListener(CellEditorListener l) {
+ listenerList.remove(CellEditorListener.class, l);
+ }
+ public CellEditorListener[] getCellEditorListeners() {
+ return listenerList.getListeners(CellEditorListener.class);
+ }
+ protected void fireEditingStopped() {
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length - 2; i >= 0; i -= 2) {
+ if (listeners[i] == CellEditorListener.class) {
+ // Lazily create the event:
+ if (Objects.isNull(changeEvent)) {
+ changeEvent = new ChangeEvent(this);
+ }
+ ((CellEditorListener) listeners[i + 1]).editingStopped(changeEvent);
+ }
+ }
+ }
+ protected void fireEditingCanceled() {
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length - 2; i >= 0; i -= 2) {
+ if (listeners[i] == CellEditorListener.class) {
+ // Lazily create the event:
+ if (Objects.isNull(changeEvent)) {
+ changeEvent = new ChangeEvent(this);
+ }
+ ((CellEditorListener) listeners[i + 1]).editingCanceled(changeEvent);
+ }
+ }
+ }
+}
diff --git a/src/Common/UI/Tables/WrapTextRenderer.java b/src/Common/UI/Tables/WrapTextRenderer.java
new file mode 100644
index 00000000..6732d97c
--- /dev/null
+++ b/src/Common/UI/Tables/WrapTextRenderer.java
@@ -0,0 +1,25 @@
+package Common.UI.Tables;
+import Common.Current;
+import Common.UI.Themes.VisualiserFonts;
+
+import javax.swing.*;
+import javax.swing.table.TableCellRenderer;
+import java.awt.*;
+public class WrapTextRenderer extends JTextArea implements TableCellRenderer {
+ public WrapTextRenderer() {
+ setLineWrap(true);
+ setWrapStyleWord(true);
+ // setOpaque(false);
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Distribution).deriveFont(14.0f));
+ }
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+ setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
+ setText((value == null) ? "" : value.toString());
+ setSize(table.getColumnModel().getColumn(column).getWidth(),
+ getPreferredSize().height);
+ if (table.getRowHeight(row) != getPreferredSize().height) {
+ table.setRowHeight(row, getPreferredSize().height);
+ }
+ return this;
+ }
+}
diff --git a/src/Common/UI/TextArea/StyledTextArea.java b/src/Common/UI/TextArea/StyledTextArea.java
new file mode 100644
index 00000000..f8c61d0c
--- /dev/null
+++ b/src/Common/UI/TextArea/StyledTextArea.java
@@ -0,0 +1,9 @@
+package Common.UI.TextArea;
+import Common.UI.Menus.TextEditorMenu;
+
+import javax.swing.*;
+public class StyledTextArea extends JTextArea {
+ public StyledTextArea() {
+ setComponentPopupMenu(new TextEditorMenu(this));
+ }
+}
diff --git a/src/Common/UI/TextField/StyledPasswordField.java b/src/Common/UI/TextField/StyledPasswordField.java
new file mode 100644
index 00000000..19817aeb
--- /dev/null
+++ b/src/Common/UI/TextField/StyledPasswordField.java
@@ -0,0 +1,11 @@
+package Common.UI.TextField;
+import Common.UI.Menus.StyledPopupMenu;
+import Common.UI.Menus.TextEditorMenu;
+
+import javax.swing.*;
+public class StyledPasswordField extends JPasswordField {
+ private StyledPopupMenu menu;
+ public StyledPasswordField() {
+ setComponentPopupMenu(new TextEditorMenu(this));
+ }
+}
diff --git a/src/Common/UI/TextField/StyledTextField.java b/src/Common/UI/TextField/StyledTextField.java
new file mode 100644
index 00000000..8e6a0cfe
--- /dev/null
+++ b/src/Common/UI/TextField/StyledTextField.java
@@ -0,0 +1,11 @@
+package Common.UI.TextField;
+import Common.UI.Menus.StyledPopupMenu;
+import Common.UI.Menus.TextEditorMenu;
+
+import javax.swing.*;
+public class StyledTextField extends JTextField {
+ private StyledPopupMenu menu;
+ public StyledTextField() {
+ setComponentPopupMenu(new TextEditorMenu(this));
+ }
+}
diff --git a/src/Common/UI/Themes/DarkVisualiserTheme.java b/src/Common/UI/Themes/DarkVisualiserTheme.java
new file mode 100644
index 00000000..86f43d52
--- /dev/null
+++ b/src/Common/UI/Themes/DarkVisualiserTheme.java
@@ -0,0 +1,64 @@
+package Common.UI.Themes;
+import java.awt.*;
+public class DarkVisualiserTheme extends VisualiserTheme {
+ @Override
+ protected String getEditorThemePath() {
+ return "/Common/UI/Themes/dark_editor.xml";
+ }
+ @Override
+ protected String getForegroundHex() {
+ return "#e0e5eb";
+ }
+ @Override
+ protected String getBackgroundHex() {
+ return "#484a4c";
+ }
+ @Override
+ protected String getSelectionBackgroundHex() {
+ return "#20355a";
+ }
+ @Override
+ protected String getTreeBackgroundHex() {
+ return "#293134";
+ }
+ @Override
+ protected String getBarForegroundHex() {
+ return "#000000";
+ }
+ @Override
+ protected String getBarBackgroundHex() {
+ return "#484a4c";
+ }
+ @Override
+ protected String getTableBackgroundHex() {
+ return "#293134";
+ }
+ @Override
+ protected Color getGoodFontColor() {
+ return Color.decode("#24ff58");
+ }
+ @Override
+ protected Color getReadyFontColor2() {
+ return Color.decode("#FFFF00");
+ }
+ @Override
+ protected Color getProgressFontColor() {
+ return Color.orange;
+ }
+ @Override
+ protected Color getBadFontColor() {
+ return Color.decode("#8B0000");
+ }
+ @Override
+ protected Color getFatalFontColor() {
+ return Color.red;
+ }
+ @Override
+ protected Color getUnknownFontColor() {
+ return Color.decode("#c7c7c7");
+ }
+ @Override
+ protected Color getHyperlinkFontColor() {
+ return Color.decode("#00aee9");
+ }
+}
diff --git a/src/Common/UI/Themes/FortranSPFTokenMaker.java b/src/Common/UI/Themes/FortranSPFTokenMaker.java
new file mode 100644
index 00000000..3eba5883
--- /dev/null
+++ b/src/Common/UI/Themes/FortranSPFTokenMaker.java
@@ -0,0 +1,408 @@
+package Common.UI.Themes;
+import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
+import org.fife.ui.rsyntaxtextarea.Token;
+import org.fife.ui.rsyntaxtextarea.TokenMap;
+
+import javax.swing.text.Segment;
+public class FortranSPFTokenMaker extends ProvidedTokenMaker {
+ @Override
+ public TokenMap getWordsToHighlight() {
+ TokenMap tokenMap = new TokenMap(true);
+ fillTokenMap(tokenMap, Token.RESERVED_WORD,
+ "FORALL", "ENDFORALL", "PUBLIC", "PRIVATE", "ADMIT", "ASSIGNMENT", "CALL", "COMMON",
+ "CYCLE", "DIMENSION", "END", "ENDDO", "ENTRY", "FORMAT", "IMPLICIT", "INTENT", "MAP",
+ "OPEN", "POINTER", "PROGRAM", "RECURSIVE", "STOP", "THEN", "WHILE", "ALLOCATABLE",
+ "ATEND", "CASE", "COMPLEX", "DATA", "DO", "ENDFILE", "EQUIVALENCE", "FUNCTION",
+ "INCLUDE", "INTERFACE", "MODULE", "OPTIONAL", "PRINT", "PURE", "READ", "RETURN",
+ "STRUCTURE", "TYPE", "WRITE", "ALLOCATE", "BACKSPACE", "CHARACTER", "CONTAINS",
+ "DEALLOCATE", "DOUBLE", "ENDIF", "EXIT", "GOTO", "INQUIRE", "INTRINSIC", "NAMELIST",
+ "PARAMETER", "PRECISION", "REAL", "REWIND", "SUBROUTINE", "UNION", "ASSIGN", "BLOCKDATA",
+ "CLOSE", "CONTINUE", "DEFAULT", "ELSE", "ELSEIF", "ENDSELECT", "EXTERNAL", "IF", "INTEGER",
+ "LOGICAL", "NONE", "PAUSE", "PROCEDURE", "RECORD", "SAVE", "TARGET", "USE", "SELECT", "BLOCK", "WHERE"
+ );
+ fillTokenMap(tokenMap, Token.OPERATOR,
+ ".EQ.",
+ ".NE.", ".LT.", ".LE.",
+ ".GT.", ".GE.",
+ ".NOT.", ".AND.", ".EQV.", ".NEQV.",
+ ".OR.", ".TRUE.", ".FALSE."
+ );
+ return tokenMap;
+ }
+ @Override
+ public void addToken(Segment segment, int start, int end, int tokenType, int startOffset) {
+ int finalTokenType = tokenType;
+ switch (tokenType) {
+ case Token.COMMENT_EOL:
+ if (segment.count >= 5) {
+ switch (segment.subSequence(1, 5).toString().toUpperCase()) {
+ case "$SPF":
+ finalTokenType = Token.COMMENT_DOCUMENTATION;
+ break;
+ case "DVM$":
+ finalTokenType = Token.COMMENT_MARKUP;
+ break;
+ case "$OMP":
+ finalTokenType = Token.COMMENT_KEYWORD;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case Token.IDENTIFIER:
+ int value = wordsToHighlight.get(segment, start, end);
+ //ключевое слово
+ if (value != -1) {
+ finalTokenType = value;
+ }
+ break;
+ default:
+ break;
+ }
+ super.addToken(segment, start, end, finalTokenType, startOffset);
+ }
+ @Override
+ public void Body(TokenProvider provider) {
+ switch (provider.position) {
+ //
+ case 0:
+ //тут всегда currentTokenType=NULL. переносимый известеи в startTokenType
+ provider.start();
+ switch (provider.c) {
+ case '!':
+ case '*':
+ case 'C':
+ case 'c':
+ case 'D':
+ case 'd':
+ //комментарий. анализ закончен
+ provider.setType(Token.COMMENT_EOL);
+ provider.stop();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ //метка.
+ provider.setType(Token.MARKUP_TAG_NAME);
+ provider.label_flag = true;
+ break;
+ case ' ':
+ case '\r':
+ //пробелы
+ provider.setType(Token.WHITESPACE);
+ break;
+ case '\t':
+ provider.SkipWrap();
+ break;
+ default:
+ //все остальное
+ provider.setType(Token.IDENTIFIER);
+ break;
+ }
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ switch (provider.currentTokenType) {
+ case Token.MARKUP_TAG_NAME:
+ switch (provider.c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '\r':
+ break;
+ case '!':
+ SaveCurrent(provider);
+ provider.start();
+ //комментарий. анализ закончен
+ provider.setType(Token.COMMENT_EOL);
+ provider.stop();
+ break;
+ case ' ':
+ SaveCurrent(provider);
+ provider.start();
+ provider.setType(Token.WHITESPACE);
+ break;
+ case '\t':
+ SaveCurrent(provider);
+ provider.start();
+ provider.SkipWrap();
+ break;
+ default:
+ //это не метка. меняем тип.
+ provider.setType(Token.IDENTIFIER);
+ break;
+ }
+ break;
+ case Token.WHITESPACE:
+ switch (provider.c) {
+ case ' ':
+ case '\r':
+ break;
+ case '\t':
+ provider.SkipWrap();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ SaveCurrent(provider);
+ provider.start();
+ //если метка уже бывала. значит больше меток нет
+ if (provider.label_flag) {
+ provider.setType(Token.IDENTIFIER);
+ } else {
+ provider.setType(Token.MARKUP_TAG_NAME);
+ provider.label_flag = true;
+ }
+ break;
+ case '!':
+ SaveCurrent(provider);
+ provider.start();
+ //комментарий. анализ закончен
+ provider.setType(Token.COMMENT_EOL);
+ provider.stop();
+ break;
+ default:
+ SaveCurrent(provider);
+ provider.start();
+ provider.setType(Token.IDENTIFIER);
+ break;
+ }
+ break;
+ case Token.IDENTIFIER:
+ switch (provider.c) {
+ case '!':
+ SaveCurrent(provider);
+ provider.start();
+ //комментарий. анализ закончен
+ provider.setType(Token.COMMENT_EOL);
+ provider.stop();
+ break;
+ case '\t':
+ SaveCurrent(provider);
+ provider.start();
+ provider.SkipWrap();
+ break;
+ default:
+ //уже неважно что это.
+ break;
+ }
+ break;
+ }
+ break;
+ case 5:
+ switch (provider.c) {
+ case ' ':
+ case '\r':
+ case '\t':
+ switch (provider.currentTokenType) {
+ case Token.WHITESPACE:
+ //это пробел, и нам норм.
+ break;
+ default:
+ SaveCurrent(provider);
+ provider.start();
+ provider.setType(Token.WHITESPACE);
+ break;
+ }
+ //это пробелы. переноса нет. убираем сохранение типа
+ provider.startTokenType = Token.NULL;
+ break;
+ default:
+ //это - позиция переноса. сохраняем все что было до нее.
+ SaveCurrent(provider);
+ provider.start();
+ provider.setType(Token.OPERATOR);
+ SaveCurrent_(provider); //сохраняем его как одиночный оператор.
+ provider.setType(provider.startTokenType);
+ //берем унаследование от предыдущей строки
+ break;
+ }
+ break;
+ //
+ //
+ default:
+ switch (provider.currentTokenType) {
+ case Token.NULL:
+ provider.start();
+ provider.detectType();
+ break;
+ case Token.WHITESPACE:
+ switch (provider.c) {
+ case ' ':
+ case '\t':
+ case '\r':
+ break;
+ default:
+ SaveCurrent(provider);
+ provider.start();
+ provider.detectType();
+ break;
+ }
+ break;
+ case Token.OPERATOR:
+ provider.checkWrap();
+ SaveCurrent(provider);
+ provider.start();
+ provider.detectType();
+ break;
+ case Token.LITERAL_NUMBER_DECIMAL_INT:
+ provider.checkWrap();
+ switch (provider.c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '\r':
+ break;
+ case '.':
+ case 'e':
+ case 'E':
+ case 'd':
+ case 'D':
+ provider.setType(Token.LITERAL_NUMBER_FLOAT);
+ break;
+ default:
+ SaveCurrent(provider);
+ provider.start();
+ provider.detectType();
+ break;
+ }
+ break;
+ case Token.LITERAL_NUMBER_FLOAT:
+ provider.checkWrap();
+ switch (provider.c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '\r':
+ break;
+ case 'e':
+ case 'E':
+ case 'd':
+ case 'D':
+ SaveCurrent_(provider);
+ provider.setType(Token.NULL);
+ break;
+ default:
+ SaveCurrent(provider);
+ provider.start();
+ provider.detectType();
+ break;
+ }
+ break;
+ case Token.RESERVED_WORD_2:
+ provider.checkWrap();
+ switch (provider.c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ //подозрения подтвердились. это дробь.
+ provider.setType(Token.LITERAL_NUMBER_FLOAT);
+ break;
+ case '\r':
+ break;
+ default:
+ provider.setType(Token.IDENTIFIER);
+ break;
+ }
+ break;
+ case Token.LITERAL_CHAR:
+ switch (provider.c) {
+ case '\'':
+ SaveCurrent_(provider);
+ provider.setType(Token.NULL);
+ break;
+ default:
+ break;
+ }
+ break;
+ case Token.LITERAL_STRING_DOUBLE_QUOTE:
+ switch (provider.c) {
+ case '"':
+ SaveCurrent_(provider);
+ provider.setType(Token.NULL);
+ break;
+ default:
+ break;
+ }
+ break;
+ case Token.IDENTIFIER:
+ provider.checkWrap();
+ if (!
+ (RSyntaxUtilities.isLetter(provider.c) ||
+ RSyntaxUtilities.isDigit(provider.c) ||
+ (provider.c == '_') ||
+ (provider.c == '.')
+ )) {
+ SaveCurrent(provider);
+ provider.start();
+ provider.detectType();
+ }
+ break;
+ }
+ //
+ }
+ }
+ @Override
+ public void performFinish(TokenProvider provider) {
+ switch (provider.currentTokenType) {
+ case Token.NULL:
+ addNullToken();
+ break;
+ // case Token.IDENTIFIER:
+ case Token.LITERAL_NUMBER_DECIMAL_INT:
+ case Token.LITERAL_NUMBER_FLOAT:
+ case Token.RESERVED_WORD_2:
+ SaveCurrent(provider);
+ break;
+ default:
+ SaveCurrent(provider);
+ addNullToken();
+ break;
+ }
+ }
+}
diff --git a/src/Common/UI/Themes/FreeFortranSPFTokenMaker.java b/src/Common/UI/Themes/FreeFortranSPFTokenMaker.java
new file mode 100644
index 00000000..b2474c4c
--- /dev/null
+++ b/src/Common/UI/Themes/FreeFortranSPFTokenMaker.java
@@ -0,0 +1,297 @@
+package Common.UI.Themes;
+import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
+import org.fife.ui.rsyntaxtextarea.Token;
+import org.fife.ui.rsyntaxtextarea.TokenMap;
+
+import javax.swing.text.Segment;
+public class FreeFortranSPFTokenMaker extends ProvidedTokenMaker {
+ @Override
+ public TokenMap getWordsToHighlight() {
+ TokenMap tokenMap = new TokenMap(true);
+ fillTokenMap(tokenMap, Token.RESERVED_WORD,
+ "FORALL", "ENDFORALL", "PUBLIC", "PRIVATE", "ADMIT", "ASSIGNMENT", "CALL", "COMMON",
+ "CYCLE", "DIMENSION", "END", "ENDDO", "ENTRY", "FORMAT", "IMPLICIT", "INTENT", "MAP",
+ "OPEN", "POINTER", "PROGRAM", "RECURSIVE", "STOP", "THEN", "WHILE", "ALLOCATABLE",
+ "ATEND", "CASE", "COMPLEX", "DATA", "DO", "ENDFILE", "EQUIVALENCE", "FUNCTION",
+ "INCLUDE", "INTERFACE", "MODULE", "OPTIONAL", "PRINT", "PURE", "READ", "RETURN",
+ "STRUCTURE", "TYPE", "WRITE", "ALLOCATE", "BACKSPACE", "CHARACTER", "CONTAINS",
+ "DEALLOCATE", "DOUBLE", "ENDIF", "EXIT", "GOTO", "INQUIRE", "INTRINSIC", "NAMELIST",
+ "PARAMETER", "PRECISION", "REAL", "REWIND", "SUBROUTINE", "UNION", "ASSIGN", "BLOCKDATA",
+ "CLOSE", "CONTINUE", "DEFAULT", "ELSE", "ELSEIF", "ENDSELECT", "EXTERNAL", "IF", "INTEGER",
+ "LOGICAL", "NONE", "PAUSE", "PROCEDURE", "RECORD", "SAVE", "TARGET", "USE", "SELECT", "BLOCK", "WHERE"
+ );
+ fillTokenMap(tokenMap, Token.OPERATOR,
+ ".EQ.",
+ ".NE.", ".LT.", ".LE.",
+ ".GT.", ".GE.",
+ ".NOT.", ".AND.", ".EQV.", ".NEQV.",
+ ".OR.", ".TRUE.", ".FALSE."
+ );
+ return tokenMap;
+ }
+ @Override
+ public void addToken(Segment segment, int start, int end, int tokenType, int startOffset) {
+ int finalTokenType = tokenType;
+ switch (tokenType) {
+ case Token.COMMENT_EOL:
+ if (segment.count >= 5) {
+ switch (segment.subSequence(1, 5).toString().toUpperCase()) {
+ case "$SPF":
+ finalTokenType = Token.COMMENT_DOCUMENTATION;
+ break;
+ case "DVM$":
+ finalTokenType = Token.COMMENT_MARKUP;
+ break;
+ case "$OMP":
+ finalTokenType = Token.COMMENT_KEYWORD;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case Token.IDENTIFIER:
+ int value = wordsToHighlight.get(segment, start, end);
+ //ключевое слово
+ if (value != -1) {
+ finalTokenType = value;
+ }
+ break;
+ default:
+ break;
+ }
+ super.addToken(segment, start, end, finalTokenType, startOffset);
+ }
+ @Override
+ public void Body(TokenProvider provider) {
+ /*
+ switch (provider.position) {
+ //
+ case 0:
+ //тут всегда currentTokenType=NULL. переносимый известеи в startTokenType
+ provider.start();
+ switch (provider.c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ //метка. может появиться только с 0-4 позиций. остальной анализ. аналогичен обычному.
+ provider.setType(Token.MARKUP_TAG_NAME);
+ provider.label_flag = true;
+ break;
+ default:
+ //все остальное
+ provider.detectType();
+ break;
+ }
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ switch (provider.currentTokenType) {
+ case Token.MARKUP_TAG_NAME:
+ switch (provider.c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '\r':
+ break;
+ default:
+ SaveCurrent(provider);
+ provider.start();
+ provider.detectType();
+ break;
+ }
+ break;
+ default:
+ DefaultLineParse(provider);
+ break;
+ }
+ break;
+ case 5:
+ switch (provider.c) {
+ case '&':
+ //это - позиция переноса. сохраняем все что было до нее.
+ SaveCurrent(provider);
+ provider.start();
+ provider.setType(Token.OPERATOR);
+ SaveCurrent_(provider); //сохраняем его как одиночный оператор.
+ provider.setType(provider.startTokenType);
+ //берем унаследование от предыдущей строки
+ break;
+ default:
+ if (provider.currentTokenType==Token.MARKUP_TAG_NAME){
+ //метка на этом символе уже обязана закончиться.
+ SaveCurrent(provider);
+ provider.start();
+ provider.detectType();
+ }else
+ DefaultLineParse(provider);
+ break;
+ }
+ break;
+ //
+ //
+ default:
+ DefaultLineParse(provider);
+ //
+ }
+ */
+ DefaultLineParse(provider);
+ }
+ public void DefaultLineParse(TokenProvider provider) {
+ switch (provider.currentTokenType) {
+ case Token.NULL:
+ provider.start();
+ provider.detectType();
+ break;
+ case Token.WHITESPACE:
+ switch (provider.c) {
+ case ' ':
+ case '\t':
+ case '\r':
+ break;
+ default:
+ SaveCurrent(provider);
+ provider.start();
+ provider.detectType();
+ break;
+ }
+ break;
+ case Token.OPERATOR:
+ SaveCurrent(provider);
+ provider.start();
+ provider.detectType();
+ break;
+ case Token.LITERAL_NUMBER_DECIMAL_INT:
+ switch (provider.c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '\r':
+ break;
+ case '.':
+ case 'e':
+ case 'E':
+ case 'd':
+ case 'D':
+ provider.setType(Token.LITERAL_NUMBER_FLOAT);
+ break;
+ default:
+ SaveCurrent(provider);
+ provider.start();
+ provider.detectType();
+ break;
+ }
+ break;
+ case Token.LITERAL_NUMBER_FLOAT:
+ switch (provider.c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '\r':
+ break;
+ case 'e':
+ case 'E':
+ case 'd':
+ case 'D':
+ SaveCurrent_(provider);
+ provider.setType(Token.NULL);
+ break;
+ default:
+ SaveCurrent(provider);
+ provider.start();
+ provider.detectType();
+ break;
+ }
+ break;
+ case Token.RESERVED_WORD_2:
+ switch (provider.c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ //подозрения подтвердились. это дробь.
+ provider.setType(Token.LITERAL_NUMBER_FLOAT);
+ break;
+ case '\r':
+ break;
+ default:
+ provider.setType(Token.IDENTIFIER);
+ break;
+ }
+ break;
+ case Token.LITERAL_CHAR:
+ switch (provider.c) {
+ case '\'':
+ SaveCurrent_(provider);
+ provider.setType(Token.NULL);
+ break;
+ default:
+ break;
+ }
+ break;
+ case Token.LITERAL_STRING_DOUBLE_QUOTE:
+ switch (provider.c) {
+ case '"':
+ SaveCurrent_(provider);
+ provider.setType(Token.NULL);
+ break;
+ default:
+ break;
+ }
+ break;
+ case Token.IDENTIFIER:
+ if (!
+ (RSyntaxUtilities.isLetter(provider.c) ||
+ RSyntaxUtilities.isDigit(provider.c) ||
+ (provider.c == '_') ||
+ (provider.c == '.')
+ )) {
+ SaveCurrent(provider);
+ provider.start();
+ provider.detectType();
+ }
+ break;
+ }
+ }
+ @Override
+ public void performFinish(TokenProvider provider) {
+ SaveCurrent(provider);
+ addNullToken();
+ }
+}
diff --git a/src/Common/UI/Themes/LightVisualiserTheme.java b/src/Common/UI/Themes/LightVisualiserTheme.java
new file mode 100644
index 00000000..0a5ecb3d
--- /dev/null
+++ b/src/Common/UI/Themes/LightVisualiserTheme.java
@@ -0,0 +1,64 @@
+package Common.UI.Themes;
+import java.awt.*;
+public class LightVisualiserTheme extends VisualiserTheme {
+ @Override
+ protected String getEditorThemePath() {
+ return "/Common/UI/Themes/light_editor.xml";
+ }
+ @Override
+ protected String getForegroundHex() {
+ return "#000000";
+ }
+ @Override
+ protected String getBackgroundHex() {
+ return "#f7f7f7";
+ }
+ @Override
+ protected String getSelectionBackgroundHex() {
+ return "#dae3f1";
+ }
+ @Override
+ protected String getTreeBackgroundHex() {
+ return "#ffffff";
+ }
+ @Override
+ protected String getBarForegroundHex() {
+ return "#637780";
+ }
+ @Override
+ protected String getBarBackgroundHex() {
+ return "#ffffff";
+ }
+ @Override
+ protected String getTableBackgroundHex() {
+ return "#ffffff";
+ }
+ @Override
+ protected Color getGoodFontColor() {
+ return Color.decode("#009738");
+ }
+ @Override
+ protected Color getReadyFontColor2() {
+ return Color.decode("#FFD700");
+ }
+ @Override
+ protected Color getProgressFontColor() {
+ return Color.decode("#f39a28");
+ }
+ @Override
+ protected Color getBadFontColor() {
+ return Color.decode("#ab0000");
+ }
+ @Override
+ protected Color getFatalFontColor() {
+ return Color.decode("#FF4500");
+ }
+ @Override
+ protected Color getUnknownFontColor() {
+ return Color.GRAY;
+ }
+ @Override
+ protected Color getHyperlinkFontColor() {
+ return Color.blue;
+ }
+}
diff --git a/src/Common/UI/Themes/ProvidedTokenMaker.java b/src/Common/UI/Themes/ProvidedTokenMaker.java
new file mode 100644
index 00000000..6c0a7a72
--- /dev/null
+++ b/src/Common/UI/Themes/ProvidedTokenMaker.java
@@ -0,0 +1,47 @@
+package Common.UI.Themes;
+import org.fife.ui.rsyntaxtextarea.AbstractTokenMaker;
+import org.fife.ui.rsyntaxtextarea.Token;
+import org.fife.ui.rsyntaxtextarea.TokenMap;
+
+import javax.swing.text.Segment;
+//объект создается 1 раз, при установке стиля редактора.
+//НИ В КОЕМ СЛУЧАЕ НЕЛЬЗЯ ПЕРЕДАВАТЬ ПО ССЫЛКЕ методам ради рефакторинга
+//все переменные должны быть сугубо локальными
+//иначе возможны непредсказуемые последствия.
+//Метод вызывается асинхронно, причем несколькими событиями)
+public abstract class ProvidedTokenMaker extends AbstractTokenMaker {
+ public static void fillTokenMap(TokenMap map, int type, String... words) {
+ for (String word : words)
+ map.put(word, type);
+ }
+ //сохранить не забирая текущий символ.
+ public void SaveCurrent(TokenProvider provider) {
+ addToken(provider.text, provider.currentTokenStart,
+ provider.i - 1, provider.currentTokenType,
+ provider.newStartOffset + provider.currentTokenStart);
+ }
+ //сохранить забирая текущий символ
+ public void SaveCurrent_(TokenProvider provider) {
+ addToken(provider.text, provider.currentTokenStart,
+ provider.i, provider.currentTokenType,
+ provider.newStartOffset + provider.currentTokenStart);
+ }
+ public abstract void Body(TokenProvider provider);
+ public abstract void performFinish(TokenProvider provider);
+ public Token getTokenList(Segment text, int startTokenType, int startOffset) {
+ // System.out.println(Utils.Brackets(text.toString()));
+ resetTokenList();
+ //структура для хранения индексов смещений, текущего состояния и т д.
+ TokenProvider provider = new TokenProvider(text, startTokenType, startOffset);
+ // provider.checkFortranWrap();
+ // System.out.println(this.);
+ while (provider.canRead()) {
+ provider.readNext();
+ Body(provider);
+ provider.gotoNext();
+ }
+ performFinish(provider);
+ // Return the first token in our linked list.
+ return firstToken;
+ }
+}
diff --git a/src/Common/UI/Themes/ThemeElement.java b/src/Common/UI/Themes/ThemeElement.java
new file mode 100644
index 00000000..f97cdc97
--- /dev/null
+++ b/src/Common/UI/Themes/ThemeElement.java
@@ -0,0 +1,8 @@
+package Common.UI.Themes;
+public interface ThemeElement {
+ default void FontUp() {
+ }
+ default void FontDown() {
+ }
+ void applyTheme();
+}
diff --git a/src/Common/UI/Themes/TokenProvider.java b/src/Common/UI/Themes/TokenProvider.java
new file mode 100644
index 00000000..155d74af
--- /dev/null
+++ b/src/Common/UI/Themes/TokenProvider.java
@@ -0,0 +1,134 @@
+package Common.UI.Themes;
+import org.fife.ui.rsyntaxtextarea.Token;
+
+import javax.swing.text.Segment;
+//сткуртура контейнер для всех текущих переменных.
+//для упрощения операций.
+public class TokenProvider {
+ public Segment text;
+ public char[] array;
+ public int offset;
+ public int count;
+ public int end;
+ // Token starting offsets are always of the form:
+ // 'startOffset + (currentTokenStart-offset)', but since startOffset and
+ // offset are constant, tokens' starting positions become:
+ // 'newStartOffset+currentTokenStart'.
+ public int newStartOffset;
+ public int currentTokenStart;
+ public int startTokenType; //хранить тип токена который нам передали, ради переносов
+ public int currentTokenType;
+ public int i;
+ public int position;
+ public char c;
+ public boolean label_flag;
+ public TokenProvider(Segment text_in, int startTokenType_in, int startOffset) {
+ text = text_in;
+ startTokenType = startTokenType_in; //может указывать на то, что мы продолжаем.
+ array = text.array;
+ offset = text.offset;
+ count = text.count;
+ end = offset + count;
+ // Token starting offsets are always of the form:
+ // 'startOffset + (currentTokenStart-offset)', but since startOffset and
+ // offset are constant, tokens' starting positions become:
+ // 'newStartOffset+currentTokenStart'.
+ newStartOffset = startOffset - offset;
+ currentTokenStart = offset;
+ currentTokenType = Token.NULL; //изначально не знаем что будем обрабатывать.
+ position = 0;
+ i = offset;
+ label_flag = false;
+ }
+ public void checkWrap() {
+ if (startTokenType != Token.NULL) {
+ start();
+ startTokenType = Token.NULL;
+ }
+ }
+ public void readNext() {
+ c = array[i];
+ }
+ public void gotoNext() {
+ ++i;
+ ++position;
+ //todo от греха от табов надо избавляться.
+ // возникает расхожедние между реальным и табским смещением. отсюда галюны.
+ // лучше бы их не отображать даже если они есть. но это к тексту файла. или как то узнавать их длину..
+ }
+ public boolean canRead() {
+ return i < end;
+ }
+ public void setType(int currentTokenType_in) {
+ currentTokenType = currentTokenType_in;
+ }
+ public void stop() {
+ i = end - 1;
+ }
+ public void start() {
+ currentTokenStart = i;
+ }
+ //в зоне основной строки
+ //по текущему символу определяем тип уже начатого токена.
+ public void detectType() {
+ switch (c) {
+ case ' ':
+ case '\t':
+ case '\r':
+ currentTokenType = Token.WHITESPACE;
+ break;
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '=':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case '<':
+ case '>':
+ case '{':
+ case '}':
+ case ',':
+ case '&':
+ currentTokenType = Token.OPERATOR;
+ break;
+ case '\'':
+ currentTokenType = Token.LITERAL_CHAR;
+ break;
+ case '"':
+ currentTokenType = Token.LITERAL_STRING_DOUBLE_QUOTE;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ currentTokenType = Token.LITERAL_NUMBER_DECIMAL_INT;
+ break;
+ case '.':
+ //возможный кандидат на число с плавающей точкой.
+ currentTokenType = Token.RESERVED_WORD_2;
+ break;
+ case '!':
+ currentTokenType = Token.COMMENT_EOL;
+ stop();
+ break;
+ default:
+ currentTokenType = Token.IDENTIFIER;
+ break;
+ }
+ }
+ //досрочный выход из зоны переноса.
+ public void SkipWrap() {
+ startTokenType = Token.NULL; //перенос исключается.
+ position += 6; //гарантированное непопадание в зону переноса при анализе.
+ setType(Token.WHITESPACE); //стоит таб, значит переноса не будет. идет набор пробелов.
+ }
+}
diff --git a/src/Common/UI/Themes/VisualiserColor.java b/src/Common/UI/Themes/VisualiserColor.java
new file mode 100644
index 00000000..0d314082
--- /dev/null
+++ b/src/Common/UI/Themes/VisualiserColor.java
@@ -0,0 +1,5 @@
+package Common.UI.Themes;
+public enum VisualiserColor {
+ ToolTip_background,
+ ToolTip_foreground
+}
diff --git a/src/Common/UI/Themes/VisualiserFonts.java b/src/Common/UI/Themes/VisualiserFonts.java
new file mode 100644
index 00000000..20df3e04
--- /dev/null
+++ b/src/Common/UI/Themes/VisualiserFonts.java
@@ -0,0 +1,21 @@
+package Common.UI.Themes;
+public enum VisualiserFonts {
+ GoodState,
+ ReadyState,
+ BadState,
+ Fatal,
+ ProgressState,
+ UnknownState,
+ Hyperlink,
+ Disabled,
+ //бесцветные
+ Distribution,
+ //---
+ TreeItalic,
+ TreePlain,
+ TreeBold,
+ TreeBoldItalic,
+ BlueState,
+ NewVersion, //---
+ Menu
+}
diff --git a/src/Common/UI/Themes/VisualiserTheme.java b/src/Common/UI/Themes/VisualiserTheme.java
new file mode 100644
index 00000000..28577bbd
--- /dev/null
+++ b/src/Common/UI/Themes/VisualiserTheme.java
@@ -0,0 +1,183 @@
+package Common.UI.Themes;
+import Common.Global;
+import org.fife.ui.rsyntaxtextarea.Theme;
+
+import java.awt.*;
+import java.awt.font.TextAttribute;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+
+import static java.awt.Font.MONOSPACED;
+public abstract class VisualiserTheme {
+ public Color foreground;
+ public Color background;
+ public Color selection_background;
+ public Color trees_background;
+ public Color bar_foreground;
+ public Color bar_background;
+ public Color table_background;
+ public LinkedHashMap Fonts = new LinkedHashMap<>();
+ public LinkedHashMap Colors = new LinkedHashMap<>();
+ public VisualiserTheme() {
+ try {
+ //-----------------------------------------------
+ //-----------------------------------------------
+ foreground = Color.decode(getForegroundHex());
+ background = Color.decode(getBackgroundHex());
+ selection_background = Color.decode(getSelectionBackgroundHex());
+ trees_background = Color.decode(getTreeBackgroundHex());
+ bar_foreground = Color.decode(getBarForegroundHex());
+ bar_background = Color.decode(getBarBackgroundHex());
+ table_background = Color.decode(getTableBackgroundHex());
+ //
+ Fonts.put(VisualiserFonts.GoodState,
+ new Font(
+ new HashMap() {
+ {
+ put(TextAttribute.FAMILY, "Times New Roman");
+ put(TextAttribute.FOREGROUND, getGoodFontColor());
+ put(TextAttribute.SIZE, 16);
+ }
+ }
+ ));
+ Fonts.put(VisualiserFonts.ReadyState,
+ new Font(
+ new HashMap() {
+ {
+ put(TextAttribute.FAMILY, "Times New Roman");
+ put(TextAttribute.FOREGROUND, getReadyFontColor2());
+ put(TextAttribute.SIZE, 16);
+ }
+ }
+ ));
+ Fonts.put(VisualiserFonts.BadState,
+ new Font(
+ new HashMap() {
+ {
+ put(TextAttribute.FAMILY, "Times New Roman");
+ put(TextAttribute.FOREGROUND, getBadFontColor());
+ put(TextAttribute.SIZE, 16);
+ }
+ }
+ ));
+ Fonts.put(VisualiserFonts.BlueState,
+ new Font(
+ new HashMap() {
+ {
+ put(TextAttribute.FAMILY, "Times New Roman");
+ put(TextAttribute.FOREGROUND, getHyperlinkFontColor());
+ put(TextAttribute.SIZE, 16);
+ }
+ }
+ ));
+ Fonts.put(VisualiserFonts.Fatal,
+ new Font(
+ new HashMap() {
+ {
+ put(TextAttribute.FAMILY, "Times New Roman");
+ put(TextAttribute.FOREGROUND, getFatalFontColor());
+ put(TextAttribute.SIZE, 16);
+ }
+ }
+ ));
+ Fonts.put(VisualiserFonts.UnknownState,
+ new Font(
+ new HashMap() {
+ {
+ put(TextAttribute.FAMILY, "Times New Roman");
+ put(TextAttribute.FOREGROUND, getUnknownFontColor());
+ put(TextAttribute.SIZE, 16);
+ }
+ }
+ ));
+ Fonts.put(VisualiserFonts.Hyperlink,
+ new Font(
+ new HashMap() {
+ {
+ put(TextAttribute.FAMILY, MONOSPACED);
+ put(TextAttribute.FOREGROUND, getHyperlinkFontColor());
+ put(TextAttribute.SIZE, 18);
+ put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
+ put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
+ }
+ }
+ ));
+ Fonts.put(VisualiserFonts.ProgressState,
+ new Font(
+ new HashMap() {
+ {
+ put(TextAttribute.FAMILY, "Times New Roman");
+ put(TextAttribute.FOREGROUND, getProgressFontColor());
+ put(TextAttribute.SIZE, 16);
+ }
+ }
+ ));
+ Fonts.put(VisualiserFonts.Disabled, new Font(
+ new HashMap() {
+ {
+ put(TextAttribute.FAMILY, MONOSPACED);
+ put(TextAttribute.BACKGROUND, Color.lightGray);
+ put(TextAttribute.FOREGROUND, Color.lightGray);
+ put(TextAttribute.SIZE, 18);
+ put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
+ }
+ }
+ ));
+ Fonts.put(VisualiserFonts.Distribution,
+ new Font(
+ new HashMap() {
+ {
+ put(TextAttribute.FAMILY, MONOSPACED);
+ put(TextAttribute.SIZE, 16);
+ }
+ }
+ )
+ );
+ Fonts.put(VisualiserFonts.TreePlain, new Font("Times New Roman", Font.PLAIN, 16));
+ Fonts.put(VisualiserFonts.TreeItalic, new Font("Times New Roman", Font.ITALIC, 16));
+ Fonts.put(VisualiserFonts.TreeBold, new Font("Times New Roman", Font.BOLD, 16));
+ Fonts.put(VisualiserFonts.TreeBoldItalic, new Font("Times New Roman", Font.BOLD|Font.ITALIC, 16));
+ Fonts.put(VisualiserFonts.Menu, new Font("Times New Roman", Font.ITALIC, 16));
+ Fonts.put(VisualiserFonts.NewVersion, new Font(
+ new HashMap() {
+ {
+ put(TextAttribute.FAMILY, "Times New Roman");
+ put(TextAttribute.FOREGROUND, Color.BLACK);
+ put(TextAttribute.BACKGROUND, Color.YELLOW);
+ put(TextAttribute.SIZE, 16);
+ }
+ }
+
+ ));
+ //
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ }
+ protected abstract String getEditorThemePath();
+ protected abstract String getForegroundHex();
+ protected abstract String getBackgroundHex();
+ protected abstract String getSelectionBackgroundHex();
+ protected abstract String getTreeBackgroundHex();
+ protected abstract String getBarForegroundHex();
+ protected abstract String getBarBackgroundHex();
+ protected abstract String getTableBackgroundHex();
+ protected abstract Color getGoodFontColor();
+ protected abstract Color getReadyFontColor2();
+ protected abstract Color getProgressFontColor();
+ protected abstract Color getBadFontColor();
+ protected abstract Color getFatalFontColor();
+ protected abstract Color getUnknownFontColor();
+ protected abstract Color getHyperlinkFontColor(); //-
+ //если использовать один и тот же объект на все едиторы пявляются странности
+ //значит при применении выделяем новый экземпляр.
+ public Theme getEditorTheme() {
+ Theme res = null;
+ try {
+ res = Theme.load(getClass().getResourceAsStream(getEditorThemePath()));
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ return res;
+ }
+}
diff --git a/src/Common/UI/Themes/VisualiserThemeName.java b/src/Common/UI/Themes/VisualiserThemeName.java
new file mode 100644
index 00000000..e378b0f8
--- /dev/null
+++ b/src/Common/UI/Themes/VisualiserThemeName.java
@@ -0,0 +1,5 @@
+package Common.UI.Themes;
+public enum VisualiserThemeName {
+ Light,
+ Dark
+}
diff --git a/src/Common/UI/Themes/dark_editor.xml b/src/Common/UI/Themes/dark_editor.xml
new file mode 100644
index 00000000..9855f78c
--- /dev/null
+++ b/src/Common/UI/Themes/dark_editor.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Common/UI/Themes/light_editor.xml b/src/Common/UI/Themes/light_editor.xml
new file mode 100644
index 00000000..0dc76953
--- /dev/null
+++ b/src/Common/UI/Themes/light_editor.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Common/UI/Trees/DataTree.java b/src/Common/UI/Trees/DataTree.java
new file mode 100644
index 00000000..f4162323
--- /dev/null
+++ b/src/Common/UI/Trees/DataTree.java
@@ -0,0 +1,39 @@
+package Common.UI.Trees;
+import Common.Current;
+import Common.Global;
+import Common.UI.DataControl_OLD;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreePath;
+public class DataTree extends StyledTree implements DataControl_OLD {
+ public DataTree(DefaultMutableTreeNode root_in) {
+ super(root_in);
+ }
+ public void ChangeCurrentObject(DefaultMutableTreeNode node) {
+ if (getCurrent() != Current.Undefined)
+ Current.set(getCurrent(), node.getUserObject());
+ }
+ @Override
+ public void ShowCurrentObject() throws Exception {
+ }
+ @Override
+ public void ShowNoCurrentObject() throws Exception {
+ }
+ @Override
+ public void SelectionAction(TreePath path) {
+ ChangeCurrentObject((DefaultMutableTreeNode) path.getLastPathComponent());
+ try {
+ ShowCurrentObject();
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ }
+ public void SelectNodeByCriteria(Object criteria) {
+ EventsOff();
+ TreePath res = ShowNodeByCriteria(criteria);
+ setSelectionPath(res);
+ ChangeCurrentObject((DefaultMutableTreeNode) res.getLastPathComponent());
+ EventsOn();
+ }
+}
+
diff --git a/src/Common/UI/Trees/GraphTreeCellRenderer.java b/src/Common/UI/Trees/GraphTreeCellRenderer.java
new file mode 100644
index 00000000..e26ae228
--- /dev/null
+++ b/src/Common/UI/Trees/GraphTreeCellRenderer.java
@@ -0,0 +1,27 @@
+package Common.UI.Trees;
+import Common.Current;
+import Common.UI.Themes.VisualiserFonts;
+import Common.Utils.Utils;
+import ProjectData.SapforData.FileObjectWithMessages;
+
+import javax.swing.*;
+import javax.swing.tree.DefaultMutableTreeNode;
+public class GraphTreeCellRenderer extends StyledTreeCellRenderer {
+ public java.awt.Component getTreeCellRendererComponent(
+ JTree tree, Object value,
+ boolean selected, boolean expanded,
+ boolean leaf, int row, boolean hasFocus) {
+ super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
+ Object o = ((DefaultMutableTreeNode) value).getUserObject();
+ if (o instanceof FileObjectWithMessages) {
+ FileObjectWithMessages target = (FileObjectWithMessages) o;
+ setIcon(Utils.getIcon(target.ImageKey()));
+ setFont(Current.getTheme().Fonts.get(target.getFont()));
+ } else {
+ setIcon(null);
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreeItalic));
+ }
+ setForeground(tree.getForeground());
+ return this;
+ }
+}
diff --git a/src/Common/UI/Trees/SelectableTree.java b/src/Common/UI/Trees/SelectableTree.java
new file mode 100644
index 00000000..6802ddb8
--- /dev/null
+++ b/src/Common/UI/Trees/SelectableTree.java
@@ -0,0 +1,18 @@
+package Common.UI.Trees;
+import Common.Current;
+import Common.UI.Selectable;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+public class SelectableTree extends DataTree {
+ public SelectableTree(DefaultMutableTreeNode root_in) {
+ super(root_in);
+ }
+ @Override
+ public void LeftMouseAction1() {
+ Object element = Current.get(getCurrent());
+ if ((element instanceof Selectable)) {
+ ((Selectable) element).SwitchSelection();
+ updateUI();
+ }
+ }
+}
diff --git a/src/Common/UI/Trees/SelectionTreeCellRenderer.java b/src/Common/UI/Trees/SelectionTreeCellRenderer.java
new file mode 100644
index 00000000..d21923ef
--- /dev/null
+++ b/src/Common/UI/Trees/SelectionTreeCellRenderer.java
@@ -0,0 +1,26 @@
+package Common.UI.Trees;
+import Common.Current;
+import Common.UI.Selectable;
+import Common.UI.Themes.VisualiserFonts;
+
+import javax.swing.*;
+import javax.swing.tree.DefaultMutableTreeNode;
+public class SelectionTreeCellRenderer extends StyledTreeCellRenderer {
+ public java.awt.Component getTreeCellRendererComponent(
+ JTree tree, Object value,
+ boolean selected, boolean expanded,
+ boolean leaf, int row, boolean hasFocus) {
+ super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
+ Object o = ((DefaultMutableTreeNode) value).getUserObject();
+ if (o instanceof Selectable) {
+ Selectable selectable = (Selectable) o;
+ setText(selectable.getSelectionText());
+ setIcon(selectable.GetSelectionIcon());
+ } else {
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreeItalic));
+ setIcon(null);
+ }
+ setForeground(tree.getForeground());
+ return this;
+ }
+}
diff --git a/src/Common/UI/Trees/StyledTree.java b/src/Common/UI/Trees/StyledTree.java
new file mode 100644
index 00000000..8193a34d
--- /dev/null
+++ b/src/Common/UI/Trees/StyledTree.java
@@ -0,0 +1,167 @@
+package Common.UI.Trees;
+import Common.Current;
+import Common.UI.Menus.GraphMenu;
+import Common.UI.Themes.ThemeElement;
+import Common.UI.Themes.VisualiserFonts;
+import Common.UI.UI;
+
+import javax.swing.*;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+public class StyledTree extends JTree implements ThemeElement {
+ //---------------------------------
+ private final GraphMenu menu;
+ public DefaultMutableTreeNode root = null;
+ //-включение /отключение событий --
+ protected boolean events_on = true;
+ public StyledTree(DefaultMutableTreeNode root_in) {
+ super(root_in);
+ root = root_in;
+ setOpaque(true);
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreePlain));
+ setToggleClickCount(0); //отключение сворачивание разворачивания по двойному клику
+ //--
+ if (!getRenderer().equals(TreeRenderers.RendererUndefined))
+ setCellRenderer(UI.TreeRenderers.get(getRenderer()));
+ //--
+ getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+ addTreeSelectionListener(e -> {
+ if (events_on && e.isAddedPath())
+ SelectionAction(e.getPath());
+ });
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 1) {
+ switch ((e.getButton())) {
+ //левая клавиша.
+ case MouseEvent.BUTTON1:
+ if (getSelectionCount() > 0) LeftMouseAction1();
+ break;
+ //колесо
+ case MouseEvent.BUTTON2:
+ break;
+ //правая клавиша
+ case MouseEvent.BUTTON3:
+ if (menu != null)
+ menu.Show(e);
+ break;
+ }
+ } else {
+ if (e.getClickCount() == 2) {
+ switch ((e.getButton())) {
+ case MouseEvent.BUTTON1:
+ if (getSelectionCount() > 0) LeftMouseAction2();
+ break;
+ }
+ }
+ }
+ }
+ });
+ menu = createMenu();
+ applyTheme();
+ ExpandAll();
+ }
+ public TreeRenderers getRenderer() {
+ return TreeRenderers.RendererUndefined;
+ }
+ public void EventsOn() {
+ events_on = true;
+ }
+ public void EventsOff() {
+ events_on = false;
+ }
+ public String getBranchesName() {
+ return "";
+ }
+ public void LeftMouseAction1() {
+ }
+ public void LeftMouseAction2() {
+ }
+ public void SelectionAction(TreePath e) {
+ }
+ @Override
+ public void applyTheme() {
+ setBackground(Current.getTheme().trees_background);
+ setForeground(Current.getTheme().foreground);
+ menu.applyTheme();
+ }
+ protected GraphMenu createMenu() {
+ return new GraphMenu(this);
+ }
+ public DefaultMutableTreeNode getNodeByRow(int row) {
+ DefaultMutableTreeNode res = null;
+ if (row >= 0) {
+ TreePath p = getPathForRow(row);
+ res = (DefaultMutableTreeNode) p.getLastPathComponent();
+ }
+ return res;
+ }
+ protected int getStartLine() {
+ return 0;
+ }
+ public void ExpandAll() {
+ for (int i = getStartLine(); i < getRowCount(); ++i)
+ expandRow(i);
+ }
+ public void CollapseAll() {
+ for (int i = getRowCount() - 1; i >= getStartLine(); --i) {
+ collapseRow(i);
+ }
+ }
+ protected boolean findNode(Object userObject, Object criteria) {
+ return true;
+ }
+ public DefaultMutableTreeNode FindByCriteria(Object criteria) {
+ DefaultMutableTreeNode res = root;
+ for (int i = 0; i < getRowCount(); ++i) {
+ DefaultMutableTreeNode node = getNodeByRow(i);
+ if (findNode(node.getUserObject(), criteria)) {
+ res = node;
+ break;
+ }
+ }
+ return res;
+ }
+ public TreePath ShowNode(DefaultMutableTreeNode node) {
+ TreePath res = new TreePath(((DefaultTreeModel) getModel()).getPathToRoot(node));
+ scrollPathToVisible(res);
+ return res;
+ }
+ public TreePath ShowNodeByCriteria(Object criteria) {
+ return ShowNode(FindByCriteria(criteria));
+ }
+ public void SelectNodeByCriteria(Object criteria) {
+ EventsOff();
+ TreePath res = ShowNodeByCriteria(criteria);
+ setSelectionPath(res);
+ EventsOn();
+ }
+ public void SelectNode(DefaultMutableTreeNode node) {
+ setSelectionPath(new TreePath(((DefaultTreeModel) getModel()).getPathToRoot(node)));
+ }
+//https://stackoverflow.com/questions/7928839/adding-and-removing-nodes-from-a-jtree !!!
+ public void AddNode(DefaultMutableTreeNode parent, DefaultMutableTreeNode node){
+ parent.add(node);
+ DefaultTreeModel model = (DefaultTreeModel) getModel();
+ model.reload(parent);
+ //--->>
+ TreePath path = new TreePath(model.getPathToRoot(node)); //брать путь к узлу так и только так.иначе не работает.!!
+ setSelectionPath(path);
+ //scrollPathToVisible(path);
+ }
+ public void RemoveNode(DefaultMutableTreeNode node){
+ if (node.getParent()!=null) {
+ DefaultTreeModel model = (DefaultTreeModel) getModel();
+ model.removeNodeFromParent(node);
+ }
+ }
+ public void RefreshNode(DefaultMutableTreeNode node){
+ DefaultTreeModel model = (DefaultTreeModel) getModel();
+ model.reload(node);
+ }
+}
diff --git a/src/Common/UI/Trees/StyledTreeCellRenderer.java b/src/Common/UI/Trees/StyledTreeCellRenderer.java
new file mode 100644
index 00000000..91b5efe7
--- /dev/null
+++ b/src/Common/UI/Trees/StyledTreeCellRenderer.java
@@ -0,0 +1,15 @@
+package Common.UI.Trees;
+import Common.Current;
+import Common.UI.Themes.ThemeElement;
+
+import javax.swing.tree.DefaultTreeCellRenderer;
+public class StyledTreeCellRenderer extends DefaultTreeCellRenderer implements ThemeElement {
+ public StyledTreeCellRenderer() {
+ applyTheme();
+ }
+ @Override
+ public void applyTheme() {
+ setBackgroundNonSelectionColor(Current.getTheme().trees_background);
+ setBackgroundSelectionColor(Current.getTheme().selection_background);
+ }
+}
diff --git a/src/Common/UI/Trees/TreeForm.java b/src/Common/UI/Trees/TreeForm.java
new file mode 100644
index 00000000..8c00b1f0
--- /dev/null
+++ b/src/Common/UI/Trees/TreeForm.java
@@ -0,0 +1,30 @@
+package Common.UI.Trees;
+import Common.UI.ControlForm;
+import Common.UI.UI;
+
+import java.awt.*;
+public class TreeForm extends ControlForm {
+ public TreeForm(Class class_in) {
+ super(class_in);
+ }
+ //временно, чтобы не затрагивать коды раньше времени.
+ public StyledTree getTree() {
+ return control;
+ }
+ @Override
+ protected void refresh() {
+ getTree().revalidate();
+ getTree().repaint();
+ }
+ @Override
+ public void Show() {
+ super.Show();
+ content.add(scroll, BorderLayout.CENTER);
+ content.updateUI();
+ }
+ @Override
+ public void Clear() {
+ super.Clear();
+ UI.Clear(content);
+ }
+}
diff --git a/src/Common/UI/Trees/TreeRenderers.java b/src/Common/UI/Trees/TreeRenderers.java
new file mode 100644
index 00000000..0e817d6f
--- /dev/null
+++ b/src/Common/UI/Trees/TreeRenderers.java
@@ -0,0 +1,13 @@
+package Common.UI.Trees;
+public enum TreeRenderers {
+ RendererUndefined,
+ //-
+ RendererGraph,
+ RendererFile,
+ RendererRemoteFile,
+ RendererVersion,
+ RendererRule,
+ RendererAttachment,
+ RendererPackageVersion,
+ RendererSelection
+}
diff --git a/src/Common/UI/UI.java b/src/Common/UI/UI.java
new file mode 100644
index 00000000..c43a4884
--- /dev/null
+++ b/src/Common/UI/UI.java
@@ -0,0 +1,451 @@
+package Common.UI;
+import Common.Current;
+import Common.Database.DataSet;
+import Common.Global;
+import Common.UI.Menus_2023.BugReportsMenuBar.BugReportsMenuBar;
+import Common.UI.Menus_2023.CompilersMenuBar.CompilersMenuBar;
+import Common.UI.Menus_2023.ConfigurationsMenuBar.ConfigurationsMenuBar;
+import Common.UI.Menus_2023.DVMParametersMenuBar.DVMParametersMenuBar;
+import Common.UI.Menus_2023.DataMenuBar;
+import Common.UI.Menus_2023.EnvironmentValuesMenuBar.EnvironmentValuesMenuBar;
+import Common.UI.Menus_2023.FastAccessMenuBar.FastAccessMenuBar;
+import Common.UI.Menus_2023.GroupsMenuBar.GroupsMenuBar;
+import Common.UI.Menus_2023.MachinesMenuBar.MachinesMenuBar;
+import Common.UI.Menus_2023.MainMenuBar.MainMenuBar;
+import Common.UI.Menus_2023.MainMenuBar.MainWindow;
+import Common.UI.Menus_2023.MakefilesMenuBar.MakefilesMenuBar;
+import Common.UI.Menus_2023.ModulesMenuBar.ModulesMenuBar;
+import Common.UI.Menus_2023.RemoteSapforsMenuBar.RemoteSapforsMenuBar;
+import Common.UI.Menus_2023.RunConfigurationsMenuBar.RunConfigurationsMenuBar;
+import Common.UI.Menus_2023.SapforConfigurationCommandsMenuBar.SapforConfigurationCommandsMenuBar;
+import Common.UI.Menus_2023.SapforConfigurationsMenuBar.SapforConfigurationsMenuBar;
+import Common.UI.Menus_2023.SapforTasksMenuBar.SapforTasksMenuBar;
+import Common.UI.Menus_2023.SapforTasksPackagesBar.SapforTasksPackagesBar;
+import Common.UI.Menus_2023.SubscribersMenuBar.SubscribersMenuBar;
+import Common.UI.Menus_2023.TasksPackagesMenuBar.TasksPackagesMenuBar;
+import Common.UI.Menus_2023.TestRunTasksMenuBar.TestRunTasksMenuBar;
+import Common.UI.Menus_2023.TestsMenuBar.TestsMenuBar;
+import Common.UI.Menus_2023.UsersMenuBar.UsersMenuBar;
+import Common.UI.Menus_2023.VariantsMenuBar.VariantsMenuBar;
+import Common.UI.Menus_2023.VersionsMenuBar.VersionsMenuBar;
+import Common.UI.Tables.*;
+import Common.UI.Themes.*;
+import Common.UI.Trees.GraphTreeCellRenderer;
+import Common.UI.Trees.SelectionTreeCellRenderer;
+import Common.UI.Windows.FormType;
+import Common.UI.Windows.SearchReplaceForm;
+import GlobalData.Compiler.CompilersDBTable;
+import GlobalData.CompilerEnvironment.UI.CompilerEnvironmentValueEditor;
+import GlobalData.CompilerEnvironment.UI.CompilerEnvironmentValueRenderer;
+import GlobalData.CompilerOption.UI.CompilerOptionParameterNameRenderer;
+import GlobalData.CompilerOption.UI.CompilerOptionParameterValueEditor;
+import GlobalData.CompilerOption.UI.CompilerOptionParameterValueRenderer;
+import GlobalData.DVMParameter.DVMParameterDBTable;
+import GlobalData.EnvironmentValue.EnvironmentValuesDBTable;
+import GlobalData.Machine.MachinesDBTable;
+import GlobalData.Makefile.MakefilesDBTable;
+import GlobalData.Module.ModulesDBTable;
+import GlobalData.RemoteFile.UI.RemoteFileChooser;
+import GlobalData.RemoteFile.UI.RemoteFileRenderer;
+import GlobalData.RemoteSapfor.RemoteSapforsDBTable;
+import GlobalData.RunConfiguration.RunConfigurationsDBTable;
+import GlobalData.SapforProfile.SapforProfilesDBTable;
+import GlobalData.Settings.SettingName;
+import GlobalData.Tasks.CompilationTask.CompilationTasksDBTable;
+import GlobalData.Tasks.RunTask.RunTasksDBTable;
+import GlobalData.User.UsersDBTable;
+import ProjectData.DBArray.ArraysDBTable;
+import ProjectData.Files.UI.FilesTreeCellRenderer;
+import ProjectData.Project.UI.PackageVersionsTreeCellRenderer;
+import ProjectData.Project.UI.VersionsTreeCellRenderer;
+import ProjectData.SapforData.Arrays.ArraysSet;
+import ProjectData.SapforData.Arrays.UI.DimensionRenderer;
+import ProjectData.SapforData.Arrays.UI.DimensionStateChanger;
+import ProjectData.SapforData.Arrays.UI.RulesTreeCellRenderer;
+import ProjectData.SapforData.Regions.RegionsSet;
+import ProjectData.SapforData.Variants.UI.VariantRankRenderer;
+import ProjectData.SapforData.Variants.VariantsSet;
+import Repository.BugReport.BugReportsDBTable;
+import Repository.Component.UI.ComponentsForm;
+import Repository.Subscribes.SubsribersDBTable;
+import TestingSystem.Configuration.UI.ConfigurationDBTable;
+import TestingSystem.Group.GroupsDBTable;
+import TestingSystem.Sapfor.SapforConfiguration.SapforConfigurationDBTable;
+import TestingSystem.Sapfor.SapforConfigurationCommand.SapforConfigurationCommandsDBTable;
+import TestingSystem.Sapfor.SapforTask.SapforTasksDBTable;
+import TestingSystem.Sapfor.SapforTasksPackage.SapforTasksPackagesDBTable;
+import TestingSystem.Tasks.TestRunTasksDBTable;
+import TestingSystem.TasksPackage.TasksPackageDBTable;
+import TestingSystem.Test.TestDBTable;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.UI.Interface.VersionsWindow;
+import Visual_DVM_2021.UI.Main.MainForm;
+import Visual_DVM_2021.UI.Main.ProfilesForm;
+import Visual_DVM_2021.UI.Main.VersionsForm;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleContext;
+import javax.swing.*;
+import javax.swing.event.ChangeListener;
+import javax.swing.table.TableCellEditor;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.text.DefaultFormatter;
+import javax.swing.text.DefaultHighlighter;
+import javax.swing.text.Highlighter;
+import javax.swing.tree.TreeCellRenderer;
+import java.awt.*;
+import java.util.LinkedHashMap;
+import java.util.Stack;
+import java.util.Vector;
+
+import static Common.UI.Tables.TableEditors.*;
+import static Common.UI.Tables.TableRenderers.*;
+import static Common.UI.Trees.TreeRenderers.*;
+public class UI {
+ public static MenuElement[] last_menu_path;
+ public static MainMenuBar mainMenuBar = null;
+ public static VersionsMenuBar versionsMenuBar = null;
+ public static FastAccessMenuBar fastAccessMenuBar = null;
+ //------------
+ public static VersionsWindow versionsWindow = null;
+ //------------
+ public static final Highlighter.HighlightPainter GoodLoopPainter = new DefaultHighlighter.DefaultHighlightPainter(new Color(152, 251, 152, 90));
+ public static final Highlighter.HighlightPainter BadLoopPainter = new DefaultHighlighter.DefaultHighlightPainter(new Color(240, 128, 128, 90));
+ public static LinkedHashMap TableRenderers = new LinkedHashMap<>();
+ public static LinkedHashMap TableEditors = new LinkedHashMap<>();
+ public static LinkedHashMap TreeRenderers = new LinkedHashMap<>();
+ public static LinkedHashMap themes = new LinkedHashMap<>();
+ public static LinkedHashMap windows = new LinkedHashMap<>();
+ public static Stack windowsStack = new Stack<>();
+ //-----
+ public static LinkedHashMap menuBars = new LinkedHashMap<>();
+ //-----
+ public static void Clear(Container container) {
+ container.removeAll();
+ container.repaint();
+ container.revalidate();
+ }
+ // http://java-online.ru/swing-joptionpane.xhtml
+ public static void TrySelect(JComboBox box, T value_in) {
+ if (value_in != null) {
+ for (int i = 0; i < box.getItemCount(); ++i) {
+ T value = (T) box.getItemAt(i);
+ if (value.equals(value_in)) {
+ box.setSelectedIndex(i);
+ return;
+ }
+ }
+ box.addItem(value_in);
+ box.setSelectedIndex(box.getItemCount() - 1);
+ }
+ }
+ public static void TrySelect_s(JComboBox box, String value_string_in) {
+ for (int i = 0; i < box.getItemCount(); ++i) {
+ Object value = box.getItemAt(i);
+ if (value.toString().equals(value_string_in)) {
+ box.setSelectedIndex(i);
+ return;
+ }
+ }
+ }
+ public static RemoteFileChooser getRemoteFileChooser() {
+ return (RemoteFileChooser) windows.get(FormType.RemoteFileChooser);
+ }
+ public static ComponentsForm getComponentsWindow() {
+ return (ComponentsForm) windows.get(FormType.Components);
+ }
+ public static boolean HasNewMainWindow() {
+ return getMainWindow() != null;
+ }
+ public static SearchReplaceForm getSearchReplaceForm() {
+ return (SearchReplaceForm) windows.get(FormType.SearchReplace);
+ }
+ public static void refreshTheme() {
+ Current.set(Current.Theme, themes.get(Global.db.settings.get(SettingName.DarkThemeOn).toBoolean() ? VisualiserThemeName.Dark : VisualiserThemeName.Light));
+ // refreshTheme_r(Visualiser.getMainWindow().MainPanel);
+ /*
+ refreshTheme_r(Visualiser.searchReplaceForm.MainPanel);
+ refreshTheme_r(Visualiser.ComponentsWindow.fields.MainPanel);
+ refreshTheme_r(Visualiser.remoteFileChooser.fields.MainPanel);
+ refreshTheme_r(Visualiser.runStatisticForm.fields.MainPanel);
+ //-----------------------------------------------------------------
+
+ UIManager.put("ToolTip.background", Current.getTheme().background);
+ UIManager.put("ToolTip.foreground", Current.getTheme().foreground);
+ UIManager.put("Panel.background", Current.getTheme().background);
+ UIManager.put("Panel.foreground", Current.getTheme().foreground);
+
+ UIManager.put("TextPane.background", Current.getTheme().background);
+ UIManager.put("TextPane.foreground", Current.getTheme().foreground);
+
+ UIManager.put("Label.background", Current.getTheme().background);
+ UIManager.put("Label.foreground", Current.getTheme().foreground);
+
+ UIManager.put("ToolBar.background", Current.getTheme().background);
+ UIManager.put("ToolBar.foreground", Current.getTheme().foreground);
+
+ for (TableCellRenderer renderer : TableRenderers.values()) {
+ if (renderer instanceof WindowControl) {
+ ((WindowControl) renderer).applyTheme();
+ }
+ }
+ for (TreeCellRenderer renderer : TreeRenderers.values()) {
+ if (renderer instanceof WindowControl) {
+ ((WindowControl) renderer).applyTheme();
+ }
+ }
+ //для текущего файла отдельно
+ /// if (Current.HasFile())
+ // Current.getFile().form.Body.applyTheme();
+ //------------
+ // UIManager.put("TabbedPane.unselectedForeground", Color.red);
+ // UIManager.put("TabbedPane.selectedBackground", Color.black);
+ //----------------------------
+ */
+ }
+ public static void CreateMenus() {
+ mainMenuBar = new MainMenuBar();
+ versionsMenuBar = new VersionsMenuBar();
+ fastAccessMenuBar = new FastAccessMenuBar();
+ //---------------------------------------------------->>
+ menuBars.put(BugReportsDBTable.class, new BugReportsMenuBar());
+ //---------------------------------------------------->>
+ menuBars.put(GroupsDBTable.class, new GroupsMenuBar());
+ menuBars.put(TestDBTable.class, new TestsMenuBar());
+ menuBars.put(ConfigurationDBTable.class, new ConfigurationsMenuBar());
+ menuBars.put(TasksPackageDBTable.class, new TasksPackagesMenuBar());
+ menuBars.put(TestRunTasksDBTable.class, new TestRunTasksMenuBar());
+ //--->>>
+ menuBars.put(MachinesDBTable.class, new MachinesMenuBar());
+ menuBars.put(UsersDBTable.class, new UsersMenuBar());
+ menuBars.put(CompilersDBTable.class, new CompilersMenuBar());
+ menuBars.put(MakefilesDBTable.class, new MakefilesMenuBar());
+ menuBars.put(ModulesDBTable.class, new ModulesMenuBar());
+ menuBars.put(RunConfigurationsDBTable.class, new RunConfigurationsMenuBar());
+ menuBars.put(EnvironmentValuesDBTable.class, new EnvironmentValuesMenuBar());
+ menuBars.put(DVMParameterDBTable.class, new DVMParametersMenuBar());
+ menuBars.put(CompilationTasksDBTable.class, new DataMenuBar("задачи на компиляцию"));
+ menuBars.put(RunTasksDBTable.class, new DataMenuBar("задачи на запуск"));
+ //---->>
+ menuBars.put(SapforConfigurationDBTable.class, new SapforConfigurationsMenuBar());
+ menuBars.put(SapforConfigurationCommandsDBTable.class, new SapforConfigurationCommandsMenuBar());
+ menuBars.put(RemoteSapforsDBTable.class, new RemoteSapforsMenuBar());
+ menuBars.put(SapforTasksPackagesDBTable.class, new SapforTasksPackagesBar());
+ menuBars.put(SapforTasksDBTable.class, new SapforTasksMenuBar());
+ //---->>
+ menuBars.put(RegionsSet.class, new DataMenuBar("области распараллеливания"));
+ menuBars.put(ArraysSet.class, new DataMenuBar("массивы"));
+ menuBars.put(ArraysDBTable.class, new DataMenuBar("сохранённые состояния") {
+ @Override
+ public void createSelectionButtons(DataSet dataSet) {
+ //не нужны.
+ }
+ });
+ menuBars.put(VariantsSet.class, new VariantsMenuBar());
+ menuBars.put(SubsribersDBTable.class, new SubscribersMenuBar());
+ menuBars.put(SapforProfilesDBTable.class, new DataMenuBar("профили", PassCode_2021.SaveProfile, PassCode_2021.EditProfile, PassCode_2021.ApplyProfile,PassCode_2021.DeleteProfile));
+ //---->>
+ }
+ public static void CreateWindows() {
+ windows.put(FormType.SearchReplace, new SearchReplaceForm());
+ windows.put(FormType.RemoteFileChooser, new RemoteFileChooser());
+ windows.put(FormType.Profiles, new ProfilesForm());
+ windows.put(FormType.Main, new MainForm());
+ //---------------------------------------
+ getMainWindow().Show();
+ }
+ public static MainWindow getMainWindow() {
+ return (MainWindow) windows.get(FormType.Main);
+ }
+ //-
+ public static void CreateAll() {
+ //
+ UIManager.put(
+ "FileChooser.openButtonText", "Открыть");
+ UIManager.put(
+ "FileChooser.saveButtonText", "Сохранить");
+ UIManager.put(
+ "FileChooser.cancelButtonText", "Отмена");
+ UIManager.put(
+ "FileChooser.fileNameLabelText", "Наименование файла");
+ UIManager.put(
+ "FileChooser.filesOfTypeLabelText", "Типы файлов");
+ UIManager.put(
+ "FileChooser.lookInLabelText", "Директория");
+ UIManager.put(
+ "FileChooser.saveInLabelText", "Сохранить в директории");
+ UIManager.put(
+ "FileChooser.folderNameLabelText", "Путь директории");
+ //
+ //
+ UIManager.put("OptionPane.yesButtonText", "Да");
+ UIManager.put("OptionPane.noButtonText", "Нет");
+ UIManager.put("OptionPane.cancelButtonText", "Отмена");
+ UIManager.put("OptionPane.okButtonText", "Готово");
+ //
+ //
+ themes.put(VisualiserThemeName.Light, new LightVisualiserTheme());
+ themes.put(VisualiserThemeName.Dark, new DarkVisualiserTheme());
+ //по умолчанию поставить светлую тему. потому что до загрузки бд работаем с таблицей компонент.
+ Current.set(Current.Theme, themes.get(VisualiserThemeName.Light));
+ //
+ //
+ TableRenderers.put(RendererDate, new DateRenderer_());
+ TableRenderers.put(RendererProgress, new ProgressBarRenderer());
+ TableRenderers.put(RendererSelect, new DBObjectSelectionRenderer());
+ TableRenderers.put(RendererDimension, new DimensionRenderer());
+ TableRenderers.put(RendererMultiline, new MultilineRenderer());
+ TableRenderers.put(RendererHyperlinks, new HyperlinksRenderer());
+ TableRenderers.put(RendererTopLeft, new TopLeftRenderer());
+ TableRenderers.put(RendererMaskedInt, new MaskedIntegerValueRenderer());
+ TableRenderers.put(RendererVariantRank, new VariantRankRenderer());
+ TableRenderers.put(RendererHiddenList, new HiddenListRenderer());
+ TableRenderers.put(RendererWrapText, new WrapTextRenderer());
+ TableRenderers.put(RendererCompilerOptionParameterValue, new CompilerOptionParameterValueRenderer());
+ TableRenderers.put(RendererCompilerOptionParameterName, new CompilerOptionParameterNameRenderer());
+ TableRenderers.put(RendererCompilerEnvironmentValue, new CompilerEnvironmentValueRenderer());
+ TableRenderers.put(RendererStatusEnum, new StatusEnumRenderer());
+ //---------------------------------------------
+ TreeRenderers.put(RendererGraph, new GraphTreeCellRenderer());
+ TreeRenderers.put(RendererRemoteFile, new RemoteFileRenderer());
+ TreeRenderers.put(RendererFile, new FilesTreeCellRenderer());
+ TreeRenderers.put(RendererVersion, new VersionsTreeCellRenderer());
+ TreeRenderers.put(RendererPackageVersion, new PackageVersionsTreeCellRenderer());
+ TreeRenderers.put(RendererRule, new RulesTreeCellRenderer());
+ TreeRenderers.put(RendererSelection, new SelectionTreeCellRenderer());
+ //----------------------------------------------
+ TableEditors.put(EditorSelect, new DBObjectSelector());
+ TableEditors.put(EditorHyperlinks, new VectorEditor());
+ TableEditors.put(EditorDimension, new DimensionStateChanger());
+ TableEditors.put(EditorCompilerOptionParameterValue, new CompilerOptionParameterValueEditor());
+ TableEditors.put(EditorCompilerEnvironmentValue, new CompilerEnvironmentValueEditor());
+ //
+ }
+ public static void printAccessible_r(Accessible accessible) {
+ System.out.print(accessible.getClass().getSimpleName() + ": children_count: ");
+ AccessibleContext context = accessible.getAccessibleContext();
+ System.out.println(context.getAccessibleChildrenCount());
+ for (int i = 0; i < context.getAccessibleChildrenCount(); ++i) {
+ printAccessible_r(context.getAccessibleChild(i));
+ }
+ }
+ public static void refreshTheme_r(Accessible accessible) {
+ // System.out.println(accessible.getClass().getSimpleName() + ": children_count: ");
+ AccessibleContext context = accessible.getAccessibleContext();
+ if (accessible instanceof ThemeElement) {
+ // System.out.println(accessible.getClass().getSimpleName() + ": refresh theme");
+ ((ThemeElement) accessible).applyTheme();
+ } else {
+ if ((accessible instanceof JPanel) ||
+ (accessible instanceof JLabel) ||
+ (accessible instanceof JToolBar) ||
+ (accessible instanceof JTabbedPane) ||
+ (accessible instanceof JScrollPane) ||
+ (accessible instanceof JSplitPane) ||
+ (accessible instanceof JTextField) ||
+ (accessible instanceof JCheckBox)
+ ) {
+ } else if (accessible instanceof JTextArea) {
+ accessible.getAccessibleContext().getAccessibleComponent().setBackground(Current.getTheme().background);
+ accessible.getAccessibleContext().getAccessibleComponent().setForeground(Current.getTheme().trees_background);
+ }
+ }
+ for (int i = 0; i < context.getAccessibleChildrenCount(); ++i) {
+ refreshTheme_r(context.getAccessibleChild(i));
+ }
+ }
+ public static void CreateComponentsForm() {
+ windows.put(FormType.Components, new ComponentsForm());
+ }
+ public static ProfilesForm getProfilesWindow() {
+ return (ProfilesForm) windows.get(FormType.Profiles);
+ }
+ public static Component getFrontWindow() {
+ Component res = null;
+ try {
+ res = windowsStack.peek();
+ } catch (Exception ex) {
+ System.out.println("NO FRONT WINDOW FOUND");
+ }
+ return res;
+ }
+ //-----
+ public static void ShowTabsNames(JTabbedPane tabs) {
+ ShowTabsNames(tabs, 0);
+ }
+ public static void ShowTabsNames(JTabbedPane tabs, int startIndex) {
+ boolean flag = Global.db.settings.get(SettingName.ShowFullTabsNames).toBoolean();
+ for (int i = startIndex; i < tabs.getTabCount(); ++i)
+ tabs.setTitleAt(i, flag ? tabs.getToolTipTextAt(i) : "");
+ }
+ public static boolean Contains(Vector list, String line, int max_index) {
+ int last_index = -1;
+ for (int i = 0; i < list.size(); ++i)
+ if (list.get(i).equals(line)) last_index = i;
+ return (last_index >= max_index);
+ }
+ public static void MakeSpinnerRapid(JSpinner spinner, ChangeListener listener) {
+ JComponent comp = spinner.getEditor();
+ JFormattedTextField field = (JFormattedTextField) comp.getComponent(0);
+ DefaultFormatter formatter = (DefaultFormatter) field.getFormatter();
+ formatter.setCommitsOnValidEdit(true);
+ formatter.setAllowsInvalid(true);
+ spinner.addChangeListener(listener);
+ }
+ //---------------
+ public static boolean Question(Component parent, String text) {
+ return !Current.hasUI() || (JOptionPane.showConfirmDialog(parent,
+ text + "?",
+ "Подтверждение",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE) == 0);
+ }
+ public static boolean Question(String text) {
+ return Question(getFrontWindow(), text);
+ }
+ public static void Info(String message) {
+ if (Current.hasUI())
+ JOptionPane.showMessageDialog(getFrontWindow(), message, "", 1);
+ }
+ public static void Error(String message) {
+ if (Current.hasUI())
+ JOptionPane.showMessageDialog(getFrontWindow(), message, "", 0);
+ }
+ public static boolean Warning(String text) {
+ return !Current.hasUI() ||
+ JOptionPane.showConfirmDialog(getFrontWindow(),
+ text + "\nВы уверены?",
+ "Подтверждение",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.WARNING_MESSAGE) == 0;
+ }
+ //--
+ public static VersionsWindow getVersionsWindow() {
+ return versionsWindow;
+ }
+ public static void CreateVersionsWindow() {
+ versionsWindow = new VersionsForm(Current.getRoot());
+ }
+ //-
+ public static void ShowSearchForm(boolean replace) {
+ getSearchReplaceForm().setMode(replace);
+ getSearchReplaceForm().ShowMode();
+ ShowSearchForm();
+ }
+ public static void HideSearchForm() {
+ if (getSearchReplaceForm().isVisible())
+ getSearchReplaceForm().setVisible(false);
+ }
+ public static void ShowSearchForm() {
+ if (getSearchReplaceForm().isVisible())
+ getSearchReplaceForm().Refresh();
+ else
+ getSearchReplaceForm().Show();
+ }
+ public static void ShowComponentsWindow() {
+ getComponentsWindow().ShowDialog("");
+ }
+ public static void ShowProfilesWindow() {
+ getProfilesWindow().ShowDialog("");
+ }
+}
diff --git a/src/Common/UI/VisualiserStringList.java b/src/Common/UI/VisualiserStringList.java
new file mode 100644
index 00000000..40ec4445
--- /dev/null
+++ b/src/Common/UI/VisualiserStringList.java
@@ -0,0 +1,38 @@
+package Common.UI;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+import java.util.Vector;
+public class VisualiserStringList extends JList {
+ DefaultListModel elements = null;
+ //-
+ public VisualiserStringList() {
+ this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ }
+ public void fill(Vector content) {
+ elements = new DefaultListModel<>();
+ for (String s : content)
+ elements.addElement(Utils.Brackets(s));
+ setModel(elements);
+ }
+ public String pack() {
+ String res = "";
+ for (int i = 0; i < elements.getSize(); ++i) {
+ String s = elements.getElementAt(i);
+ s = s.substring(1, s.length() - 1);
+ res+=s+"\n";
+ }
+ return res;
+ }
+ public void addElement(String element) {
+ String element_ = Utils.Brackets(element);
+ if (!elements.contains(element_))
+ elements.addElement(element_);
+ else UI.Info("элемент " + element_ + " уже существует.");
+ }
+ public void removeElement(String element) {
+ if (element != null)
+ elements.removeElement(element);
+ else UI.Info("элемент не выбран");
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/DBObjectDialog.java b/src/Common/UI/Windows/Dialog/DBObjectDialog.java
new file mode 100644
index 00000000..70804502
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/DBObjectDialog.java
@@ -0,0 +1,24 @@
+package Common.UI.Windows.Dialog;
+import Common.Database.DBObject;
+public abstract class DBObjectDialog extends Dialog {
+ public boolean edit = false;
+ public DBObjectDialog(Class f) {
+ super(f);
+ }
+ @Override
+ public void Init(Object... params) {
+ //тут входной параметр всегда объект. он же и есть Result
+ //считаем что он всегда создан.
+ Result = (T) params[0];
+ fillFields();
+ }
+ public void SetEditLimits() {
+ //установить ограничения если объект в режиме редактирования( например нельзя менять тип машины, или почту адресата)
+ }
+ public void fillFields() {
+ //отобразить объект
+ }
+ public void SetReadonly(){
+ //заблокировать окно для редактирования
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/Dialog.java b/src/Common/UI/Windows/Dialog/Dialog.java
new file mode 100644
index 00000000..7992b2ad
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/Dialog.java
@@ -0,0 +1,160 @@
+package Common.UI.Windows.Dialog;
+import Common.Current;
+import Common.Global;
+import Common.UI.Themes.ThemeElement;
+import Common.UI.Themes.VisualiserFonts;
+import Common.UI.UI;
+import Common.Utils.TextLog;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+//T Тип объекта
+//F Тип полей.
+public class Dialog extends JDialog implements ThemeElement {
+ public F fields; //рабочая область диалога.
+ public String title_text;
+ public JLabel lTitle = new JLabel();
+ public boolean OK = false;
+ //--------------------------------------
+ public T Result = null;
+ public Class f = null;
+ public TextLog Log = new TextLog(); //журнал валидации.
+ protected JScrollPane scroll = null;
+ protected JPanel buttonsPane = null;
+ protected JButton btnOK = null;
+ protected JButton btnCancel = null;
+ protected JCheckBox showNoMore = null;
+ public String getIconPath() {
+ return "";
+ }
+ protected Component content;
+ //--------------------------------------
+ public Dialog(Class f_in) {
+ f = f_in;
+ setModal(true);
+ toFront();
+ getContentPane().setLayout(new BorderLayout());
+ lTitle.setFont(Current.getTheme().Fonts.get(VisualiserFonts.Menu));
+ if (!getIconPath().isEmpty()) {
+ setIconImage(Utils.getIcon(getIconPath()).getImage());
+ }
+ //делаем титульную надпись в самом окне чтобы не зависеть от языковой политики ОС
+ getContentPane().add(lTitle, BorderLayout.NORTH);
+ //сюда добавляется содержимое.
+ content = null;
+ CreateContent();
+ InitFields(); //дополнительная инициализация полей..
+ getContentPane().add(NeedsScroll() ? (scroll = new JScrollPane(content)) : content, BorderLayout.CENTER);
+ CreateButtons();
+ // call onCancel() when cross is clicked
+ setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+ addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ UI.windowsStack.pop();
+ System.out.println("Previous Front Window");
+ onCancel();
+ onClose();
+ }
+ });
+ // pack(); //авторазмер окна.
+ setLocationRelativeTo(null);
+ LoadSize();
+ }
+ public void CreateContent() {
+ try {
+ content = (fields = f.newInstance()).getContent();
+ //--?
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ }
+ public void onClose() {
+
+ }
+ public void LoadSize() {
+ setMinimumSize(new Dimension(getDefaultWidth(), getDefaultHeight()));
+ setPreferredSize(new Dimension(getDefaultWidth(), getDefaultHeight()));
+ }
+ //бывает что у полей собственные скроллы
+ public boolean NeedsScroll() {
+ return true;
+ }
+ public boolean NeedsShowNoMore() {
+ return false;
+ }
+ public int getDefaultWidth() {
+ return 800;
+ }
+ public int getDefaultHeight() {
+ return 450;
+ }
+ //создание полей формы( без заполнения)
+ public void InitFields() {
+ }
+ public void CreateButtons() {
+ btnOK = new JButton(" OK ");
+ btnCancel = new JButton("Отмена");
+ buttonsPane = new JPanel();
+ buttonsPane.setOpaque(true);
+ buttonsPane.setBackground(Color.WHITE);
+ btnOK.addActionListener(e -> onOK());
+ btnCancel.addActionListener(e -> onCancel());
+ buttonsPane.add(btnOK);
+ buttonsPane.add(btnCancel);
+ if (NeedsShowNoMore()) {
+ buttonsPane.add(showNoMore = new JCheckBox("больше не показывать"));
+ showNoMore.setOpaque(true);
+ showNoMore.setBackground(Color.WHITE);
+ }
+ getContentPane().add(buttonsPane, BorderLayout.SOUTH);
+ }
+ public boolean isOnTop() {
+ return true;
+ }
+ public boolean ShowDialog(String title, Object... params) {
+ OK = false;
+ title_text = title;
+ Init(params);
+ ShowTitle();
+ setAlwaysOnTop(isOnTop());
+ UI.windowsStack.push(this);
+ System.out.println("New Front Window");
+ setVisible(true);
+ return OK;
+ }
+ public void ShowTitle() {
+ lTitle.setText(getTitleText());
+ }
+ public String getTitleText() {
+ return title_text;
+ }
+ public void Init(Object... params) {
+ }
+ public void onOK() {
+ Log.Clear();
+ validateFields();
+ if (Log.isEmpty()) {
+ ProcessResult();
+ OK = true;
+ CloseAction();
+ } else
+ UI.Error("Валидация не пройдена:\n" + Log.toString());
+ }
+ protected void onCancel() {
+ CloseAction();
+ }
+ public void CloseAction() {
+ dispose();
+ }
+ public void validateFields() {
+ }
+ public void ProcessResult() {
+ }
+ @Override
+ public void applyTheme() {
+ //todo -> Применение темы
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/DialogFields.java b/src/Common/UI/Windows/Dialog/DialogFields.java
new file mode 100644
index 00000000..1aa09bf3
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/DialogFields.java
@@ -0,0 +1,5 @@
+package Common.UI.Windows.Dialog;
+import java.awt.*;
+public interface DialogFields {
+ Component getContent();
+}
diff --git a/src/Common/UI/Windows/Dialog/DialogSlider.java b/src/Common/UI/Windows/Dialog/DialogSlider.java
new file mode 100644
index 00000000..2bddee83
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/DialogSlider.java
@@ -0,0 +1,9 @@
+package Common.UI.Windows.Dialog;
+import javax.swing.*;
+import java.awt.*;
+public class DialogSlider extends JSlider implements DialogFields {
+ @Override
+ public Component getContent() {
+ return this;
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/DialogSpinner.java b/src/Common/UI/Windows/Dialog/DialogSpinner.java
new file mode 100644
index 00000000..8304a914
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/DialogSpinner.java
@@ -0,0 +1,9 @@
+package Common.UI.Windows.Dialog;
+import javax.swing.*;
+import java.awt.*;
+public class DialogSpinner extends JSpinner implements DialogFields {
+ @Override
+ public Component getContent() {
+ return this;
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/DialogTextComboBox.java b/src/Common/UI/Windows/Dialog/DialogTextComboBox.java
new file mode 100644
index 00000000..51cf5369
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/DialogTextComboBox.java
@@ -0,0 +1,16 @@
+package Common.UI.Windows.Dialog;
+import Common.Current;
+import Common.UI.Themes.VisualiserFonts;
+
+import javax.swing.*;
+import java.awt.*;
+public class DialogTextComboBox extends JComboBox implements DialogFields {
+ public DialogTextComboBox() {
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Menu));
+ setEditable(false);
+ }
+ @Override
+ public Component getContent() {
+ return this;
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/DialogTextField.java b/src/Common/UI/Windows/Dialog/DialogTextField.java
new file mode 100644
index 00000000..b02466b8
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/DialogTextField.java
@@ -0,0 +1,10 @@
+package Common.UI.Windows.Dialog;
+import Common.UI.TextField.StyledTextField;
+
+import java.awt.*;
+public class DialogTextField extends StyledTextField implements DialogFields {
+ @Override
+ public Component getContent() {
+ return this;
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/DialogWrapText.java b/src/Common/UI/Windows/Dialog/DialogWrapText.java
new file mode 100644
index 00000000..0f3db907
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/DialogWrapText.java
@@ -0,0 +1,42 @@
+package Common.UI.Windows.Dialog;
+import Common.Current;
+import Common.UI.Themes.VisualiserFonts;
+
+import javax.swing.*;
+import java.awt.*;
+public class DialogWrapText extends JTextPane implements DialogFields {
+ public DialogWrapText(){
+ setOpaque(true);
+ setBackground(Color.WHITE);
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreeBold));
+ setEditable(false);
+ }
+ @Override
+ public Component getContent() {
+ return this;
+ }
+ /*
+ public void setTextW(String text_in){
+ String[] lines = text_in.split("\n");
+ String labelText = "";
+ if (lines.length == 1) {
+ labelText = text_in;
+ } else {
+ int i = 0;
+ for (String line : lines) {
+ String fline = "";
+ if (i == 0) {
+ fline = "" + line + " ";
+ } else if (i == lines.length - 1) {
+ fline = line + "";
+ } else {
+ fline = line + " ";
+ }
+ ++i;
+ labelText += fline;
+ }
+ }
+ setText(labelText);
+ }
+ */
+}
diff --git a/src/Common/UI/Windows/Dialog/NumberDialog.java b/src/Common/UI/Windows/Dialog/NumberDialog.java
new file mode 100644
index 00000000..65a0a8ca
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/NumberDialog.java
@@ -0,0 +1,11 @@
+package Common.UI.Windows.Dialog;
+public abstract class NumberDialog extends Dialog {
+ public NumberDialog(Class f) {
+ super(f);
+ }
+ @Override
+ public void Init(Object... params) {
+ if (params.length > 0) setNumber((int) params[0]);
+ }
+ public abstract void setNumber(int num_in);
+}
diff --git a/src/Common/UI/Windows/Dialog/PercentsForm.java b/src/Common/UI/Windows/Dialog/PercentsForm.java
new file mode 100644
index 00000000..dd59a09c
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/PercentsForm.java
@@ -0,0 +1,22 @@
+package Common.UI.Windows.Dialog;
+public class PercentsForm extends SliderNumberForm {
+ public PercentsForm() {
+ }
+ @Override
+ public String getTitleText() {
+ return super.getTitleText() + "%";
+ }
+ @Override
+ public void InitFields() {
+ fields.setPaintLabels(true);
+ fields.setPaintTicks(true);
+ fields.setPaintTrack(true);
+ fields.setSnapToTicks(true);
+ fields.setMinorTickSpacing(1);
+ fields.setMajorTickSpacing(25);
+ }
+ @Override
+ public void Init(Object... params) {
+ super.Init(params[0], 0, 100);
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/SessionMaxtimeDialog.java b/src/Common/UI/Windows/Dialog/SessionMaxtimeDialog.java
new file mode 100644
index 00000000..3a07ac8d
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/SessionMaxtimeDialog.java
@@ -0,0 +1,10 @@
+package Common.UI.Windows.Dialog;
+import javax.swing.*;
+public class SessionMaxtimeDialog extends SpinnerNumberForm {
+ public SessionMaxtimeDialog() {
+ }
+ @Override
+ public void InitFields() {
+ fields.setModel(new SpinnerNumberModel(10, 5, 65535, 1));
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/SliderNumberForm.java b/src/Common/UI/Windows/Dialog/SliderNumberForm.java
new file mode 100644
index 00000000..8152fdac
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/SliderNumberForm.java
@@ -0,0 +1,53 @@
+package Common.UI.Windows.Dialog;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+public class SliderNumberForm extends NumberDialog {
+ public SliderNumberForm() {
+ super(DialogSlider.class);
+ setResizable(false);
+ }
+ @Override
+ public void setNumber(int num_in) {
+ fields.setValue(num_in);
+ }
+ //тут всегда должно быть три параметра
+ //минимум нет смысла задавать меньше 1
+ @Override
+ public void Init(Object... params) {
+ if (params.length == 3) {
+ setNumber((Integer) params[0]);
+ fields.setMinimum((Integer) params[1]);
+ fields.setMaximum((Integer) params[2]);
+ }
+ fields.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent e) {
+ ShowTitle();
+ }
+ });
+ }
+ @Override
+ public void InitFields() {
+ fields.setPaintLabels(true);
+ fields.setPaintTicks(true);
+ fields.setPaintTrack(true);
+ fields.setSnapToTicks(false);
+ fields.setMinorTickSpacing(1);
+ fields.setMajorTickSpacing(1);
+ }
+ @Override
+ public int getDefaultWidth() {
+ return 600;
+ }
+ @Override
+ public int getDefaultHeight() {
+ return 200;
+ }
+ @Override
+ public String getTitleText() {
+ return title_text + " : " + fields.getValue();
+ }
+ @Override
+ public void ProcessResult() {
+ Result = fields.getValue();
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/SpinnerNumberForm.java b/src/Common/UI/Windows/Dialog/SpinnerNumberForm.java
new file mode 100644
index 00000000..88a4a3b5
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/SpinnerNumberForm.java
@@ -0,0 +1,22 @@
+package Common.UI.Windows.Dialog;
+public abstract class SpinnerNumberForm extends NumberDialog {
+ public SpinnerNumberForm() {
+ super(DialogSpinner.class);
+ }
+ @Override
+ public void setNumber(int num_in) {
+ fields.setValue(num_in);
+ }
+ @Override
+ public int getDefaultWidth() {
+ return 400;
+ }
+ @Override
+ public int getDefaultHeight() {
+ return 130;
+ }
+ @Override
+ public void ProcessResult() {
+ Result = (Integer) fields.getValue();
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/Text/ComboTextDialog.java b/src/Common/UI/Windows/Dialog/Text/ComboTextDialog.java
new file mode 100644
index 00000000..2aab5279
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/Text/ComboTextDialog.java
@@ -0,0 +1,35 @@
+package Common.UI.Windows.Dialog.Text;
+import Common.UI.Windows.Dialog.Dialog;
+import Common.UI.Windows.Dialog.DialogTextComboBox;
+
+import java.util.Vector;
+public class ComboTextDialog extends Dialog {
+ public ComboTextDialog() {
+ super(DialogTextComboBox.class);
+ }
+ @Override
+ public void ProcessResult() {
+ Result = (String) fields.getSelectedItem();
+ }
+ @Override
+ public void validateFields() {
+ if (fields.getSelectedItem() == null)
+ Log.Writeln("Элемент не выбран");
+ }
+ @Override
+ public void Init(Object... params) {
+ Vector sp = (Vector) params[0];
+ if (!sp.isEmpty()) {
+ for (Object p : sp)
+ fields.addItem(p.toString());
+ }
+ }
+ @Override
+ public int getDefaultWidth() {
+ return 450;
+ }
+ @Override
+ public int getDefaultHeight() {
+ return 135;
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/Text/FileNameForm.java b/src/Common/UI/Windows/Dialog/Text/FileNameForm.java
new file mode 100644
index 00000000..226531aa
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/Text/FileNameForm.java
@@ -0,0 +1,10 @@
+package Common.UI.Windows.Dialog.Text;
+import Common.Utils.Utils;
+public class FileNameForm extends TextFieldDialog {
+ public FileNameForm() {
+ }
+ @Override
+ public void validateFields() {
+ Utils.validateFileShortNewName(fields.getText(), Log);
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/Text/MultilineTextForm.java b/src/Common/UI/Windows/Dialog/Text/MultilineTextForm.java
new file mode 100644
index 00000000..66104582
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/Text/MultilineTextForm.java
@@ -0,0 +1,25 @@
+package Common.UI.Windows.Dialog.Text;
+import Common.UI.Editor.BaseEditor;
+public class MultilineTextForm extends TextDialog {
+ public MultilineTextForm() {
+ super(BaseEditor.class);
+ }
+ //при наследовании по умолчанию поля не присваивать!
+ //инициализация полей работает после конструктора предка!!
+ @Override
+ public void ProcessResult() {
+ Result = fields.getText();
+ }
+ @Override
+ public void InitFields() {
+ fields.setSearchEnabled(false);
+ fields.setLineWrap(true);
+ fields.setWrapStyleWord(true);
+ fields.setHighlightCurrentLine(false);
+ }
+ @Override
+ public void setText(String text_in) {
+ fields.setText(text_in);
+ fields.setCaretPosition(0);
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/Text/ReadOnlyMultilineTextForm.java b/src/Common/UI/Windows/Dialog/Text/ReadOnlyMultilineTextForm.java
new file mode 100644
index 00000000..d2d84d7c
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/Text/ReadOnlyMultilineTextForm.java
@@ -0,0 +1,12 @@
+package Common.UI.Windows.Dialog.Text;
+public class ReadOnlyMultilineTextForm extends MultilineTextForm {
+ public ReadOnlyMultilineTextForm() {
+ }
+ @Override
+ public void InitFields() {
+ fields.setEditable(false);
+ }
+ @Override
+ public void CreateButtons() {
+ }
+}
diff --git a/src/Common/UI/Windows/Dialog/Text/TextDialog.java b/src/Common/UI/Windows/Dialog/Text/TextDialog.java
new file mode 100644
index 00000000..eb025bfd
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/Text/TextDialog.java
@@ -0,0 +1,15 @@
+package Common.UI.Windows.Dialog.Text;
+import Common.UI.Windows.Dialog.Dialog;
+import Common.UI.Windows.Dialog.DialogFields;
+//текстовый диалог. возвращает текст. может иметь параметром исходный текст.
+public abstract class TextDialog extends Dialog {
+ public TextDialog(Class f) {
+ super(f);
+ }
+ @Override
+ public void Init(Object... params) {
+ if (params.length > 0) setText((String) params[0]);
+ }
+ public abstract void setText(String text_in);
+}
+
diff --git a/src/Common/UI/Windows/Dialog/Text/TextFieldDialog.java b/src/Common/UI/Windows/Dialog/Text/TextFieldDialog.java
new file mode 100644
index 00000000..71cbfcec
--- /dev/null
+++ b/src/Common/UI/Windows/Dialog/Text/TextFieldDialog.java
@@ -0,0 +1,35 @@
+package Common.UI.Windows.Dialog.Text;
+import Common.UI.Windows.Dialog.DialogTextField;
+
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+public class TextFieldDialog extends TextDialog {
+ public TextFieldDialog() {
+ super(DialogTextField.class);
+ setResizable(false);
+ fields.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+ onOK();
+ }
+ }
+ });
+ }
+ @Override
+ public int getDefaultWidth() {
+ return 450;
+ }
+ @Override
+ public int getDefaultHeight() {
+ return 135;
+ }
+ @Override
+ public void ProcessResult() {
+ Result = fields.getText();
+ }
+ @Override
+ public void setText(String text_in) {
+ fields.setText(text_in);
+ }
+}
diff --git a/src/Common/UI/Windows/Form.java b/src/Common/UI/Windows/Form.java
new file mode 100644
index 00000000..241f28e0
--- /dev/null
+++ b/src/Common/UI/Windows/Form.java
@@ -0,0 +1,98 @@
+package Common.UI.Windows;
+import Common.Global;
+import Common.UI.Themes.ThemeElement;
+import GlobalData.FormsParams.DBForm;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.sql.SQLException;
+public abstract class Form extends JFrame implements ThemeElement {
+ private DBForm info = null;
+ public Form() {
+ if (getIconName().length() > 0) setIconImage(new ImageIcon(Form.class.getResource(getIconName())).getImage());
+ SetListener();
+ this.setTitle(Global.isWindows ? getWTitleText() : getUTitleText());
+ pack();
+ setMinimumSize(new Dimension(getDefaultWidth(), getDefaultHeight()));
+ }
+ abstract protected JPanel getMainPanel();
+ public String getIconName() {
+ return "";
+ }
+ public String getWTitleText() {
+ return "";
+ }
+ public String getUTitleText() {
+ return "";
+ }
+ protected FormType getFormType() {
+ return FormType.Undefined;
+ }
+ protected void SetListener() {
+ setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+ addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ Close();
+ }
+ });
+ }
+ public int getDefaultWidth() {
+ return 800;
+ }
+ public int getDefaultHeight() {
+ return 450;
+ }
+ /*
+ *вызывать после перегрузки, чтобы отобразить окно.
+ */
+ public Component getRelative() {
+ return null;
+ }
+ public void Show() {
+ try {
+ LoadWindowParameters();
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ setContentPane(getMainPanel());
+ setVisible(true);
+ }
+ public void Close() {
+ try {
+ SaveWindowParameters();
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ setVisible(false);
+ dispose();
+ AfterClose();
+ }
+ public void AfterClose() {
+ }
+ public void LoadWindowParameters() throws SQLException, InstantiationException, IllegalAccessException, NoSuchFieldException {
+ if (!getFormType().equals(FormType.Undefined))
+ if (Global.db.forms.Data.containsKey(getFormType())) {
+ info = Global.db.forms.Data.get(getFormType());
+ info.Apply(this);
+ return;
+ }
+ setSize(getDefaultWidth(), getDefaultHeight());
+ setLocationRelativeTo(getRelative());
+ }
+ public void SaveWindowParameters() throws Exception {
+ if (!getFormType().equals(FormType.Undefined)) {
+ if (info != null) {
+ info.Init(this);
+ Global.db.Update(info);
+ } else
+ Global.db.Insert(new DBForm(getFormType(), this));
+ }
+ }
+ @Override
+ public void applyTheme() {
+ //todo -> применение темы.
+ }
+}
diff --git a/src/Common/UI/Windows/FormType.java b/src/Common/UI/Windows/FormType.java
new file mode 100644
index 00000000..a8654411
--- /dev/null
+++ b/src/Common/UI/Windows/FormType.java
@@ -0,0 +1,10 @@
+package Common.UI.Windows;
+public enum FormType {
+ Undefined,
+
+ Main,
+ SearchReplace,
+ Components,
+ RemoteFileChooser,
+ Profiles
+}
diff --git a/src/Common/UI/Windows/Sapfor.png b/src/Common/UI/Windows/Sapfor.png
new file mode 100644
index 00000000..0b6a7991
Binary files /dev/null and b/src/Common/UI/Windows/Sapfor.png differ
diff --git a/src/Common/UI/Windows/SearchReplaceForm.form b/src/Common/UI/Windows/SearchReplaceForm.form
new file mode 100644
index 00000000..ce846970
--- /dev/null
+++ b/src/Common/UI/Windows/SearchReplaceForm.form
@@ -0,0 +1,213 @@
+
+
diff --git a/src/Common/UI/Windows/SearchReplaceForm.java b/src/Common/UI/Windows/SearchReplaceForm.java
new file mode 100644
index 00000000..456e10c2
--- /dev/null
+++ b/src/Common/UI/Windows/SearchReplaceForm.java
@@ -0,0 +1,253 @@
+package Common.UI.Windows;
+import Common.Current;
+import Common.UI.TextField.StyledTextField;
+import Common.UI.Trees.StyledTree;
+import Common.UI.UI;
+import Common.Utils.Utils;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+import javafx.util.Pair;
+import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
+import org.fife.ui.rtextarea.SearchContext;
+import org.fife.ui.rtextarea.SearchEngine;
+import org.fife.ui.rtextarea.SearchResult;
+
+import javax.swing.*;
+import javax.swing.tree.DefaultMutableTreeNode;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.LinkedHashMap;
+public class SearchReplaceForm extends Form {
+ public JPanel MainPanel;
+ public boolean forward = true;
+ SearchContext context = null;
+ RSyntaxTextArea editor = null;
+ boolean replace_mode = false;
+ private JTextField tfFind;
+ private JTextField tfReplace;
+ private JCheckBox replaceOn;
+ private JCheckBox registerOn;
+ private JCheckBox wholeWordOn;
+ private JRadioButton rbUp;
+ private JRadioButton rbDown;
+ private JButton bAll;
+ private JButton bNext;
+ private JCheckBox loopOn;
+ private JLabel lCount;
+ private SearchResult result = null;
+ //https://techarks.ru/qa/java/kak-uznat-kakoj-iz-jlist-s-Y4/
+ public void ClearMarkers() {
+ //сброс выделения. решается подсовыванием пустой строки
+ context.setSearchFor("");
+ SearchEngine.find(editor, context);
+ DropMatchCount();
+ }
+ public void DropMatchCount() {
+ lCount.setText("0");
+ }
+ public void setEditor(RSyntaxTextArea editor_in) {
+ editor = editor_in;
+ }
+ @Override
+ protected JPanel getMainPanel() {
+ return MainPanel;
+ }
+ @Override
+ public void Close() {
+ ClearMarkers();
+ super.Close();
+ }
+ public void setMode(boolean replace) {
+ replace_mode = replace;
+ System.out.println("MODE CHANGED");
+ tfReplace.setEnabled(replace_mode);
+ String prefix = replace_mode ? "Заменить" : "Найти";
+ bNext.setText(prefix + " далее");
+ bAll.setText(prefix + " всё");
+ }
+ public void ShowMode() {
+ replaceOn.setSelected(replace_mode);
+ }
+ @Override
+ public Component getRelative() {
+ return (Component) UI.getMainWindow();
+ }
+ @Override
+ public int getDefaultWidth() {
+ return 650;
+ }
+ @Override
+ public int getDefaultHeight() {
+ return 400;
+ }
+ public void Refresh() {
+ String text = editor.getSelectedText();
+ if ((text != null) && !text.isEmpty())
+ tfFind.setText(text);
+ tfFind.requestFocus();
+ }
+ //-------------------------------
+ public void SwitchDirection(boolean direction_in) {
+ forward = direction_in;
+ if (forward) {
+ rbUp.setSelected(false);
+ rbDown.setSelected(true);
+ } else {
+ rbDown.setSelected(false);
+ rbUp.setSelected(true);
+ }
+ }
+ public void applyParams() {
+ String toFind = Utils.hideRegularMetasymbols(tfFind.getText());
+ String toReplace = Utils.hideRegularMetasymbols(tfReplace.getText());
+ System.out.println("toFind=" + toFind);
+ System.out.println("toReplace" + toReplace);
+ System.out.println("============");
+ context.setSearchFor(toFind);
+ context.setMatchCase(registerOn.isSelected());
+ context.setWholeWord(wholeWordOn.isSelected());
+ if (replace_mode)
+ context.setReplaceWith(toReplace);
+ DropMatchCount();
+ }
+ public void onAll() {
+ applyParams();
+ result = replace_mode ?
+ SearchEngine.replaceAll(editor, context) : SearchEngine.markAll(editor, context);
+ lCount.setText(String.valueOf(
+ replace_mode ? result.getCount() : result.getMarkedCount()));
+ }
+ public void onNext() {
+ applyParams();
+ context.setSearchForward(forward);
+ result = replace_mode ? SearchEngine.replace(editor, context) : SearchEngine.find(editor, context);
+ if (loopOn.isSelected() && !result.wasFound()) SwitchDirection(!forward);
+ lCount.setText(String.valueOf(result.getMarkedCount()));
+ }
+ @Override
+ protected FormType getFormType() {
+ return FormType.SearchReplace;
+ }
+ private void createUIComponents() {
+ // TODO: place custom component creation code here
+ tfFind = new StyledTextField();
+ tfReplace = new StyledTextField();
+ }
+ //------------------
+ //-
+ private JButton bSearchInFiles;
+ private JPanel filesTreePanel;
+ private JLabel lFilesMatchesCount;
+ public static String lastProjectPath = "";
+ public static LinkedHashMap matches = new LinkedHashMap<>();
+ public void dropFilesMatches() {
+ matches = new LinkedHashMap<>();
+ }
+ public void showNoFilesMatches() {
+ lFilesMatchesCount.setText("—");
+ UI.Clear(filesTreePanel);
+ }
+ public void showFilesMatches() {
+ long total = 0;
+ DefaultMutableTreeNode res = new DefaultMutableTreeNode("файлов " + matches.size());
+ for (String fileName : matches.keySet()) {
+ DefaultMutableTreeNode fileNode = new DefaultMutableTreeNode(new Pair(fileName, matches.get(fileName)) {
+ @Override
+ public String toString() {
+ return getKey() + ":" + getValue();
+ }
+ });
+ res.add(fileNode);
+ total += matches.get(fileName);
+ }
+ StyledTree matchesTree = new StyledTree(res) {
+ {
+ setRootVisible(false);
+ }
+ @Override
+ public void LeftMouseAction2() {
+ DefaultMutableTreeNode selectedFile = (DefaultMutableTreeNode) getLastSelectedPathComponent();
+ if (selectedFile != null) {
+ Pair info = (Pair) selectedFile.getUserObject();
+ if (Current.getProject().db.files.containsKey(info.getKey())) {
+ Pass_2021.passes.get(PassCode_2021.OpenCurrentFile).Do(Current.getProject().db.files.get(info.getKey()));
+ //--->>>
+ replaceOn.setSelected(false);
+ setMode(false);
+ SwitchDirection(true);
+ //-
+ bNext.requestFocus();
+ bNext.doClick();
+ }
+ }
+ }
+ };
+ filesTreePanel.add(matchesTree);
+ filesTreePanel.revalidate();
+ filesTreePanel.repaint();
+ lFilesMatchesCount.setText(String.valueOf(total));
+ }
+ @Override
+ public void Show() {
+ super.Show();
+ //------->>
+ showNoFilesMatches();
+ if (lastProjectPath.equals(Current.getProject().Home.getAbsolutePath()))
+ showFilesMatches();
+ else
+ dropFilesMatches();
+ //------->>
+ Refresh();
+ // setAlwaysOnTop(true);
+ }
+ public SearchReplaceForm() {
+ context = new SearchContext();
+ //-
+ context.setRegularExpression(true);
+ //-
+ rbDown.addActionListener(e -> SwitchDirection(!forward));
+ rbUp.addActionListener(e -> SwitchDirection(!forward));
+ bAll.addActionListener(e -> onAll());
+ bNext.addActionListener(e -> onNext());
+ replaceOn.addActionListener(e -> {
+ setMode(replaceOn.isSelected());
+ });
+ bNext.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.getKeyCode() == KeyEvent.VK_ENTER)
+ bNext.doClick();
+ }
+ });
+ tfFind.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ switch (e.getKeyCode()) {
+ case KeyEvent.VK_ENTER:
+ bNext.requestFocus();
+ bNext.doClick();
+ break;
+ }
+ }
+ });
+ bSearchInFiles.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ try {
+ showNoFilesMatches();
+ lastProjectPath = Current.getProject().Home.getAbsolutePath();
+ matches = Current.getProject().getMatches(
+ tfFind.getText(),
+ registerOn.isSelected(),
+ wholeWordOn.isSelected());
+ showFilesMatches();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ });
+ }
+}
diff --git a/src/Common/Utils/Files/ProjectsChooser.java b/src/Common/Utils/Files/ProjectsChooser.java
new file mode 100644
index 00000000..97f304b0
--- /dev/null
+++ b/src/Common/Utils/Files/ProjectsChooser.java
@@ -0,0 +1,25 @@
+package Common.Utils.Files;
+import Common.Utils.Utils;
+import ProjectData.Project.db_project_info;
+
+import javax.swing.*;
+import javax.swing.filechooser.FileFilter;
+import java.io.File;
+public class ProjectsChooser extends VFileChooser_ {
+ public ProjectsChooser(String title) {
+ super(title, new FileFilter() {
+ @Override
+ public boolean accept(File f) {
+ return
+ !Utils.ContainsCyrillic(f.getAbsolutePath()) &&
+ !f.getName().equalsIgnoreCase(db_project_info.data)
+ ;
+ }
+ @Override
+ public String getDescription() {
+ return "Все папки";
+ }
+ });
+ fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ }
+}
diff --git a/src/Common/Utils/Files/VDirectoryChooser.java b/src/Common/Utils/Files/VDirectoryChooser.java
new file mode 100644
index 00000000..7ca8f730
--- /dev/null
+++ b/src/Common/Utils/Files/VDirectoryChooser.java
@@ -0,0 +1,21 @@
+package Common.Utils.Files;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+import javax.swing.filechooser.FileFilter;
+import java.io.File;
+public class VDirectoryChooser extends VFileChooser_ {
+ public VDirectoryChooser(String title) {
+ super(title, new FileFilter() {
+ @Override
+ public boolean accept(File f) {
+ return !Utils.ContainsCyrillic(f.getAbsolutePath());
+ }
+ @Override
+ public String getDescription() {
+ return "Все папки";
+ }
+ });
+ fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ }
+}
diff --git a/src/Common/Utils/Files/VFileChooser.java b/src/Common/Utils/Files/VFileChooser.java
new file mode 100644
index 00000000..38e09544
--- /dev/null
+++ b/src/Common/Utils/Files/VFileChooser.java
@@ -0,0 +1,44 @@
+package Common.Utils.Files;
+import Common.Utils.Utils;
+
+import javax.swing.*;
+import javax.swing.filechooser.FileFilter;
+import java.io.File;
+import java.util.Arrays;
+import java.util.Vector;
+public class VFileChooser extends VFileChooser_ {
+ Vector Extensions = new Vector<>();
+ String extensionsLine = "";
+ public VFileChooser(String title, String... extensions_in) {
+ super(title, null);
+ Extensions.addAll(Arrays.asList(extensions_in));
+ if (Extensions.isEmpty())
+ extensionsLine = "*.*";
+ else
+ for (String ext : Extensions)
+ extensionsLine += "*" + (ext.isEmpty() ? "" : ".") + ext + ";";
+ fileChooser.setFileFilter(new FileFilter() {
+ @Override
+ public boolean accept(File f) {
+ return !Utils.ContainsCyrillic(f.getName())
+ && (f.isDirectory() || acceptExtensions(f));
+ }
+ @Override
+ public String getDescription() {
+ return extensionsLine;
+ }
+ });
+ fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+ }
+ public VFileChooser(String title, FileFilter filter_in) {
+ super(title, filter_in);
+ fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+ }
+ public boolean acceptExtensions(File file) {
+ if (Extensions.isEmpty()) return true;
+ String file_ext = Utils.getExtension(file);
+ for (String ext : Extensions)
+ if (ext.equalsIgnoreCase(file_ext)) return true;
+ return false;
+ }
+}
diff --git a/src/Common/Utils/Files/VFileChooser_.java b/src/Common/Utils/Files/VFileChooser_.java
new file mode 100644
index 00000000..3e458d1a
--- /dev/null
+++ b/src/Common/Utils/Files/VFileChooser_.java
@@ -0,0 +1,50 @@
+package Common.Utils.Files;
+import javax.swing.*;
+import javax.swing.filechooser.FileFilter;
+import java.awt.*;
+import java.io.File;
+import java.util.Arrays;
+import java.util.Vector;
+public class VFileChooser_ {
+ protected JFileChooser fileChooser = new JFileChooser() {
+ @Override
+ protected JDialog createDialog(Component parent) throws HeadlessException {
+ JDialog res = super.createDialog(parent);
+ res.setAlwaysOnTop(true);
+ return res;
+ }
+ };
+ public File getCurrentDirectory(){
+ return fileChooser.getCurrentDirectory();
+ }
+ public VFileChooser_(String title, FileFilter filter) {
+ fileChooser.setDialogTitle(title);
+ fileChooser.setAcceptAllFileFilterUsed(false);
+ fileChooser.setFileFilter(filter);
+ }
+ public void setTitle(String title_in) {
+ fileChooser.setDialogTitle(title_in);
+ }
+ public File ShowDialog() {
+ fileChooser.setMultiSelectionEnabled(false);
+ File result = null;
+ if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
+ result = fileChooser.getSelectedFile();
+ }
+ return result;
+ }
+ public Vector ShowMultiDialog() {
+ fileChooser.setMultiSelectionEnabled(true);
+ Vector result = new Vector<>();
+ if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
+ result = new Vector<>(Arrays.asList(fileChooser.getSelectedFiles()));
+ }
+ return result;
+ }
+ public void SetCurrentDirectory(String dir) {
+ fileChooser.setCurrentDirectory(new File(dir));
+ }
+ public void SetCurrentDirectory(File dir) {
+ fileChooser.setCurrentDirectory(dir);
+ }
+}
diff --git a/src/Common/Utils/Index.java b/src/Common/Utils/Index.java
new file mode 100644
index 00000000..a0d82c34
--- /dev/null
+++ b/src/Common/Utils/Index.java
@@ -0,0 +1,24 @@
+package Common.Utils;
+import java.io.Serializable;
+public class Index implements Serializable {
+ int value = 0;
+ public int Inc() {
+ return value++;
+ }
+ public int Dec() {
+ return value--;
+ }
+ public void Set(int value_in) {
+ value = value_in;
+ }
+ public int getValue() {
+ return value;
+ }
+ public void Reset() {
+ value = 0;
+ }
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
+}
diff --git a/src/Common/Utils/InterruptThread.java b/src/Common/Utils/InterruptThread.java
new file mode 100644
index 00000000..107e0d52
--- /dev/null
+++ b/src/Common/Utils/InterruptThread.java
@@ -0,0 +1,27 @@
+package Common.Utils;
+import ProjectData.Project.db_project_info;
+import org.apache.commons.io.FileUtils;
+
+import java.io.File;
+import java.util.concurrent.Callable;
+public class InterruptThread extends Thread{
+ //------------
+ public static final String Eliminated = "Eliminated";
+ public InterruptThread(int sleep_ms, Callable action){
+ super(() -> {
+ File interruptFile = new File(db_project_info.interrupt);
+ try {
+ while (true) {
+ Thread.sleep(sleep_ms);
+ if (interruptFile.exists()) {
+ FileUtils.writeStringToFile(new File(Eliminated + " by INTERRUPT file"), "");
+ FileUtils.forceDelete(interruptFile);
+ action.call();
+ }
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ });
+ }
+}
diff --git a/src/Common/Utils/Stopwatch.java b/src/Common/Utils/Stopwatch.java
new file mode 100644
index 00000000..97de2c4a
--- /dev/null
+++ b/src/Common/Utils/Stopwatch.java
@@ -0,0 +1,16 @@
+package Common.Utils;
+public class Stopwatch {
+ long st, en;
+ double res;
+ public void Start() {
+ st = System.nanoTime();
+ }
+ public void Stop() {
+ en = System.nanoTime();
+ res = en - st;
+ }
+ public String Print() {
+ //https://hr-vector.com/java/formatirovanie-chisel-strok
+ return String.format("%,3.2f", res * 0.000001) + " ms";
+ }
+}
diff --git a/src/Common/Utils/StringTemplate.java b/src/Common/Utils/StringTemplate.java
new file mode 100644
index 00000000..a8162fa9
--- /dev/null
+++ b/src/Common/Utils/StringTemplate.java
@@ -0,0 +1,63 @@
+package Common.Utils;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+public class StringTemplate {
+ //https://javarush.ru/groups/posts/regulyarnye-vyrazheniya-v-java
+ public static String separator = "(\\s)+"; //хотя бы один пробел
+ public static String parameter = "(.)+"; //хотя бы один символ
+ //------------------------------------------------------------------
+ public String prefix = ""; //часть команды до параметра, запакованная через пробел
+ public String suffix = ""; //часть команды после параметра, запакованная через пробел
+ public String pattern = "";
+ //------------------------------------------------------------------
+ public StringTemplate(String p, String s) {
+ prefix = Utils.pack(p);
+ suffix = Utils.pack(s);
+ // System.out.println(Utils.Brackets(prefix));
+ // System.out.println(Utils.Brackets(suffix));
+ String[] prefix_words = prefix.split(" ");
+ String[] suffix_words = suffix.split(" ");
+ //настраиваем регулярное выражение----------
+ prefix = "^(\\s)*";
+ for (String word : prefix_words) {
+ if (!word.isEmpty())
+ prefix += (word + separator);
+ }
+ suffix = "";
+ for (String word : suffix_words) {
+ if (!word.isEmpty())
+ suffix += (separator + word);
+ }
+ suffix += "(\\s)*$";
+ pattern = prefix + parameter + suffix;
+ }
+ public static String getFirstMatch(String pattern_in, String text_in) {
+ Matcher m = Pattern.compile(pattern_in, Pattern.CASE_INSENSITIVE).matcher(text_in);
+ m.find();
+ return text_in.substring(m.start(), m.end());
+ }
+ public boolean check(String text_in) {
+ // System.out.println("sentense = " + Utils.Brackets(text_in));
+ // System.out.println("pattern = " + Utils.Brackets(pattern));
+ return Pattern.compile(pattern, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE).matcher(text_in).find();
+ }
+ public String check_and_get_param(String text_in) {
+ Pattern regex = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ Matcher matcher = regex.matcher(text_in);
+ // System.out.println("sentense = " + Utils.Brackets(text_in));
+ // System.out.println("pattern = " + Utils.Brackets(pattern));
+ if (matcher.find()) {
+ // System.out.println("match found " + matcher.start() + " " + matcher.end());
+ String sentence = text_in.substring(matcher.start(), matcher.end());
+ // System.out.println("sentence=" + Utils.Brackets(sentence));
+ String prefix_ = getFirstMatch(prefix, sentence);
+ // System.out.println("prefix_ = " + Utils.Brackets(prefix_));
+ String suffix_ = getFirstMatch(suffix, sentence);
+ // System.out.println("suffix_ = " + Utils.Brackets(suffix_));
+ String param = sentence.substring(prefix_.length(), sentence.length() - suffix_.length());
+ // System.out.println("param = " + Utils.Brackets(param));
+ return param;
+ }
+ return null;
+ }
+}
diff --git a/src/Common/Utils/TextLog.java b/src/Common/Utils/TextLog.java
new file mode 100644
index 00000000..a9d2dd14
--- /dev/null
+++ b/src/Common/Utils/TextLog.java
@@ -0,0 +1,22 @@
+package Common.Utils;
+import Common.Global;
+public class TextLog {
+ String text = "";
+ public void Writeln(String line) {
+ text += line + "\n";
+ }
+ public void Writeln_(String line) {
+ text += line + "\n";
+ Global.Log.Print(line);
+ }
+ public void Clear() {
+ text = "";
+ }
+ public boolean isEmpty() {
+ return text.isEmpty();
+ }
+ @Override
+ public String toString() {
+ return text;
+ }
+}
diff --git a/src/Common/Utils/Utils.java b/src/Common/Utils/Utils.java
new file mode 100644
index 00000000..db6d1a58
--- /dev/null
+++ b/src/Common/Utils/Utils.java
@@ -0,0 +1,1432 @@
+package Common.Utils;
+import Common.Global;
+import Common.UI.UI;
+import ProjectData.Files.DBProjectFile;
+import ProjectData.Project.db_project_info;
+import Visual_DVM_2021.Passes.PassException;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import org.apache.commons.io.FileUtils;
+
+import javax.swing.*;
+import javax.swing.tree.DefaultMutableTreeNode;
+import java.awt.*;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.io.*;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.nio.file.*;
+import java.security.MessageDigest;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.concurrent.Semaphore;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+public class Utils {
+ public static Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
+ public static final int Nan = -1;
+ public static final Pattern VALID_EMAIL_ADDRESS_REGEX =
+ Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
+ //https://losst.ru/komandy-terminala-linux
+ public static String[] linux_system_commands = new String[]{
+ //
+ "a2p",
+ "ac",
+ "addgroup",
+ "adduser",
+ "agrep",
+ "alias",
+ "apropos",
+ "apt",
+ "aptitude",
+ "ar",
+ "arch",
+ "arp",
+ "as",
+ "aspell",
+ "at",
+ "awk",
+ "basename",
+ "bash",
+ "bс",
+ "bdiff",
+ "bfs",
+ "bg",
+ "biff",
+ "break",
+ "bs",
+ "bye",
+ "cal",
+ "calendar",
+ "cancel",
+ "cat",
+ "cc",
+ "cd",
+ "cfdisk",
+ "chdir",
+ "checkeq",
+ "checknr",
+ "chfn",
+ "chgrp",
+ "chmod",
+ "chown",
+ "chroot",
+ "chsh",
+ "cksum",
+ "clear",
+ "cmp",
+ "col",
+ "comm",
+ "compress",
+ "continue",
+ "cp",
+ "cpio",
+ "crontab",
+ "csh",
+ "csplit",
+ "ctags",
+ "cu",
+ "curl",
+ "cut",
+ "date",
+ "dc",
+ "dd",
+ "delgroup",
+ "deluser",
+ "depmod",
+ "deroff",
+ "df",
+ "dhclient",
+ "dig",
+ "dircmp",
+ "dirname",
+ "dmesg",
+ "dos2unix",
+ "dpkg",
+ "dpost",
+ "du",
+ "echo",
+ "ed",
+ "edit",
+ "egrep",
+ "eject",
+ "elm",
+ "emacs",
+ "emerge",
+ "enable",
+ "env",
+ "eqn",
+ "ex",
+ "exit",
+ "expand",
+ "expr",
+ "fc",
+ "fdisk",
+ "fg",
+ "fgrep",
+ "file",
+ "find",
+ "findsmb",
+ "finger",
+ "fmt",
+ "fold",
+ "for",
+ "foreach",
+ "free",
+ "fsck",
+ "ftp",
+ "fuser",
+ "gawk",
+ "getfacl",
+ "gpasswd",
+ "gprof",
+ "grep",
+ "groupadd",
+ "groupdel",
+ "groupmod",
+ "gnuzip",
+ "gview",
+ "gvim",
+ "gzip",
+ "halt",
+ "head",
+ "help",
+ "history",
+ "host",
+ "hostid",
+ "hostname",
+ "htop",
+ "id",
+ "ifconfig",
+ "ifdown",
+ "ifquery",
+ "ifup",
+ "info",
+ "insmod",
+ "iostat",
+ "ip",
+ "iwconfig",
+ "jobs",
+ "join",
+ "kill",
+ "killall",
+ "ksh",
+ "last",
+ "ld",
+ "ldd",
+ "less",
+ "link",
+ "ln",
+ "lo",
+ "locate",
+ "login",
+ "logname",
+ "logout",
+ "losetup",
+ "ls",
+ "lsmod",
+ "lsof",
+ "lzcat",
+ "lzma",
+ "mach",
+ "mailx",
+ "make",
+ "man",
+ "merge",
+ "mesg",
+ "mkdir",
+ "mkfs",
+ "mkswap",
+ "modinfo",
+ "modprobe",
+ "more",
+ "mount",
+ "mt",
+ "mv",
+ "mysql",
+ "mysqldump",
+ "nc",
+ "netstat",
+ "newgrp",
+ "nice",
+ "niscat",
+ "nischmod",
+ "nischown",
+ "nischttl",
+ "nisdefaults",
+ "nistbladm",
+ "nl",
+ "nmap",
+ "nohup",
+ "nroff",
+ "nslookup",
+ "od",
+ "on",
+ "onintr",
+ "pack",
+ "pacman",
+ "pagesize",
+ "parted",
+ "partprobe",
+ "passwd",
+ "paste",
+ "pax",
+ "pact",
+ "perl",
+ "pg",
+ "pico",
+ "pine",
+ "pkill",
+ "poweroff",
+ "pr",
+ "printenv",
+ "printf",
+ "ps",
+ "pstree",
+ "pvs",
+ "pwd",
+ "quit",
+ "rcp",
+ "readlink",
+ "reboot",
+ "red",
+ "rename",
+ "repeat",
+ "replace",
+ "rlogin",
+ "rm",
+ "rmdir",
+ "rmmod",
+ "route",
+ "rpcinfo",
+ "rsh",
+ "rsync",
+ "s2p",
+ "scp",
+ "screen",
+ "script",
+ "sdiff",
+ "sed",
+ "sendmail",
+ "service",
+ "set",
+ "setfacl",
+ "sfdisk",
+ "sftp",
+ "sh",
+ "shred",
+ "shutdown",
+ "sleep",
+ "slogin",
+ "smbclient",
+ "sort",
+ "spell",
+ "split",
+ "startx",
+ "ss",
+ "ssh",
+ "stat",
+ "stop",
+ "strftime",
+ "strip",
+ "stty",
+ "su",
+ "sudo",
+ "swapoff",
+ "swapon",
+ "systemctl",
+ "tabs",
+ "tac",
+ "tail",
+ "talk",
+ "tar",
+ "tcopy",
+ "tcpdump",
+ "tcsh",
+ "tee",
+ "telnet",
+ "test",
+ "time",
+ "timex",
+ "todos",
+ "top",
+ "touch",
+ "traceroute",
+ "tree",
+ "tty",
+ "umask",
+ "umount",
+ "unalias",
+ "uname",
+ "uncompress",
+ "uniq",
+ "unlink",
+ "unlzma",
+ "unpack",
+ "until",
+ "unxz",
+ "unzip",
+ "uptime",
+ "useradd",
+ "userdel",
+ "usermod",
+ "vacation",
+ "vi",
+ "vim",
+ "w",
+ "wait",
+ "wall",
+ "wc",
+ "wget",
+ "whereis",
+ "which",
+ "while",
+ "who",
+ "whoami",
+ "whois",
+ "Xorg",
+ "xargs",
+ "xfd",
+ "xhost",
+ "xlsfonts",
+ "xrdb",
+ "xset",
+ "xz",
+ "xzcat",
+ "yacc",
+ "yes",
+ "yppasswd",
+ "yum",
+ "zcat",
+ "zipcloack",
+ "zipinfo",
+ "zipnote",
+ "zipsplit",
+ "zypper"
+ //
+ };
+ public static char[] forbidden_file_name_characters = new char[]{
+ '#', '%', '&', '{', '}',
+ '<', '>', '*', '?', '!',
+ '$', '\'', '\"', '@', '+',
+ '`', '|', '=', '#', ':', '/', '\\',
+ '~', '^'
+ };
+ public static char[] regular_metasymbols = new char[]{
+ '<', '>', '(', ')', '[', ']', '{', '}', '^', '-', '=', '$', '!', '|', '?', '*', '+', '.'
+ };
+ //все запретные символы через пробел.
+ public static String all_forbidden_characters_string = "";
+ public static String hideRegularMetasymbols(String word) {
+ String res = word.replace("\\", "\\\\");
+ for (char c : regular_metasymbols)
+ res = res.replace(String.valueOf(c), "\\" + c);
+ return res;
+ }
+ public static boolean isLinuxSystemCommand(String text) {
+ for (String command : linux_system_commands) {
+ if (text.equalsIgnoreCase(command)) return true;
+ }
+ return false;
+ }
+ public static boolean ContainsForbiddenName(String string) {
+ char[] chars = string.toCharArray();
+ for (char c : chars)
+ if (isForbidden(c)) return true;
+ return false;
+ }
+ public static boolean isForbidden(char c) {
+ for (char f : forbidden_file_name_characters)
+ if (c == f) return true;
+ return false;
+ }
+ public static void init() {
+ for (char f : forbidden_file_name_characters)
+ all_forbidden_characters_string += f + " ";
+ }
+ public static String DQuotes(Object o) {
+ return "\"" + o.toString() + "\"";
+ }
+ public static String Quotes(Object o) {
+ return "'" + o.toString() + "'";
+ }
+ public static String Brackets(Object o) {
+ return "[" + o.toString() + "]";
+ }
+ public static String RBrackets(Object o) {
+ return "(" + o.toString() + ")";
+ }
+ public static String MFVar(Object o) {
+ return "$(" + o.toString() + ")";
+ }
+ public static String TBrackets(Object o) {
+ return "<" + o.toString() + ">";
+ }
+ public static String getExtension(File file) {
+ String fn = file.getName();
+ int di = fn.lastIndexOf(".");
+ return (di >= 0) ? fn.substring(di + 1).toLowerCase() : "";
+ }
+ public static String getFileNameWithoutExtension(File file) {
+ return getNameWithoutExtension(file.getName());
+ }
+ public static String getNameWithoutExtension(String fn) {
+ return (fn.contains(".")) ? fn.substring(0, fn.lastIndexOf(".")).toLowerCase() : fn.toLowerCase();
+ }
+ public static boolean ContainsCyrillic(String string) {
+ return string.chars()
+ .mapToObj(Character.UnicodeBlock::of)
+ .anyMatch(b -> b.equals(Character.UnicodeBlock.CYRILLIC));
+ }
+ public static void CheckDirectory(File dir) {
+ // System.out.println("check: "+dir);
+ if (!dir.exists()) {
+ try {
+ FileUtils.forceMkdir(dir);
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ }
+ }
+ public static void CheckAndCleanDirectory(File dir) {
+ // System.out.println("check and clean: "+dir);
+ if (dir.exists()) {
+ File[] files = dir.listFiles();
+ if (files != null)
+ for (File f : files) {
+ try {
+ forceDeleteWithCheck(f);
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ }
+ } else {
+ try {
+ FileUtils.forceMkdir(dir);
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ }
+ }
+ public static Object requireNonNullElse(Object value, Object default_value) {
+ return (value != null) ? value : default_value;
+ }
+ //https://javadevblog.com/kak-schitat-fajl-v-string-primer-chteniya-fajla-na-java.html
+ //https://habr.com/ru/post/269667/
+ public static String ReadAllText(File file) {
+ try {
+ return new String(Files.readAllBytes(file.toPath()));
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ return "";
+ }
+ public static String toU(String path) {
+ return path.replace('\\', '/');
+ }
+ public static String toW(String path) {
+ return path.replace('/', '\\');
+ }
+ public static double getFileSizeMegaBytes(File file) {
+ double res = file.length() / (1024 * 1024);
+ System.out.println(res);
+ return res;
+ }
+ public static void CleanDirectory(File dir) {
+ if (dir.exists() && dir.isDirectory()) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (File f : files) {
+ try {
+ forceDeleteWithCheck(f);
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ }
+ }
+ }
+ }
+ public static long last_ticks = Utils.Nan;
+ public static void sleep(long millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (Exception ignore) {
+ }
+ }
+ public static Semaphore date_semaphore = new Semaphore(1);
+ public static long getDateNumber() {
+ //-
+ try {
+ date_semaphore.acquire();
+ } catch (Exception ignore) {
+ }
+ //-
+ long ticks = new Date().toInstant().getEpochSecond();
+ while (ticks == last_ticks) {
+ sleep(1);
+ ticks = new Date().toInstant().getEpochSecond();
+ }
+ last_ticks = ticks; // Это и есть разделяемый ресурс.
+ date_semaphore.release();
+ return ticks;
+ }
+ public static String getDateName(String name_) {
+ return name_ + "_" + getDateNumber();
+ }
+ public static void WriteToFile(File f, String text) throws IOException {
+ Files.write(
+ f.toPath(),
+ text.getBytes(),
+ StandardOpenOption.CREATE,
+ StandardOpenOption.TRUNCATE_EXISTING);
+ }
+ public static boolean isDigit(String s) {
+ try {
+ Integer.parseInt(s);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ public static boolean isEnglishLetter(char c) {
+ return (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')));
+ }
+ public static boolean isRussianLetter(char c) {
+ return ((c >= 'а') && (c <= 'я'))
+ || ((c >= 'А') && (c <= 'Я'))
+ || (c == 'Ё')
+ || (c == 'ё');
+ }
+ public static boolean isSign(char c) {
+ switch (c) {
+ //арифметика.
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '<':
+ case '>':
+ case '&':
+ case '=':
+ case '%':
+ case '^':
+ //- обр слеш
+ case '\\':
+ //препинание
+ case ' ':
+ case '_':
+ case '.':
+ case ',':
+ case '!':
+ case '?':
+ case ';':
+ case ':':
+ //escape последовательности
+ case '\t':
+ case '\n':
+ case '\r':
+ //кавычки
+ case '\'':
+ case '"':
+ //- скобки
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ //прочее
+ case '~':
+ case '`':
+ case '|':
+ case '@':
+ case '$':
+ case '#':
+ case '№':
+ return true;
+ }
+ return false;
+ }
+ public static char Translit(char c) {
+ switch (c) {
+ case 'А':
+ case 'а':
+ case 'Я':
+ case 'я':
+ return 'A';
+ //
+ case 'Б':
+ case 'б':
+ return 'B';
+ //-
+ case 'В':
+ case 'в':
+ return 'V';
+ //
+ case 'Г':
+ case 'г':
+ return 'G';
+ //
+ case 'Д':
+ case 'д':
+ return 'D';
+ //
+ case 'Е':
+ case 'е':
+ case 'Ё':
+ case 'ё':
+ case 'Э':
+ case 'э':
+ return 'E';
+ //
+ case 'Ж':
+ case 'ж':
+ return 'J';
+ //
+ case 'З':
+ case 'з':
+ return 'Z';
+ //
+ case 'И':
+ case 'и':
+ case 'Й':
+ case 'й':
+ return 'I';
+ //
+ case 'К':
+ case 'к':
+ return 'K';
+ //
+ case 'Л':
+ case 'л':
+ return 'L';
+ //
+ case 'М':
+ case 'м':
+ return 'M';
+ //
+ case 'Н':
+ case 'н':
+ return 'N';
+ //
+ case 'О':
+ case 'о':
+ return 'O';
+ //
+ case 'П':
+ case 'п':
+ return 'P';
+ //
+ case 'Р':
+ case 'р':
+ return 'R';
+ //
+ case 'С':
+ case 'с':
+ return 'S';
+ case 'Т':
+ case 'т':
+ return 'T';
+ //
+ case 'У':
+ case 'у':
+ case 'Ю':
+ case 'ю':
+ return 'U';
+ case 'Х':
+ case 'х':
+ case 'Щ':
+ case 'щ':
+ case 'Ш':
+ case 'ш':
+ return 'H';
+ //
+ case 'Ф':
+ case 'ф':
+ return 'F';
+ //
+ case 'Ч':
+ case 'ч':
+ case 'Ц':
+ case 'ц':
+ return 'C';
+ //
+ case 'Ы':
+ case 'ы':
+ return 'Y';
+ //
+ }
+ return ' ';
+ }
+ public static String ending(boolean flag) {
+ return flag ? ")" : ",";
+ }
+ // http://java-online.ru/blog-archive.xhtml
+ public static void getFilesCountR(File dir, Index res) {
+ for (File f : dir.listFiles()) {
+ res.Inc();
+ if (f.isDirectory())
+ getFilesCountR(f, res);
+ }
+ }
+ public static int getFilesCount(File dir) {
+ Index res = new Index();
+ getFilesCountR(dir, res);
+ return res.getValue();
+ }
+ public static String print_date(Date date) {
+ String pattern = "dd.MM.yyyy HH:mm:ss";
+ DateFormat df = new SimpleDateFormat(pattern);
+ return df.format(date);
+ }
+ public static boolean isBracketsBalanced(String fragment) {
+ int cc = 0;
+ for (char c : fragment.toCharArray()) {
+ if (c == '(')
+ cc++;
+ if (c == ')')
+ cc--;
+ if (cc < 0)
+ return false;
+ }
+ return (cc == 0);
+ }
+ public static File CreateTempResourceFile(String res_name) throws Exception {
+ URL u = (Utils.class.getResource("/files/" + res_name));
+ InputStream i = u.openStream();
+ Path p = Paths.get(Global.TempDirectory.getAbsolutePath(), getDateName(res_name));
+ Files.copy(i, p, StandardCopyOption.REPLACE_EXISTING);
+ return p.toFile();
+ }
+ public static void CreateResourceFile(String res_name, File dst) throws Exception {
+ URL u = (Utils.class.getResource("/files/" + res_name));
+ InputStream i = u.openStream();
+ Files.copy(i, dst.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ }
+ //просто дать объект под файл с сгенерированным именем
+ public static File CreateTempFile(String name, String text) throws IOException {
+ File res = getTempFileName(name);
+ WriteToFile(res, text);
+ return res;
+ }
+ public static File CreateTempFile(String name, String ext, String text) throws IOException {
+ File res = getTempFileName(name, ext);
+ WriteToFile(res, text);
+ return res;
+ }
+ public static File getTempFileName(String name, String ext) {
+ return Paths.get(System.getProperty("user.dir"), "Temp", getDateName(name) + (ext.isEmpty() ? "" : ("." + ext))).toFile();
+ }
+ public static File getTempFileName(String name) {
+ return getTempFileName(name, "");
+ }
+ public static boolean isAnchestor(File child, File anchestor) {
+ return child.getAbsolutePath().startsWith(anchestor.getAbsolutePath() + (Global.isWindows ? "\\" : "/"));
+ }
+ //при условии что это точно его предок
+ public static String getRelativeAddress(File file, File anchestor) {
+ return file.getAbsolutePath().substring(anchestor.getAbsolutePath().length() + 1);
+ }
+ public static String pack(String s_in) {
+ return String.join(" ",
+ Arrays.stream(s_in.split(" ")).filter(d -> !d.isEmpty()).collect(Collectors.toCollection(Vector::new)));
+ }
+ public static String remove(String string, String... to_remove) {
+ String res = string;
+ for (String c : to_remove)
+ res = res.replace(c, "");
+ return res;
+ }
+ //для переименования/добавления новых файлов.
+ public static boolean validateFileShortNewName(String name, TextLog Log) {
+ boolean res = true;
+ if (name.isEmpty()) {
+ Log.Writeln_("Имя файла не может быть пустым");
+ res = false;
+ }
+ if (ContainsCyrillic(name)) {
+ Log.Writeln_("Имя файла не может содержать кириллицу");
+ res = false;
+ }
+ if (ContainsForbiddenName(name)) {
+ Log.Writeln_("Имя файла не может содержать запрещённых символов\n" + all_forbidden_characters_string);
+ res = false;
+ }
+ return res;
+ }
+ //корень сюда гарантированно не попадает. значит можно запрещать двоеточие.
+ //идет по всем уровням файлов
+ public static boolean validateProjectFile(File file, TextLog Log) {
+ String name = file.getName();
+ if (ContainsCyrillic(name) || ContainsForbiddenName(name)) {
+ Log.Writeln_(file.getAbsolutePath());
+ return false;
+ }
+ return true;
+ }
+ //входной параметр всегда папка.
+ public static void validateProjectFolder_r(File dir, TextLog Log) {
+ validateProjectFile(dir, Log);
+ File[] files = dir.listFiles();
+ if (files != null)
+ for (File file : files) {
+ if (file.isDirectory())
+ validateProjectFolder_r(file, Log);
+ else validateProjectFile(file, Log);
+ }
+ }
+ public static boolean validateProjectFolder(File dir, TextLog Log) {
+ TextLog files_list = new TextLog();
+ String[] filesLines = files_list.text.split("\n");
+ validateProjectFolder_r(dir, files_list);
+ if (!files_list.isEmpty())
+ Log.Writeln_("Имена " + filesLines.length + " файлов/подпапок содержат запрещённые символы " +
+ all_forbidden_characters_string +
+ "или кириллицу");
+ //нужно проверить корень на наличие хоть одной программы.
+ return Log.isEmpty();
+ }
+ public static ImageIcon getIcon(String path) {
+ URL imageUrl = Utils.class.getResource(path);
+ if (imageUrl == null) {
+ System.out.println("image: " + Brackets(path) + "not found");
+ return null;
+ }
+ return new ImageIcon(imageUrl);
+ }
+ public static ImageIcon getTabIcon(String path) {
+ URL imageUrl = Utils.class.getResource(path);
+ if (imageUrl == null) {
+ System.out.println("image: " + Brackets(path) + "not found");
+ return null;
+ }
+ ImageIcon icon = new ImageIcon(imageUrl);
+ return new ImageIcon(icon.getImage().getScaledInstance(
+ 18,
+ 18,
+ Image.SCALE_DEFAULT));
+ }
+ public static void CopyToClipboard(String text) {
+ Toolkit.getDefaultToolkit()
+ .getSystemClipboard()
+ .setContents(
+ new StringSelection(text),
+ null
+ );
+ }
+ public static String getFromClipboard() {
+ String res = "";
+ try {
+ res = (String) Toolkit.getDefaultToolkit()
+ .getSystemClipboard().getData(DataFlavor.stringFlavor);
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ return res;
+ }
+ public static void delete_with_check(File file) throws Exception {
+ int attempts = 0;
+ while (attempts < 10) {
+ if (file.exists()) {
+ try {
+ FileUtils.forceDelete(file);
+ } catch (Exception ex) {
+ // ex.printStackTrace();
+ }
+ } else return;
+ if (file.exists()) {
+ attempts++;
+ System.out.println("файл " + Brackets(file.getAbsolutePath()) + " занят");
+ Thread.sleep(2000);
+ } else return;
+ }
+ throw new PassException("Не удалось удалить файл " + Brackets(file.getAbsolutePath()) + " за " + attempts + " попыток");
+ }
+ public static void GetVertices(float R, float r, float x0, float y0, int n, float phi) {
+ boolean inner = false;
+ for (int i = 0; i < 2 * n; i++) {
+ float rad = inner ? r : R;
+ System.out.println("x=" + (x0 + rad * Math.cos(phi + Math.PI * i / n)));
+ System.out.println("y=" + (y0 + rad * Math.sin(phi + Math.PI * i / n)));
+ System.out.println("--");
+ inner = !inner;
+ }
+ }
+ public static String md5Custom(String st) {
+ MessageDigest messageDigest = null;
+ byte[] digest = new byte[0];
+ try {
+ messageDigest = MessageDigest.getInstance("MD5");
+ messageDigest.reset();
+ messageDigest.update(st.getBytes());
+ digest = messageDigest.digest();
+ } catch (Exception e) {
+ // тут можно обработать ошибку
+ // возникает она если в передаваемый алгоритм в getInstance(,,,) не существует
+ Global.Log.PrintException(e);
+ }
+ BigInteger bigInt = new BigInteger(1, digest);
+ String md5Hex = bigInt.toString(16);
+ while (md5Hex.length() < 32) {
+ md5Hex = "0" + md5Hex;
+ }
+ return md5Hex;
+ }
+ public static void renameSubdirs_r(DefaultMutableTreeNode node, File old_anchestor, File new_anchestor) {
+ if (node.getUserObject() instanceof File) {
+ File old_file = (File) node.getUserObject();
+ String relative_name = old_file.getAbsolutePath().substring(old_anchestor.getAbsolutePath().length() + 1);
+ File new_file = Paths.get(new_anchestor.getAbsolutePath(), relative_name).toFile();
+ node.setUserObject(new_file);
+ for (int i = 0; i < node.getChildCount(); ++i) {
+ renameSubdirs_r((DefaultMutableTreeNode) node.getChildAt(i), old_anchestor, new_anchestor);
+ }
+ }
+ }
+ public static void forceDeleteWithCheck(File file) throws Exception {
+ int attempts = 0;
+ while (attempts < 10) {
+ if (file.exists()) {
+ try {
+ FileUtils.forceDelete(file);
+ } catch (Exception ignore) {
+ }
+ } else return;
+ if (file.exists()) {
+ attempts++;
+ Global.Log.Print("неудачная попытка удаления: файл " + Brackets(file.getAbsolutePath()) + " занят");
+ Thread.sleep(2000);
+ } else return;
+ }
+ throw new PassException("Не удалось удалить файл " + Brackets(file.getAbsolutePath()) + " за " + attempts + " попыток");
+ }
+ public static byte[] packFile(File src) throws Exception {
+ System.out.println("pack begins: " + src.getAbsolutePath());
+ byte[] dst = Files.readAllBytes(src.toPath());
+ System.out.println("pack done: bytes:" + dst.length);
+ return dst;
+ }
+ public static void unpackFile(byte[] bytes, File dst) throws Exception {
+ FileOutputStream os = new FileOutputStream(dst);
+ System.out.println(dst.getAbsolutePath());
+ System.out.println("unpack begins: bytes:" + bytes.length);
+ os.write(bytes);
+ os.close();
+ System.out.println("unpack done to " + dst.getAbsolutePath());
+ }
+ public static Socket createClientSocket(InetAddress address, int port, int timeout) throws Exception {
+ Socket socket = new Socket();
+ socket.setSoTimeout(timeout);
+ socket.connect(new InetSocketAddress(address, port), timeout);
+ return socket;
+ }
+ public static void CreateResourceFile(File dst) throws Exception {
+ URL u = (Utils.class.getResource("/files/" + dst.getName()));
+ InputStream i = u.openStream();
+ Files.copy(i, dst.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ }
+ public static boolean validateEmail(String address, TextLog log) {
+ Matcher matcher = VALID_EMAIL_ADDRESS_REGEX.matcher(address);
+ if (!matcher.find()) {
+ log.Writeln_("введённый адрес электронной почты некорректен.");
+ return false;
+ }
+ String match = address.substring(matcher.start(), matcher.end());
+ if (!match.equals(address)) {
+ log.Writeln_("введённый адрес электронной почты некорректен.");
+ return false;
+ }
+ return true;
+ }
+ public static void getFilesByExtensions_r(File dir, Vector res, String... extensions) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (file.isFile()) {
+ for (String ext : extensions) {
+ if (getExtension(file).equalsIgnoreCase(ext))
+ res.add(file);
+ }
+ }
+ if (file.isDirectory())
+ getFilesByExtensions_r(file, res);
+ }
+ }
+ }
+ //----->>
+ public static void deleteFilesByExtensions(File dir, String... extensions) throws Exception {
+ Vector res = new Vector<>();
+ Utils.getFilesByExtensions_r(dir, res, extensions);
+ for (File src : res)
+ Utils.forceDeleteWithCheck(src);
+ }
+ //----->>
+ //--процессы-------------------------------------------------->>>>>
+ //
+ public static Process startScript(File scriptDirectory, File targetDirectory, String name, String scriptText, Map envs) throws Exception {
+ //->
+ File scriptFile = Paths.get(scriptDirectory.getAbsolutePath(), name + (Global.isWindows ? ".bat" : "")).toFile();
+ FileUtils.write(scriptFile, "cd " + Utils.DQuotes(targetDirectory.getAbsolutePath()) + "\n" + scriptText);
+ if (!scriptFile.setExecutable(true)) throw new PassException("Не удалось создать исполняемый файл для скрипта");
+ //->>
+ ProcessBuilder procBuilder = new ProcessBuilder(scriptFile.getAbsolutePath());
+ procBuilder.directory(scriptDirectory);
+ procBuilder.redirectErrorStream(true);
+ if (envs != null) {
+ for (String envName : envs.keySet()) {
+ procBuilder.environment().put(envName, envs.get(envName));
+ }
+ }
+ return procBuilder.start();
+ }
+ public static Process startScript(File scriptDirectory, File targetDirectory, String name, String scriptText) throws Exception {
+ return startScript(scriptDirectory, targetDirectory, name, scriptText, null);
+ }
+ //
+ //
+ public static String readLine(Process process) throws Exception {
+ InputStream stdout = process.getInputStream();
+ InputStreamReader isrStdout = new InputStreamReader(stdout);
+ BufferedReader brStdout = new BufferedReader(isrStdout);
+ String line = brStdout.readLine();
+ System.out.println(line);
+ return line;
+ }
+ public static Vector readAllLines(Process process) throws Exception {
+ Vector output = new Vector<>();
+ InputStream stdout = process.getInputStream();
+ InputStreamReader isrStdout = new InputStreamReader(stdout);
+ BufferedReader brStdout = new BufferedReader(isrStdout);
+ String line;
+ while ((line = brStdout.readLine()) != null) {
+ System.out.println(line);
+ output.add(line);
+ }
+ return output;
+ }
+ public static String readAllOutput(Process process) throws Exception {
+ return String.join("\n", readAllLines(process));
+ }
+ //
+ public static String extractHeaderName(String line) {
+ String tline = line.trim().toLowerCase();
+ if (tline.startsWith("include")) {
+ String[] data = tline.split("'");
+ return data.length > 1 ? data[1] : null;
+ }
+ return null;
+ }
+ public static String getRelativeName(File dir, File file) {
+ return
+ file.getAbsolutePath().startsWith(dir.getAbsolutePath()) ?
+ file.getAbsolutePath().substring(dir.getAbsolutePath().length() + 1).replace('/', '\\') :
+ file.getAbsolutePath()
+ ;
+ }
+ public static String compareTexts(String master, String slave) {
+ Vector lines = new Vector<>(Arrays.asList(master.split("\n")));
+ Vector slavelines = new Vector<>(Arrays.asList(slave.split("\n")));
+ Vector t2 = new Vector<>();
+ int old_j = 0;
+ int j = 0;
+ for (int i = 0; i < lines.size(); ++i) {
+ if (UI.Contains(slavelines, lines.get(i), old_j)) {
+ for (int k = old_j; k < slavelines.size(); ++k) {
+ j = k;
+ if (lines.get(i).equals(slavelines.get(k))) {
+ j++;
+ t2.add(slavelines.get(k));
+ break;
+ } else
+ t2.add("+ " + slavelines.get(k));
+ }
+ old_j = j;
+ } else {
+ //строки гарантированно нет.
+ t2.add("- " + lines.get(i));
+ }
+ }
+ //теперь граничное условие. если первый файл кончился а второй нет, его остаток это добавление.
+ for (int i = j; i < slavelines.size(); ++i)
+ t2.add("+ " + slavelines.get(i));
+ return String.join("\n", t2);
+ }
+ public static int getHalfKernels() {
+ int countCores = 1;
+ if (Runtime.getRuntime().availableProcessors() > 1)
+ countCores = Runtime.getRuntime().availableProcessors() / 2;
+ return countCores;
+ }
+ public static int getMaxKernels() {
+ return Math.max(2, Runtime.getRuntime().availableProcessors());
+ }
+ public static int getMatrixProcessors(String matrix) {
+ if (matrix.trim().isEmpty()) return 1;
+ String[] data = matrix.split(" ");
+ int res = 1;
+ for (String d : data)
+ res *= Integer.parseInt(d);
+ return res;
+ }
+ public static int getCTestMaxDim(File test) {
+ int fileMax = 0;
+ final String prefix = "#pragma dvm array distribute";
+ int n = 0;
+ try {
+ for (String line : FileUtils.readLines(test, Charset.defaultCharset())) {
+ // #pragma dvm array distribute[block][block], не важно
+ String packedLine = remove(pack(line).toLowerCase(), "\n", "\r", "\t");
+ if (packedLine.startsWith(prefix)) {
+ // System.out.println(n + ": " + packedLine);
+ packedLine = packedLine.substring(prefix.length());
+ boolean bracketOpen = false;
+ int pragmaMax = 0;
+ String distr = "";
+ for (int i = packedLine.indexOf('['); i < packedLine.length(); ++i) {
+ char c = packedLine.charAt(i);
+ // System.out.print(c);
+ if (bracketOpen) {
+ if (c == ']') {
+ bracketOpen = false;
+ // System.out.println("="+Utils.DQuotes(distr));
+ if (distr.equals("block"))
+ pragmaMax++;
+ distr = "";
+ } else {
+ distr += c;
+ }
+ } else {
+ if (c == '[') {
+ bracketOpen = true;
+ } else {
+ break;
+ }
+ }
+ }
+ // System.out.println("< - " + pragmaMax);
+ fileMax = Math.max(fileMax, pragmaMax);
+ }
+ ++n;
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ return fileMax;
+ }
+ public static int getCProjectMaxDim(db_project_info project) {
+ int res = 0;
+ for (DBProjectFile file : project.db.files.Data.values()) {
+ if (file.isActiveProgram())
+ res = Math.max(res, getCTestMaxDim(file.file));
+ }
+ return res;
+ }
+ public static Vector unpackStrings(String string, boolean brackets) {
+ Vector res = new Vector<>();
+ if (string.isEmpty())
+ res.add(brackets ? "[]" : "");
+ else {
+ StringBuilder line = new StringBuilder();
+ for (char c : string.toCharArray()) {
+ if (c == '\n') {
+ res.add(brackets ? Utils.Brackets(line.toString()) : line.toString());
+ line = new StringBuilder();
+ } else
+ line.append(c);
+ }
+ }
+ return res;
+ }
+ public static Vector unpackStrings(String string) {
+ return unpackStrings(string, false);
+ }
+ public static boolean isTimeout(long startDate, long maxtime_sec) {
+ Date now = new Date();
+ long delta = (now.getTime() - startDate) / 1000;
+ return (delta > maxtime_sec);
+ }
+ //https://translated.turbopages.org/proxy_u/en-ru.ru.596e2df7-62fd38bb-6b4aad49-74722d776562/https/stackoverflow.com/questions/34658054/finding-whole-word-only-in-java-string-search
+ public static long findInFile(String keyword_in, boolean registerOn, boolean wholeWord, File file) {
+ if (keyword_in.isEmpty()) return 0;
+ long res = 0;
+ try {
+ String text = FileUtils.readFileToString(file);
+ String keyword = keyword_in;
+ //-->>
+ if (!registerOn) {
+ text = text.toUpperCase();
+ keyword = keyword.toUpperCase();
+ }
+ String regex = wholeWord ? "\\b" + keyword + "\\b" : keyword;
+ Pattern pattern = Pattern.compile(regex);
+ Matcher matcher = pattern.matcher(text);
+ while (matcher.find()) res++;
+ System.out.println("matches=" + res);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return res;
+ }
+ public static char toStrike = (char) 822;
+ public static String strikeThrough(String s) {
+ StringBuilder res = new StringBuilder();
+ for (char c : s.toCharArray()) {
+ res.append(c);
+ if (c != toStrike)
+ res.append(toStrike);
+ }
+ return res.toString();
+ }
+ public static String noStrikeThrough(String s) {
+ StringBuilder res = new StringBuilder();
+ for (char c : s.toCharArray()) {
+ if (c != (toStrike))
+ res.append(c);
+ }
+ return res.toString();
+ }
+ public static String splitToolTip(String tip, int length) {
+ int DIALOG_TOOLTIP_MAX_SIZE = 75;
+ int SPACE_BUFFER = 10;
+ if (tip.length() <= length + SPACE_BUFFER) {
+ return tip;
+ }
+ Vector parts = new Vector<>();
+ int maxLength = 0;
+ String overLong = tip.substring(0, length + SPACE_BUFFER);
+ int lastSpace = overLong.lastIndexOf(' ');
+ if (lastSpace >= length) {
+ parts.add(tip.substring(0, lastSpace));
+ maxLength = lastSpace;
+ } else {
+ parts.add(tip.substring(0, length));
+ maxLength = length;
+ }
+ while (maxLength < tip.length()) {
+ if (maxLength + length < tip.length()) {
+ parts.add(tip.substring(maxLength, maxLength + length));
+ maxLength += maxLength + length;
+ } else {
+ parts.add(tip.substring(maxLength));
+ break;
+ }
+ }
+ StringBuilder sb = new StringBuilder("");
+ for (int i = 0; i < parts.size() - 1; i++) {
+ sb.append(parts.get(i) + " ");
+ }
+ sb.append(parts.get(parts.size() - 1));
+ sb.append((""));
+ return sb.toString();
+ }
+ /*
+ public static String appendString(String s, int sizeTo, char symbol) {
+ int delta = sizeTo - s.length();
+ StringBuilder res = new StringBuilder(s);
+ if (delta <= 0) {
+ for (int i = 0; i < sizeTo; ++i)
+ res.append(symbol);
+ }
+ for (int i = 0; i < delta; ++i) {
+ res.append(symbol);
+ }
+ return res.toString();
+ }
+ */
+ public static void addEmptyLines(Vector lines, int num) {
+ IntStream.range(0, num).mapToObj(i -> "").forEach(lines::add);
+ }
+ public static String jsonToPrettyFormat(String jsonString) {
+ JsonParser parser = new JsonParser();
+ JsonObject json = parser.parse(jsonString).getAsJsonObject();
+ Gson gson = new GsonBuilder().setPrettyPrinting().create();
+ return gson.toJson(json);
+ }
+ protected static boolean isSource(File file) {
+ if (file.isFile()) {
+ String extension = getExtension(file);
+ switch (extension) {
+ case "f":
+ case "fdv":
+ case "for":
+ case "f77":
+ case "f90":
+ case "fh":
+ case "c":
+ case "cdv":
+ case "cpp":
+ case "h":
+ return true;
+ }
+ }
+ return false;
+ }
+ public static boolean containsSource(File folder, boolean question) {
+ File visualiserData = new File(folder, db_project_info.data);
+ if (visualiserData.exists()) {
+ return true;
+ } //есть папка с данными, значит его уже открывали, все хорошо.
+ File[] files = folder.listFiles();
+ Vector sources = new Vector<>();
+ if (files != null) {
+ for (File file : files) {
+ // System.out.println(file.getAbsolutePath());
+ if (isSource(file)) {
+ // System.out.println(file.getAbsolutePath() + " is source!");
+ sources.add(file);
+ }
+ }
+ }
+ if (sources.isEmpty()) {
+ if (question) return UI.Question("Папка " + Brackets(folder.getName()) + "\n" +
+ "не содержит ни одного файла, распознанного как поддерживаемый код\n" +
+ "Всё равно открыть её как проект");
+ else return false;
+ } else return true;
+ }
+ public static void Kill(String PID, boolean force) {
+ if (!PID.isEmpty()) {
+ String killCommand =
+ force ? Global.isWindows ? "taskkill /PID " + Utils.DQuotes(PID) + " /F /T" : "kill -9 " + Utils.DQuotes(PID) :
+ Global.isWindows ? "taskkill /PID " + Utils.DQuotes(PID) : "kill -2 " + Utils.DQuotes(PID);
+ System.out.println(killCommand);
+ try {
+ Process killer = Utils.startScript(Global.TempDirectory, Global.TempDirectory, "killer", killCommand);
+ killer.waitFor();
+ System.out.println(Utils.readAllOutput(killer));
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ public static boolean isFunctionName(String name) {
+ if (name.isEmpty())
+ return false;
+ char[] letters = name.toCharArray();
+ if (!(isEnglishLetter(letters[0]) || letters[0] == '_')) {
+ return false;
+ }
+ //---
+ for (int i = 1; i < letters.length; ++i) {
+ if (!(isEnglishLetter(letters[i]) || letters[i] == '_' || Utils.isDigit(String.valueOf(letters[i])))) {
+ return false;
+ }
+ }
+ return true;
+ }
+ public static int fromBoolean(boolean flag) {
+ return flag ? 1 : 0;
+ }
+ public static void keepNewFiles(File directory, int count) throws Exception {
+ if (count > 0) {
+ File[] old_ = directory.listFiles(pathname -> pathname.isFile());
+ if (old_ != null) {
+ Vector old = new Vector<>();
+ Collections.addAll(old, old_);
+ old.sort((o1, o2) -> (int) (o2.lastModified() - o1.lastModified()));
+ for (int i = count - 1; i < old.size(); ++i) {
+ File file = old.get(i);
+ System.out.println(file.getName() + ":" + file.lastModified());
+ FileUtils.forceDelete(file);
+ }
+ }
+ }
+ }
+ public static boolean isParallelVersionName(String name) {
+ char[] chars = name.toLowerCase().toCharArray();
+ if ((chars.length > 1) && (chars[0] == 'p')) {
+ for (int i = 1; i < chars.length; ++i) {
+ if (!Character.isDigit(chars[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ public static void copyDirectory(File src, File dst) throws Exception {
+ int code = Utils.Nan;
+ String command = "xcopy " +
+ Utils.DQuotes(src.getAbsolutePath()) + " " +
+ Utils.DQuotes(dst.getAbsolutePath()) + " /e";
+ try {
+ code = Runtime.getRuntime().exec(command).waitFor();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ throw new PassException("Команда " + command + " завершилась с исключением.");
+ }
+ if (code != 0)
+ throw new PassException("Команда " + command + " завершилась с кодом " + code);
+ }
+}
+
diff --git a/src/Common/Utils/Validators/DVMHelpParser.java b/src/Common/Utils/Validators/DVMHelpParser.java
new file mode 100644
index 00000000..8ac549a2
--- /dev/null
+++ b/src/Common/Utils/Validators/DVMHelpParser.java
@@ -0,0 +1,241 @@
+package Common.Utils.Validators;
+import Common.Utils.Utils;
+import GlobalData.Compiler.Compiler;
+import GlobalData.CompilerEnvironment.CompilerEnvironment;
+import GlobalData.CompilerOption.CompilerOption;
+
+import java.util.Arrays;
+public class DVMHelpParser {
+ public static HelpParserState state;
+ public static String t_line;
+ public static String line;
+ //-
+ public static OptionState optionState;
+ public static CompilerOption option;
+ //-
+ public static int spacesCounter;
+ public static CompilerEnvironment environment;
+ public static EnvironmentState environmentState;
+ //-
+ public static String descriptionLine = "";
+ //-
+ public static Compiler compiler = null;
+ public static String[] banned_options = new String[]{
+ "-o",
+ "-c",
+ "-f90",
+ "-FI"
+ };
+ public static void ResetOption() {
+ optionState = OptionState.SearchName;
+ option = null;
+ descriptionLine = "";
+ }
+ public static void TryConfirmOptionDescriptionLine() {
+ if (option != null && !descriptionLine.isEmpty()) {
+ option.description.add(descriptionLine.trim());
+ descriptionLine = "";
+ }
+ }
+ public static void TryConfirmOption() {
+ if ((option != null) && (!compiler.options.containsKey(option.name))) {
+ if (!descriptionLine.isEmpty())
+ option.description.add(descriptionLine.trim());
+ option.CheckParameterVariants();
+ if (!Arrays.asList(banned_options).contains(option.name)) {
+ compiler.options.put(option.name, option);
+ }
+ ResetOption();
+ }
+ }
+ public static void ResetEnvironment() {
+ environmentState = EnvironmentState.SearchName;
+ spacesCounter = 0;
+ environment = null;
+ descriptionLine = "";
+ }
+ public static void TryConfirmEnvironmentDescriptionLine() {
+ if (environment != null && !descriptionLine.isEmpty()) {
+ environment.description.add(descriptionLine.trim());
+ descriptionLine = "";
+ }
+ }
+ public static void TryConfirmEnvironment() {
+ if ((environment != null) && (!compiler.environments.containsKey(environment.name))) {
+ if (!descriptionLine.isEmpty())
+ environment.description.add(descriptionLine.trim());
+ environment.CheckDefaults();
+ compiler.environments.put(environment.name, environment);
+ ResetEnvironment();
+ }
+ }
+ public static void ReadOptions(Compiler compiler_in) {
+ compiler = compiler_in;
+ String[] lines = compiler.helpText.split("\n");
+ state = HelpParserState.Search;
+ for (String line_ : lines) {
+ line = line_; //нужна для окружения. там пробелы нужно считать сразу.
+ t_line = Utils.remove(line_.trim(), "\r");
+ switch (state) {
+ case Search:
+ switch (t_line) {
+ case "Output and debugging options:":
+ case "Convertation options:":
+ case "Optimization options:":
+ System.out.println(t_line + " Options chapter started!");
+ state = HelpParserState.OptionsChapter;
+ ResetOption();
+ break;
+ case "Environment variables":
+ System.out.println(t_line + " Environments chapter started!");
+ state = HelpParserState.EnvironmentsChapterHeader;
+ break;
+ }
+ break;
+ case EnvironmentsChapterHeader:
+ state = HelpParserState.EnvironmentsChapter;
+ ResetEnvironment();
+ break;
+ case OptionsChapter:
+ if (t_line.isEmpty()) {
+ TryConfirmOption();
+ System.out.println("Chapter ended");
+ state = HelpParserState.Search;
+ } else {
+ char[] symbols = t_line.toCharArray();
+ //- Новая строка.
+ optionState = OptionState.SearchName;
+ //-
+ for (char c : symbols) {
+ //-
+ // System.out.print(c);
+ //-
+ switch (optionState) {
+ case SearchName:
+ switch (c) {
+ case '-':
+ TryConfirmOption();
+ //-
+ option = new CompilerOption();
+ option.name += c;
+ optionState = OptionState.Name;
+ break;
+ default:
+ descriptionLine += c;
+ optionState = OptionState.Description;
+ break;
+ }
+ break;
+ case Name:
+ switch (c) {
+ case '<':
+ optionState = OptionState.Parameter;
+ break;
+ case ' ':
+ case '=':
+ case '\t':
+ option.parameterSeparator += c;
+ optionState = OptionState.SearchParameter;
+ break;
+ default:
+ option.name += c;
+ break;
+ }
+ break;
+ case SearchParameter:
+ if (c == '<') {
+ optionState = OptionState.Parameter;
+ } else {
+ option.parameterSeparator = "";
+ optionState = OptionState.Description;
+ descriptionLine += c;
+ }
+ break;
+ case Parameter:
+ if (c == '>') {
+ optionState = OptionState.SearchDescription;
+ } else {
+ option.parameterName += c;
+ }
+ break;
+ case SearchDescription:
+ if (c != ' ') {
+ descriptionLine += c;
+ optionState = OptionState.Description;
+ }
+ break;
+ case Description:
+ descriptionLine += c;
+ break;
+ }
+ }
+ //-
+ TryConfirmOptionDescriptionLine();
+ }
+ break;
+ case EnvironmentsChapter:
+ if (t_line.isEmpty()) {
+ TryConfirmEnvironment();
+ System.out.println("Chapter ended");
+ state = HelpParserState.Search;
+ } else {
+ char[] symbols = line.toCharArray();
+ //- Новая строка.
+ environmentState = EnvironmentState.SearchName;
+ spacesCounter = 0;
+ //-
+ for (char c : symbols) {
+ switch (environmentState) {
+ case SearchName:
+ if (c == ' ') {
+ if (spacesCounter++ > 4) {
+ //имя нам уже не встретится. это строка описания.
+ environmentState = EnvironmentState.Description;
+ }
+ } else if (Character.isLetter(c)) {
+ if (spacesCounter == 4) {
+ TryConfirmEnvironment();
+ environment = new CompilerEnvironment();
+ environment.name += c;
+ environmentState = EnvironmentState.Name;
+ }
+ } else {
+ descriptionLine += c;
+ environmentState = EnvironmentState.Description;
+ }
+ break;
+ case Name:
+ //в имени окружения пробелов быть не может. ждем описания.
+ if (c == ' ') {
+ environmentState = EnvironmentState.SearchDescription;
+ } else if (Character.isLetterOrDigit(c) || c == '_') {
+ //буквы цифры и подчеркивания - имя продолжается.
+ environment.name += c;
+ } else {
+ descriptionLine += c;
+ environmentState = EnvironmentState.Description;
+ }
+ break;
+ case SearchDescription:
+ if (c == ' ') {
+ //игнорируем.
+ } else {
+ descriptionLine += c;
+ environmentState = EnvironmentState.Description;
+ }
+ break;
+ case Description:
+ descriptionLine += c;
+ break;
+ }
+ TryConfirmOptionDescriptionLine();
+ }
+ //-
+ TryConfirmEnvironmentDescriptionLine();
+ }
+ break;
+ }
+ }
+ }
+ //------------------------------------------------------------------------------------>>
+}
diff --git a/src/Common/Utils/Validators/EnvironmentState.java b/src/Common/Utils/Validators/EnvironmentState.java
new file mode 100644
index 00000000..87a4fc6c
--- /dev/null
+++ b/src/Common/Utils/Validators/EnvironmentState.java
@@ -0,0 +1,8 @@
+package Common.Utils.Validators;
+public enum EnvironmentState {
+ SearchName,
+ Name,
+ //-
+ SearchDescription,
+ Description
+}
diff --git a/src/Common/Utils/Validators/HelpParserState.java b/src/Common/Utils/Validators/HelpParserState.java
new file mode 100644
index 00000000..f7dce397
--- /dev/null
+++ b/src/Common/Utils/Validators/HelpParserState.java
@@ -0,0 +1,10 @@
+package Common.Utils.Validators;
+public enum HelpParserState {
+ Search,
+ OptionsChapter,
+ //------------------
+ //------------------
+ EnvironmentsChapterHeader,
+ EnvironmentsChapter,
+ End
+}
diff --git a/src/Common/Utils/Validators/OptionState.java b/src/Common/Utils/Validators/OptionState.java
new file mode 100644
index 00000000..8101b9ac
--- /dev/null
+++ b/src/Common/Utils/Validators/OptionState.java
@@ -0,0 +1,11 @@
+package Common.Utils.Validators;
+public enum OptionState {
+ SearchName,
+ Name,
+ //-
+ SearchParameter,
+ Parameter,
+ //-
+ SearchDescription,
+ Description
+}
diff --git a/src/Common/Utils/Validators/PathValidator.java b/src/Common/Utils/Validators/PathValidator.java
new file mode 100644
index 00000000..1b6a061d
--- /dev/null
+++ b/src/Common/Utils/Validators/PathValidator.java
@@ -0,0 +1,68 @@
+package Common.Utils.Validators;
+import Common.Utils.TextLog;
+import Common.Utils.Utils;
+import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
+public class PathValidator extends Validator {
+ PathValidatorState state;
+ StringBuilder name;
+ int spaces_count;
+ public PathValidator(String string, String string_name_in, TextLog log_in) {
+ super(string, string_name_in, log_in);
+ }
+ @Override
+ protected void reset() {
+ state = PathValidatorState.Start;
+ name = new StringBuilder();
+ spaces_count = 0;
+ }
+ @Override
+ protected boolean continueCondition() {
+ return (state == PathValidatorState.Name) || state == PathValidatorState.Start;
+ }
+ @Override
+ protected void Body() {
+ switch (state) {
+ case Start:
+ if (RSyntaxUtilities.isLetter(c) || RSyntaxUtilities.isDigit(c) || c == '_') {
+ name.append(c);
+ state = PathValidatorState.Name;
+ } else state = PathValidatorState.WrongNameFormat;
+ break;
+ case Name:
+ switch (c) {
+ case '/':
+ reset();
+ break;
+ case ' ':
+ spaces_count++;
+ name.append(c);
+ break;
+ default:
+ if (Utils.isForbidden(c))
+ state = PathValidatorState.Forbidden;
+ else name.append(c);
+ break;
+ }
+ break;
+ }
+ }
+ @Override
+ protected void PerformFinish() {
+ switch (state) {
+ case WrongNameFormat:
+ Log.Writeln(string_name + ": имя файла или каталога в пути имеет неверный формат");
+ break;
+ case Forbidden:
+ Log.Writeln(string_name + ": Составляющие путь имена содержат запрещённые символы \n" + Utils.all_forbidden_characters_string);
+ break;
+ case Name:
+ if (spaces_count > 0)
+ Log.Writeln(string_name + ": Пробелы в окончании пути к файлу запрещены.");
+ break;
+ }
+ }
+ @Override
+ protected int getStartIndex() {
+ return 1;
+ }
+}
diff --git a/src/Common/Utils/Validators/PathValidatorState.java b/src/Common/Utils/Validators/PathValidatorState.java
new file mode 100644
index 00000000..e6244bff
--- /dev/null
+++ b/src/Common/Utils/Validators/PathValidatorState.java
@@ -0,0 +1,8 @@
+package Common.Utils.Validators;
+public enum PathValidatorState {
+ Start,
+ Name,
+ WrongNameFormat,
+ Forbidden,
+ SpacesInLastName
+}
diff --git a/src/Common/Utils/Validators/ShellParser.java b/src/Common/Utils/Validators/ShellParser.java
new file mode 100644
index 00000000..255191be
--- /dev/null
+++ b/src/Common/Utils/Validators/ShellParser.java
@@ -0,0 +1,229 @@
+package Common.Utils.Validators;
+import Common.Global;
+import Common.Utils.Utils;
+
+import java.io.InputStreamReader;
+import java.util.Vector;
+public class ShellParser {
+ public static ShellParserState state;
+ public static StringBuilder lineBuilder;
+ public static String userName;
+ public static StringBuilder invitationBuilder;
+ public static char c;
+ public static char[] buffer = new char[1];
+ public static Vector lines = new Vector<>();
+ public static boolean bracketOpened = false;
+ public static boolean return_active = false;
+ public static boolean isCommandSymbol() {
+ int code = c;
+ return code <= 31 || c == 127;
+ }
+ public static void ResetLine() {
+ invitationBuilder = new StringBuilder();
+ lineBuilder = new StringBuilder();
+ bracketOpened = false;
+ state = ShellParserState.NewLine;
+ return_active = false;
+ }
+ public static boolean isNameCharacter() {
+ //латиница, цифры,подчеркивания. и -
+ return String.valueOf(c).matches("[\\w\\-]*") || c == '?';
+ }
+ //false наоборот означать что конец строки ЕСТЬ.
+ public static boolean checkEndLine() {
+ if (return_active) {
+ switch (c) {
+ case '\n':
+ //ложная тревога. возврат каретки ни на что не влияет.
+ lines.add(lineBuilder.toString());
+ ResetLine();
+ return false;
+ case '\r':
+ return false;
+ default:
+ //тут был возврат. надо игнорить символ, ибо он уже прочитан.
+ return_active = false;
+ return false;
+ }
+ } else {
+ switch (c) {
+ case '\r':
+ return_active = true;
+ return false;
+ case '\n':
+ lines.add(lineBuilder.toString());
+ ResetLine();
+ return false;
+ }
+ }
+ return true;
+ }
+ public static void NewLine() {
+ if (c == '[') {//приглашение со скобками.
+ bracketOpened = true;
+ invitationBuilder.append(c);
+ state = ShellParserState.UserName;
+ } else {
+ if (isNameCharacter()) {
+ invitationBuilder.append(c);
+ state = ShellParserState.UserName;
+ } else
+ //не буква и не скобка. значит в этой строке приглашения нет.
+ state = ShellParserState.Skip;
+ }
+ }
+ public static void UserName() {
+ if (c == '@') { //проверить. а тот ли юзернейм.
+ String test = invitationBuilder.toString();
+ if (bracketOpened) test = test.substring(1);
+ test = test.toLowerCase();
+ state = test.endsWith(userName.toLowerCase()) ? ShellParserState.MachineName : ShellParserState.Skip;
+ invitationBuilder.append(c);
+ } else if (isNameCharacter()||(c=='['))
+ invitationBuilder.append(c);
+ else
+ state = ShellParserState.Skip;
+ }
+ public static void MachineName() {
+ switch (c) {
+ case ' ':
+ case ':':
+ state = ShellParserState.Path;
+ invitationBuilder.append(c);
+ break;
+ default:
+ if (isNameCharacter())
+ invitationBuilder.append(c);
+ else state = ShellParserState.Skip;
+ break;
+ }
+ }
+ public static void Path() {
+ switch (c) {
+ case '$':
+ case '#':
+ case '>':
+ invitationBuilder.append(c);
+ state = ShellParserState.Space; //приглашение завершено. осталось прочитать пробел после него
+ break;
+ case ']':
+ if (bracketOpened) {
+ invitationBuilder.append(c);
+ bracketOpened = false;
+ } else {
+ // UI.Info("KEK");
+ state = ShellParserState.Skip; //непарная скобка, все, привет
+ }
+ break;
+ default:
+ invitationBuilder.append(c);
+ break;
+ }
+ }
+ public static void Space() {
+ if (c == ' ') {
+ state = ShellParserState.End;
+ invitationBuilder.append(c);
+ } else {
+ state = ShellParserState.Skip;
+ }
+ }
+ public static void setUserName(String userName_in) {
+ userName = userName_in;
+ }
+ public static void printChar() {
+ int code = c;
+ if ((!return_active) || (c == '\n')) {
+ System.out.print(c == '\r' ? ("\\r") :
+
+ (c=='\n'? "\\n\n":c));
+ if (isCommandSymbol())
+ System.out.print(Utils.RBrackets(code));
+ }
+ }
+ public static void ReadInvitation(InputStreamReader fromServer) {
+ lines.clear();
+ ResetLine();
+ do {
+ try {
+ if (fromServer.read(buffer) >= 0) {
+ c = buffer[0];
+ printChar();
+ // if (!isCommandSymbol()) {
+ if (checkEndLine() && (!isCommandSymbol())) {
+ lineBuilder.append(c);
+ switch (state) {
+ case NewLine:
+ NewLine();
+ break;
+ case UserName:
+ UserName();
+ break;
+ case MachineName:
+ MachineName();
+ break;
+ case Path:
+ Path();
+ break;
+ case Space:
+ Space();
+ break;
+ case Skip:
+ break;
+ }
+ }
+ // System.out.println(Utils.Brackets(state));
+ // }
+ } else
+ state = ShellParserState.End;
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ state = ShellParserState.End;
+ }
+ } while (!state.equals(ShellParserState.End));
+ }
+ public static void ReadLine(InputStreamReader fromServer) {
+ state = ShellParserState.NewLine;
+ do {
+ try {
+ if (fromServer.read(buffer) >= 0) {
+ c = buffer[0];
+ printChar();
+ switch (c) {
+ case '\r':
+ break;
+ case '\n':
+ return;
+ }
+ } else
+ state = ShellParserState.End;
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ state = ShellParserState.End;
+ }
+ } while (!state.equals(ShellParserState.End));
+ }
+ public static String getCommandResult(InputStreamReader fromServer) {
+ //если последняя строка ответа - кончается на приглашение, то ничего не делаем.
+ //если нет. значит ответ кончается на перевод строки. или пуст.
+ // нужно прочитать еще одно приглашение.
+ String last_line = "";
+ String res = "";
+ boolean no_extra_read = false;
+ if (lines.size() > 0) {
+ last_line = lines.lastElement();
+ if (no_extra_read = last_line.endsWith(invitationBuilder.toString())) {
+ System.out.println("needs trim");
+ lines.remove(lines.size() - 1);
+ //больше ничего не читаем. но. обрезаем ее конец.
+ last_line = last_line.substring(0, last_line.length() - invitationBuilder.length());
+ lines.add(last_line);
+ }
+ res = String.join("\n", lines);
+ }
+ if (!no_extra_read) {
+ ReadInvitation(fromServer);
+ }
+ return res;
+ }
+}
diff --git a/src/Common/Utils/Validators/ShellParserState.java b/src/Common/Utils/Validators/ShellParserState.java
new file mode 100644
index 00000000..174dbc82
--- /dev/null
+++ b/src/Common/Utils/Validators/ShellParserState.java
@@ -0,0 +1,12 @@
+package Common.Utils.Validators;
+public enum ShellParserState {
+ //--------------------------------
+ NewLine, //начало строки.
+ UserName, //имя пользователя.
+ MachineName, //имя машины
+ Path, //путь к текущей папке - часть приглашения
+ Space, //завершающий приглашение пробел.
+ Skip, //гарантированно не приглашение.
+ //--------------------------------
+ End//выход
+}
diff --git a/src/Common/Utils/Validators/StatementsChecker.java b/src/Common/Utils/Validators/StatementsChecker.java
new file mode 100644
index 00000000..5d21fb31
--- /dev/null
+++ b/src/Common/Utils/Validators/StatementsChecker.java
@@ -0,0 +1,14 @@
+package Common.Utils.Validators;
+import Common.Utils.TextLog;
+public class StatementsChecker {
+ public static boolean Check(TextLog Log, boolean drop_on_first, Object... args) {
+ if (args.length % 2 != 0) return false;
+ for (int i = 0; i < args.length; i += 2) {
+ if ((boolean) args[i]) {
+ Log.Writeln((String) args[i + 1]);
+ if (drop_on_first) return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/Common/Utils/Validators/Validator.java b/src/Common/Utils/Validators/Validator.java
new file mode 100644
index 00000000..a9d69147
--- /dev/null
+++ b/src/Common/Utils/Validators/Validator.java
@@ -0,0 +1,36 @@
+package Common.Utils.Validators;
+import Common.Utils.TextLog;
+public class Validator {
+ protected char c;
+ protected int i;
+ protected String string_name;
+ protected char[] chars;
+ protected TextLog Log;
+ public Validator(String string, String string_name_in, TextLog log_in) {
+ string_name = string_name_in;
+ chars = string.toCharArray();
+ Log = log_in;
+ reset();
+ }
+ protected void reset() {
+ }
+ protected int getStartIndex() {
+ return 0;
+ }
+ protected boolean continueCondition() {
+ return true;
+ }
+ protected void Body() {
+ }
+ protected void PerformFinish() {
+ }
+ public void Validate() {
+ for (i = getStartIndex(); i < chars.length && continueCondition(); ++i) {
+ c = chars[i];
+ System.out.print(c);
+ Body();
+ }
+ System.out.println();
+ PerformFinish();
+ }
+}
diff --git a/src/GlobalData/Account/Account.java b/src/GlobalData/Account/Account.java
new file mode 100644
index 00000000..c63fd1ed
--- /dev/null
+++ b/src/GlobalData/Account/Account.java
@@ -0,0 +1,63 @@
+package GlobalData.Account;
+import Common.Database.DBObject;
+import Common.UI.UI;
+import Common.Utils.TextLog;
+import Repository.BugReport.BugReport;
+import com.sun.org.glassfish.gmbal.Description;
+public class Account extends DBObject {
+ @Description("PRIMARY KEY,NOT NULL")
+ public int id = 0;
+ public String name = "?";
+ public String email = "?";
+ //--
+ @Description("IGNORE")
+ public AccountRole role = AccountRole.Undefined; //роль незареганного пользователя
+ //--
+ public boolean CheckRegistered(TextLog Log) {
+ if (role.equals(AccountRole.Undefined)) {
+ if (Log != null) {
+ Log.Writeln("Пользователь не зарегистрирован");
+ if (UI.HasNewMainWindow())
+ UI.getMainWindow().FocusCallback();
+ }
+ return false;
+ }
+ return true;
+ }
+ public boolean isRegistered() {
+ return !role.equals(AccountRole.Undefined);
+ }
+ public boolean CheckAuthorship(String address_in, TextLog log) {
+ if (!isAdmin() && (!email.equals(address_in))) {
+ if (log != null)
+ log.Writeln_("Вы не являетесь автором или администратором");
+ return false;
+ }
+ return true;
+ }
+ public boolean CheckAccessRights(String address_in, TextLog log) {
+ return (CheckRegistered(log) && CheckAuthorship(address_in, log));
+ }
+ public boolean ExtendedCheckAccessRights(BugReport bugReport, TextLog log) {
+ if (CheckRegistered(log)) {
+ if (email.equals(bugReport.executor_address)) {
+ //исполнитель.
+ return true;
+ } else {
+ if (!isAdmin() && (!email.equals(bugReport.sender_address))) {
+ log.Writeln_("Вы не являетесь автором, исполнителем, или администратором");
+ return false;
+ } else return true;
+ }
+ }
+ return false;
+ }
+ public boolean isAdmin() {
+ return role.equals(AccountRole.Admin);
+ }
+ @Override
+ public Object getPK() {
+ return id;
+ }
+}
+
diff --git a/src/GlobalData/Account/AccountRole.java b/src/GlobalData/Account/AccountRole.java
new file mode 100644
index 00000000..e636dccc
--- /dev/null
+++ b/src/GlobalData/Account/AccountRole.java
@@ -0,0 +1,22 @@
+package GlobalData.Account;
+public enum AccountRole {
+ Undefined,
+ User,
+ Developer,
+ Admin;
+ public String getDescription() {
+ switch (this) {
+ case Undefined:
+ return "не зарегистрирован";
+ case User:
+ return "Пользователь";
+ case Developer:
+ return "Разработчик";
+ case Admin:
+ return "Администратор";
+ default:
+ break;
+ }
+ return "";
+ }
+}
diff --git a/src/GlobalData/Account/AccountSubscribeState.java b/src/GlobalData/Account/AccountSubscribeState.java
new file mode 100644
index 00000000..3a84612b
--- /dev/null
+++ b/src/GlobalData/Account/AccountSubscribeState.java
@@ -0,0 +1,19 @@
+package GlobalData.Account;
+public enum AccountSubscribeState {
+ Undefined,
+ None,
+ Active;
+ public String getDescription() {
+ switch (this) {
+ case Undefined:
+ return "Подписка: нет данных";
+ case None:
+ return "Подписка: аннулирована";
+ case Active:
+ return "Подписка: активна";
+ default:
+ break;
+ }
+ return "";
+ }
+}
diff --git a/src/GlobalData/Account/AccountsDBTable.java b/src/GlobalData/Account/AccountsDBTable.java
new file mode 100644
index 00000000..f6a298b6
--- /dev/null
+++ b/src/GlobalData/Account/AccountsDBTable.java
@@ -0,0 +1,11 @@
+package GlobalData.Account;
+import Common.Database.DBTable;
+public class AccountsDBTable extends DBTable {
+ public AccountsDBTable() {
+ super(Integer.class, Account.class);
+ }
+ @Override
+ public String getSingleDescription() {
+ return "аккаунт";
+ }
+}
diff --git a/src/GlobalData/Compiler/Compiler.java b/src/GlobalData/Compiler/Compiler.java
new file mode 100644
index 00000000..14946483
--- /dev/null
+++ b/src/GlobalData/Compiler/Compiler.java
@@ -0,0 +1,193 @@
+package GlobalData.Compiler;
+import Common.Current;
+import Common.Database.iDBObject;
+import Common.Utils.Utils;
+import Common.Utils.Validators.DVMHelpParser;
+import GlobalData.CompilerEnvironment.CompilerEnvironmentsSet;
+import GlobalData.CompilerOption.CompilerOptionsSet;
+import GlobalData.Machine.Machine;
+import ProjectData.Files.DBProjectFile;
+import ProjectData.LanguageName;
+import com.sun.org.glassfish.gmbal.Description;
+public class Compiler extends iDBObject {
+ public int machine_id = -1;
+ public String description = "";
+ public CompilerType type = CompilerType.dvm;
+ public String home_path = ""; //домашняя папка. нужна для двм компиляторов, в теории и для остальных может сгодиться, например для установки окружения ifort под виндой
+ public String call_command = ""; //непосредственно вызов компилятора.
+ public String version_command = "";//команда запроса версии компилятора.
+ public String help_command = "";// команда запроса help
+ public String version = "?";
+ public String revision = "?";
+ //-
+ @Description("IGNORE")
+ public boolean helpLoaded = false;
+ @Description("IGNORE")
+ public String helpText = "";
+ //-
+ @Description("IGNORE")
+ public boolean versionLoaded = false;
+ @Description("IGNORE")
+ public String versionText = "";
+ //-
+ public CompilerOptionsSet options = new CompilerOptionsSet();
+ public CompilerEnvironmentsSet environments = new CompilerEnvironmentsSet();
+ //-
+ public Compiler() {
+ }
+ public Compiler(Machine machine,
+ String description_in,
+ CompilerType type_in,
+ String call_command_in,
+ String version_command_in,
+ String help_command_in
+ ) {
+ machine_id = machine.id;
+ description = description_in;
+ type = type_in;
+ call_command = call_command_in;
+ version_command = version_command_in;
+ help_command = help_command_in;
+ }
+ public void ResetHelp() {
+ helpLoaded = false;
+ helpText = "";
+ options.clear();
+ environments.clear();
+ }
+ public void ResetVersion() {
+ versionLoaded = false;
+ versionText = "";
+ }
+ public void ParseHelp() {
+ switch (type) {
+ case dvm:
+ DVMHelpParser.ReadOptions(this);
+ break;
+ default:
+ break;
+ }
+ }
+ public void ParseVersion() {
+ switch (type) {
+ case dvm:
+ String [] lines = versionText.split("\n");
+ if (lines.length>=3) {
+ String[] data = lines[2].split(" ");
+ if (data.length >= 4)
+ version = data[3].replace(",", "");
+ if (data.length >= 7) revision = data[6].replace(",", "");
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ @Override
+ public boolean isVisible() {
+ return Current.HasMachine() && Current.getMachine().id == machine_id;
+ }
+ //todo понять как извлекать версию чтобы выдавать нормальную инфу.
+ @Override
+ public String toString() {
+ return call_command;
+ }
+ public String getStyleOptions(DBProjectFile program) {
+ String res = "";
+ switch (type) {
+ case gnu:
+ switch (program.languageName) {
+ case fortran:
+ switch (program.style) {
+ case free:
+ res = "-ffree-form";
+ break;
+ case extended:
+ res = "-ffixed-line-length-132";
+ break;
+ case fixed:
+ res = "-ffixed-form";
+ break;
+ case none:
+ break;
+ }
+ break;
+ }
+ break;
+ case dvm:
+ switch (program.languageName) {
+ case fortran:
+ switch (program.style) {
+ case fixed:
+ case extended:
+ res = "-FI";
+ break;
+ case free:
+ res = "-f90";
+ break;
+ case none:
+ break;
+ }
+ break;
+ }
+ break;
+ case intel:
+ switch (program.languageName) {
+ case fortran:
+ switch (program.style) {
+ case fixed:
+ case extended:
+ res = "-fixed";
+ break;
+ case free:
+ res = "-free";
+ break;
+ case none:
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ return res;
+ }
+ //todo как то извлекать/заполнять версии компилятора?
+ public String getDescription() {
+ return description;
+ }
+ public String getSpecialLinkCommand(LanguageName languageName) {
+ switch (type) {
+ case dvm:
+ switch (languageName) {
+ case fortran:
+ return "flink";
+ case c:
+ return "clink";
+ }
+ break;
+ }
+ return "";
+ }
+ public String getSpecialCompilationCommand(LanguageName languageName) {
+ switch (type) {
+ case dvm:
+ switch (languageName) {
+ case fortran:
+ return "f";
+ case c:
+ return "c";
+ }
+ break;
+ }
+ return "";
+ }
+ public String getHelpCommand() {
+ return Utils.DQuotes(call_command) + " " + help_command;
+ }
+ public String getVersionCommand() {
+ return Utils.DQuotes(call_command) + " " + version_command;
+ }
+ public String getVersionInfo(){
+ return "v="+version+" r="+revision;
+ }
+}
diff --git a/src/GlobalData/Compiler/CompilerType.java b/src/GlobalData/Compiler/CompilerType.java
new file mode 100644
index 00000000..25d39c5a
--- /dev/null
+++ b/src/GlobalData/Compiler/CompilerType.java
@@ -0,0 +1,9 @@
+package GlobalData.Compiler;
+public enum CompilerType {
+ Undefined,
+ //----------------------
+ dvm,
+ mpi,
+ gnu,
+ intel
+}
diff --git a/src/GlobalData/Compiler/CompilersDBTable.java b/src/GlobalData/Compiler/CompilersDBTable.java
new file mode 100644
index 00000000..9a3ab08f
--- /dev/null
+++ b/src/GlobalData/Compiler/CompilersDBTable.java
@@ -0,0 +1,153 @@
+package GlobalData.Compiler;
+import Common.Current;
+import Common.Database.*;
+import Common.UI.DataSetControlForm;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.DBObjectDialog;
+import Common.Utils.Utils;
+import Common.Utils.Validators.PathValidator;
+import GlobalData.Compiler.UI.CompilerFields;
+import GlobalData.Makefile.Makefile;
+import GlobalData.Module.Module;
+import GlobalData.RunConfiguration.RunConfiguration;
+
+import java.util.LinkedHashMap;
+public class CompilersDBTable extends iDBTable {
+ public CompilersDBTable() {
+ super(Compiler.class);
+ }
+ @Override
+ public String getSingleDescription() {
+ return "компилятор";
+ }
+ @Override
+ public String getPluralDescription() {
+ return "компиляторы";
+ }
+ @Override
+ public LinkedHashMap, FKBehaviour> getFKDependencies() {
+ LinkedHashMap, FKBehaviour> res = new LinkedHashMap<>();
+ res.put(Makefile.class, new FKBehaviour(FKDataBehaviour.DROP, FKCurrentObjectBehaviuor.PASSIVE));
+ res.put(Module.class, new FKBehaviour(FKDataBehaviour.DROP, FKCurrentObjectBehaviuor.PASSIVE));
+ res.put(RunConfiguration.class, new FKBehaviour(FKDataBehaviour.DROP, FKCurrentObjectBehaviuor.PASSIVE));
+ return res;
+ }
+ @Override
+ public DBObjectDialog getDialog() {
+ return new DBObjectDialog(CompilerFields.class) {
+ @Override
+ public void validateFields() {
+ //
+ String home = fields.tfHome.getText();
+ if (!home.isEmpty()) {
+ if (home.startsWith("/")) {
+ if (Utils.ContainsCyrillic(home))
+ Log.Writeln("Расположение компилятора не может содержать кириллицу");
+ else {
+ new PathValidator(home, "Расположение компилятора", Log).Validate();
+ }
+ } else
+ Log.Writeln("Расположение компилятора может быть либо пустой строкой, либо путём к файлу");
+ }
+ //
+ //
+ String call_command = fields.tfCallCommand.getText();
+ if (call_command.isEmpty())
+ Log.Writeln("Команда вызова компилятора не может быть пустой");
+ else if (Utils.ContainsCyrillic(call_command))
+ Log.Writeln("Команда вызова компилятора не может содержать кириллицу");
+ else {
+ switch (call_command.charAt(0)) {
+ case ' ':
+ Log.Writeln("Команда вызова компилятора не может начинаться с пробела.");
+ break;
+ case '/':
+ if (call_command.endsWith("/"))
+ Log.Writeln("Каталог не может быть указан в качестве команды.");
+ else
+ new PathValidator(call_command, "Команда вызова компилятора", Log).Validate();
+ break;
+ default:
+ //это команда.
+ //самое опасное место. теоретически тут можно ввести любую команду ОС, в том числе rm -rf
+ if (call_command.contains(" "))
+ Log.Writeln("Прямая команда вызова не может содержать пробелы");
+ if (!call_command.contains("+")&&Utils.ContainsForbiddenName(call_command))
+ Log.Writeln("Прямая команда вызова содержит запрещённые символы");
+ else {
+ if (Utils.isLinuxSystemCommand(call_command))
+ Log.Writeln(Utils.DQuotes(call_command) + " является системной командой Linux");
+ }
+ break;
+ }
+ }
+ //
+ }
+ @Override
+ public void fillFields() {
+ fields.tfDescription.setText(Result.description);
+ fields.tfCallCommand.setText(Result.call_command);
+ fields.tfHelpCommand.setText(Result.help_command);
+ fields.tfVersionCommand.setText(Result.version_command);
+ fields.tfHome.setText(Result.home_path);
+ UI.TrySelect(fields.cbCompilerType, Result.type);
+ fields.events_on = true;
+ }
+ @Override
+ public void ProcessResult() {
+ Result.machine_id = Current.getMachine().id;
+ Result.description = fields.tfDescription.getText();
+ Result.call_command = fields.tfCallCommand.getText();
+ Result.help_command = fields.tfHelpCommand.getText();
+ Result.version_command = fields.tfVersionCommand.getText();
+ Result.home_path = fields.tfHome.getText();
+ Result.type = (CompilerType) fields.cbCompilerType.getSelectedItem();
+ }
+ @Override
+ public int getDefaultHeight() {
+ return 300;
+ }
+ };
+ }
+ @Override
+ protected DataSetControlForm createUI() {
+ return new DataSetControlForm(this){
+ @Override
+ protected void AdditionalInitColumns() {
+ columns.get(0).setVisible(false);
+ }
+ @Override
+ public void ShowCurrentObject() throws Exception {
+ super.ShowCurrentObject();
+ UI.getMainWindow().getTestingWindow().ShowCredentials();
+ }
+ @Override
+ public void ShowNoCurrentObject() throws Exception {
+ super.ShowNoCurrentObject();
+ UI.getMainWindow().getTestingWindow().ShowCredentials();
+ }
+ };
+ }
+ @Override
+ public String[] getUIColumnNames() {
+ return new String[]{"описание", "команда вызова", "версия", "ревизия"};
+ }
+ @Override
+ public Object getFieldAt(Compiler object, int columnIndex) {
+ switch (columnIndex) {
+ case 1:
+ return object.description;
+ case 2:
+ return object.call_command;
+ case 3:
+ return object.version;
+ case 4:
+ return object.revision;
+ }
+ return null;
+ }
+ @Override
+ public Current CurrentName() {
+ return Current.Compiler;
+ }
+}
diff --git a/src/GlobalData/Compiler/UI/CompilerFields.form b/src/GlobalData/Compiler/UI/CompilerFields.form
new file mode 100644
index 00000000..8d0dccf7
--- /dev/null
+++ b/src/GlobalData/Compiler/UI/CompilerFields.form
@@ -0,0 +1,134 @@
+
+
diff --git a/src/GlobalData/Compiler/UI/CompilerFields.java b/src/GlobalData/Compiler/UI/CompilerFields.java
new file mode 100644
index 00000000..1ee43dd8
--- /dev/null
+++ b/src/GlobalData/Compiler/UI/CompilerFields.java
@@ -0,0 +1,93 @@
+package GlobalData.Compiler.UI;
+import Common.Current;
+import Common.UI.TextField.StyledTextField;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.DialogFields;
+import Common.Utils.Files.VDirectoryChooser;
+import GlobalData.Compiler.CompilerType;
+import GlobalData.Machine.MachineType;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+
+import javax.swing.*;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import java.awt.*;
+import java.io.File;
+import java.util.Objects;
+public class CompilerFields implements DialogFields {
+ public JPanel content;
+ public JTextField tfHome;
+ public JButton bBrowse;
+ public JTextField tfDescription;
+ public JTextField tfCallCommand;
+ public JTextField tfVersionCommand;
+ public JTextField tfHelpCommand;
+ public JComboBox cbCompilerType;
+ public boolean events_on = false;
+ VDirectoryChooser directoryChooser = new VDirectoryChooser("Выбор домашней папки dvm системы");
+ public CompilerFields() {
+ bBrowse.addActionListener(e -> {
+ CompilerType type = (CompilerType) cbCompilerType.getSelectedItem();
+ if (type == CompilerType.dvm) {
+ String dst = null;
+ if (Current.getMachine().type.equals(MachineType.Local)) {
+ File file = directoryChooser.ShowDialog();
+ if (file != null)
+ dst = file.getAbsolutePath();
+ } else {
+ if (Pass_2021.passes.get(PassCode_2021.SelectRemoteFile).Do(true))
+ dst = Current.getRemoteFile().full_name;
+ }
+ if (dst != null)
+ tfHome.setText(dst);
+ } else
+ UI.Info("Назначение домашней папки поддерживается только для dvm системы.");
+ });
+ tfHome.getDocument().addDocumentListener(new DocumentListener() {
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ TryRestoreCallCommand();
+ }
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ TryRestoreCallCommand();
+ }
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ }
+ }
+ );
+ cbCompilerType.addActionListener(e -> {
+ if (Objects.requireNonNull(cbCompilerType.getSelectedItem()) == CompilerType.dvm) {
+ tfVersionCommand.setText("ver");
+ tfHelpCommand.setText("help");
+ } else {
+ tfVersionCommand.setText("--version");
+ tfHelpCommand.setText("--help");
+ }
+ });
+ }
+ public void TryRestoreCallCommand() {
+ if (events_on && (cbCompilerType.getSelectedItem() != null) && cbCompilerType.getSelectedItem().equals(CompilerType.dvm))
+ tfCallCommand.setText(tfHome.getText() +
+ (tfHome.getText().endsWith("/") ? "" : "/") +
+ "bin/dvm_drv");
+ }
+ private void createUIComponents() {
+ // TODO: place custom component creation code here
+ tfDescription = new StyledTextField();
+ tfHome = new StyledTextField();
+ tfCallCommand = new StyledTextField();
+ tfVersionCommand = new StyledTextField();
+ tfHelpCommand = new StyledTextField();
+ cbCompilerType = new JComboBox<>();
+ cbCompilerType.addItem(CompilerType.dvm);
+ cbCompilerType.addItem(CompilerType.intel);
+ cbCompilerType.addItem(CompilerType.gnu);
+ }
+ @Override
+ public Component getContent() {
+ return content;
+ }
+}
diff --git a/src/GlobalData/CompilerEnvironment/CompilerEnvironment.java b/src/GlobalData/CompilerEnvironment/CompilerEnvironment.java
new file mode 100644
index 00000000..6b709340
--- /dev/null
+++ b/src/GlobalData/CompilerEnvironment/CompilerEnvironment.java
@@ -0,0 +1,76 @@
+package GlobalData.CompilerEnvironment;
+import Common.Database.DBObject;
+import Common.Utils.TextLog;
+import com.sun.org.glassfish.gmbal.Description;
+
+import java.util.Vector;
+public class CompilerEnvironment extends DBObject {
+ @Description("PRIMARY KEY, UNIQUE")
+ public String name = "";
+ public String value = "";
+ public EnvironmentValueType type = EnvironmentValueType.String;
+ public Vector valueVariants = new Vector<>();
+ public Vector description = new Vector<>();
+ @Override
+ public Object getPK() {
+ return name;
+ }
+ public void CheckDefaults() {
+ //определить тип. в dvm переменных он может быть указан в начале 1 строки.
+ if (!description.isEmpty()) {
+ String line = description.get(0);
+ if (line.startsWith("Boolean value.")) {
+ type = EnvironmentValueType.Boolean;
+ valueVariants.add("0");
+ valueVariants.add("1");
+ } else if (line.startsWith("Integer value.")) {
+ type = EnvironmentValueType.Integer;
+ } else if (line.startsWith("Real number.")) {
+ type = EnvironmentValueType.Real;
+ }
+ //-
+ if (line.endsWith("Accepted values:")) {
+ // все что дальше - варианты и их описания после запятой.
+ for (int i = 1; i < description.size(); ++i) {
+ String[] data = description.get(i).split(",");
+ if (data.length > 1)
+ valueVariants.add(data[0]);
+ }
+ }
+ }
+ }
+ public void validate(TextLog log, String new_value) {
+ if (new_value.isEmpty()) {
+ log.Writeln_("Переменная не предполагает пустого значения");
+ } else {
+ if (!valueVariants.isEmpty()) {
+ if (!valueVariants.contains(new_value))
+ log.Writeln_("Переменная : недопустимое значение. Выберите доступный вариант.");
+ }
+ switch (type) {
+ case Boolean:
+ if (!valueVariants.contains(new_value))
+ log.Writeln_("Переменная допускает только 0 или 1 в качестве значений");
+ break;
+ case Integer:
+ try {
+ Integer.parseInt(new_value);
+ } catch (NumberFormatException ex) {
+ log.Writeln_("Переменная допускает только целочисленные значения");
+ }
+ break;
+ case Real:
+ try {
+ Double.parseDouble(new_value);
+ } catch (NumberFormatException ex) {
+ log.Writeln_("Переменная допускает только числа с плавающей запятой в качестве значения");
+ }
+ break;
+ case String:
+ if (new_value.contains("\""))
+ log.Writeln_("Переменная не может содержать двойные кавычки в значении");
+ break;
+ }
+ }
+ }
+}
diff --git a/src/GlobalData/CompilerEnvironment/CompilerEnvironmentsSet.java b/src/GlobalData/CompilerEnvironment/CompilerEnvironmentsSet.java
new file mode 100644
index 00000000..78470b67
--- /dev/null
+++ b/src/GlobalData/CompilerEnvironment/CompilerEnvironmentsSet.java
@@ -0,0 +1,45 @@
+package GlobalData.CompilerEnvironment;
+import Common.Database.DataSet;
+import Common.UI.DataSetControlForm;
+import Common.UI.Tables.TableEditors;
+import Common.UI.Tables.TableRenderers;
+
+import static Common.UI.Tables.TableRenderers.RendererMultiline;
+public class CompilerEnvironmentsSet extends DataSet {
+ public CompilerEnvironmentsSet() {
+ super(String.class, CompilerEnvironment.class);
+ }
+ @Override
+ public String[] getUIColumnNames() {
+ return new String[]{
+ "Значение", "Описание"
+ };
+ }
+ @Override
+ public Object getFieldAt(CompilerEnvironment object, int columnIndex) {
+ switch (columnIndex) {
+ case 2:
+ return object.value;
+ case 3:
+ return object.description;
+ default:
+ return null;
+ }
+ }
+ @Override
+ protected DataSetControlForm createUI() {
+ return new DataSetControlForm(this) {
+ @Override
+ public boolean hasCheckBox() {
+ return true;
+ }
+ @Override
+ protected void AdditionalInitColumns() {
+ columns.get(2).setRenderer(TableRenderers.RendererCompilerEnvironmentValue);
+ columns.get(2).setEditor(TableEditors.EditorCompilerEnvironmentValue);
+ //-
+ columns.get(3).setRenderer(RendererMultiline);
+ }
+ };
+ }
+}
diff --git a/src/GlobalData/CompilerEnvironment/EnvironmentValueType.java b/src/GlobalData/CompilerEnvironment/EnvironmentValueType.java
new file mode 100644
index 00000000..2ee34744
--- /dev/null
+++ b/src/GlobalData/CompilerEnvironment/EnvironmentValueType.java
@@ -0,0 +1,7 @@
+package GlobalData.CompilerEnvironment;
+public enum EnvironmentValueType {
+ String,
+ Boolean,
+ Integer,
+ Real
+}
diff --git a/src/GlobalData/CompilerEnvironment/UI/CompilerEnvironmentValueEditor.java b/src/GlobalData/CompilerEnvironment/UI/CompilerEnvironmentValueEditor.java
new file mode 100644
index 00000000..f01853d9
--- /dev/null
+++ b/src/GlobalData/CompilerEnvironment/UI/CompilerEnvironmentValueEditor.java
@@ -0,0 +1,36 @@
+package GlobalData.CompilerEnvironment.UI;
+import Common.Current;
+import Common.UI.Tables.DBObjectEditor;
+import Common.UI.Themes.VisualiserFonts;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.Text.ComboTextDialog;
+import GlobalData.CompilerEnvironment.CompilerEnvironment;
+public class CompilerEnvironmentValueEditor extends DBObjectEditor {
+ @Override
+ public void Action() {
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Hyperlink));
+ setText(value.value.isEmpty() ? "не задано" : value.value);
+ //-
+ ComboTextDialog dialog = new ComboTextDialog() {
+ @Override
+ public void validateFields() {
+ super.validateFields();
+ if (fields.getSelectedItem() != null)
+ value.validate(Log, fields.getSelectedItem().toString());
+ }
+ };
+ dialog.fields.setEditable(value.valueVariants.isEmpty());
+ if (!value.value.isEmpty())
+ UI.TrySelect(dialog.fields, value.value);
+ if (dialog.ShowDialog("Изменить значение опции " + value.name,
+ value.valueVariants
+ )) {
+ value.value = dialog.Result;
+ setText(value.value.isEmpty() ? "не задано" : value.value);
+ }
+ }
+ @Override
+ public Object getCellEditorValue() {
+ return value.value;
+ }
+}
diff --git a/src/GlobalData/CompilerEnvironment/UI/CompilerEnvironmentValueRenderer.java b/src/GlobalData/CompilerEnvironment/UI/CompilerEnvironmentValueRenderer.java
new file mode 100644
index 00000000..5e0fe3b7
--- /dev/null
+++ b/src/GlobalData/CompilerEnvironment/UI/CompilerEnvironmentValueRenderer.java
@@ -0,0 +1,15 @@
+package GlobalData.CompilerEnvironment.UI;
+import Common.Current;
+import Common.UI.Tables.DBObjectRenderer;
+import Common.UI.Themes.VisualiserFonts;
+import GlobalData.CompilerEnvironment.CompilerEnvironment;
+public class CompilerEnvironmentValueRenderer extends DBObjectRenderer {
+ @Override
+ public void Display() {
+ if (value != null) {
+ CompilerEnvironment environment = (CompilerEnvironment) value;
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Hyperlink));
+ setText(environment.value.isEmpty() ? "не задано" : environment.value);
+ }
+ }
+}
diff --git a/src/GlobalData/CompilerEnvironment/UI/CompilerEnvironmentsFields.form b/src/GlobalData/CompilerEnvironment/UI/CompilerEnvironmentsFields.form
new file mode 100644
index 00000000..5f59f3cd
--- /dev/null
+++ b/src/GlobalData/CompilerEnvironment/UI/CompilerEnvironmentsFields.form
@@ -0,0 +1,11 @@
+
+
diff --git a/src/GlobalData/CompilerEnvironment/UI/CompilerEnvironmentsFields.java b/src/GlobalData/CompilerEnvironment/UI/CompilerEnvironmentsFields.java
new file mode 100644
index 00000000..4e4fc8d2
--- /dev/null
+++ b/src/GlobalData/CompilerEnvironment/UI/CompilerEnvironmentsFields.java
@@ -0,0 +1,12 @@
+package GlobalData.CompilerEnvironment.UI;
+import Common.UI.Windows.Dialog.DialogFields;
+
+import javax.swing.*;
+import java.awt.*;
+public class CompilerEnvironmentsFields implements DialogFields {
+ private JPanel content;
+ @Override
+ public Component getContent() {
+ return content;
+ }
+}
diff --git a/src/GlobalData/CompilerOption/CompilerOption.java b/src/GlobalData/CompilerOption/CompilerOption.java
new file mode 100644
index 00000000..0a5bd152
--- /dev/null
+++ b/src/GlobalData/CompilerOption/CompilerOption.java
@@ -0,0 +1,48 @@
+package GlobalData.CompilerOption;
+import Common.Database.DBObject;
+import Common.Utils.Utils;
+import com.sun.org.glassfish.gmbal.Description;
+
+import java.util.Arrays;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+public class CompilerOption extends DBObject {
+ @Description("PRIMARY KEY, UNIQUE")
+ public String name = "";
+ public String parameterSeparator = "";
+ public String parameterName = "";
+ public String parameterValue = "";
+ public Vector parameterVariants = new Vector<>();
+ public Vector description = new Vector<>();
+ //--------------------------------------
+ public boolean hasParameter() {
+ return !parameterName.isEmpty();
+ }
+ @Override
+ public Object getPK() {
+ return name;
+ }
+ @Override
+ public String toString() {
+ return name + (hasParameter() ? (parameterSeparator +
+ (parameterValue.contains(" ") ? Utils.DQuotes(parameterValue) : parameterValue)) : "");
+ }
+ public void CheckParameterVariants() {
+ for (String line : description)
+ if (CheckLine(line)) break;
+ }
+ public boolean CheckLine(String line) {
+ if (hasParameter()) {
+ Pattern DVM_PARAM_VALUES_REGEX = Pattern.compile(Utils.TBrackets(parameterName) + "\\s*=\\s*" + "\\w+(\\|\\w+)+", Pattern.CASE_INSENSITIVE);
+ Matcher matcher = DVM_PARAM_VALUES_REGEX.matcher(line);
+ if (matcher.find()) {
+ String s = line.substring(matcher.start(), matcher.end());
+ String packed = s.substring(s.lastIndexOf('=') + 1).trim();
+ parameterVariants = new Vector<>(Arrays.asList(packed.split("\\|")));
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/GlobalData/CompilerOption/CompilerOptionsSet.java b/src/GlobalData/CompilerOption/CompilerOptionsSet.java
new file mode 100644
index 00000000..2af9b08e
--- /dev/null
+++ b/src/GlobalData/CompilerOption/CompilerOptionsSet.java
@@ -0,0 +1,47 @@
+package GlobalData.CompilerOption;
+import Common.Database.DataSet;
+import Common.UI.DataSetControlForm;
+import Common.UI.Tables.TableEditors;
+import Common.UI.Tables.TableRenderers;
+
+import static Common.UI.Tables.TableRenderers.RendererMultiline;
+public class CompilerOptionsSet extends DataSet {
+ public CompilerOptionsSet() {
+ super(String.class, CompilerOption.class);
+ }
+ @Override
+ public String[] getUIColumnNames() {
+ return new String[]{
+ "Параметр", "Значение", "Описание"
+ };
+ }
+ @Override
+ public Object getFieldAt(CompilerOption object, int columnIndex) {
+ switch (columnIndex) {
+ case 2:
+ return object.parameterName + object.parameterSeparator;
+ case 3:
+ return object.parameterValue;
+ case 4:
+ return object.description;
+ default:
+ return null;
+ }
+ }
+ @Override
+ protected DataSetControlForm createUI() {
+ return new DataSetControlForm(this) {
+ @Override
+ public boolean hasCheckBox() {
+ return true;
+ }
+ @Override
+ protected void AdditionalInitColumns() {
+ columns.get(2).setRenderer(TableRenderers.RendererCompilerOptionParameterName);
+ columns.get(3).setRenderer(TableRenderers.RendererCompilerOptionParameterValue);
+ columns.get(3).setEditor(TableEditors.EditorCompilerOptionParameterValue);
+ columns.get(4).setRenderer(RendererMultiline);
+ }
+ };
+ }
+}
diff --git a/src/GlobalData/CompilerOption/UI/CompilerOptionParameterNameRenderer.java b/src/GlobalData/CompilerOption/UI/CompilerOptionParameterNameRenderer.java
new file mode 100644
index 00000000..541f8394
--- /dev/null
+++ b/src/GlobalData/CompilerOption/UI/CompilerOptionParameterNameRenderer.java
@@ -0,0 +1,20 @@
+package GlobalData.CompilerOption.UI;
+import Common.Current;
+import Common.UI.Tables.DBObjectRenderer;
+import Common.UI.Themes.VisualiserFonts;
+import GlobalData.CompilerOption.CompilerOption;
+public class CompilerOptionParameterNameRenderer extends DBObjectRenderer {
+ @Override
+ public void Display() {
+ if (value != null) {
+ CompilerOption option = (CompilerOption) value;
+ if (option.hasParameter()) {
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreePlain));
+ setText(option.parameterName);
+ } else {
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.UnknownState));
+ setText("нет");
+ }
+ }
+ }
+}
diff --git a/src/GlobalData/CompilerOption/UI/CompilerOptionParameterValueEditor.java b/src/GlobalData/CompilerOption/UI/CompilerOptionParameterValueEditor.java
new file mode 100644
index 00000000..e118301e
--- /dev/null
+++ b/src/GlobalData/CompilerOption/UI/CompilerOptionParameterValueEditor.java
@@ -0,0 +1,34 @@
+package GlobalData.CompilerOption.UI;
+import Common.Current;
+import Common.UI.Tables.DBObjectEditor;
+import Common.UI.Themes.VisualiserFonts;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.Text.ComboTextDialog;
+import GlobalData.CompilerOption.CompilerOption;
+public class CompilerOptionParameterValueEditor extends DBObjectEditor {
+ @Override
+ public void Action() {
+ if (value.hasParameter()) {
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Hyperlink));
+ //-
+ setText(value.parameterValue.isEmpty() ? "не задано" : value.parameterValue);
+ //-
+ ComboTextDialog dialog = new ComboTextDialog();
+ if (!value.parameterValue.isEmpty())
+ UI.TrySelect(dialog.fields, value.parameterValue);
+ dialog.fields.setEditable(value.parameterVariants.isEmpty());
+ if (dialog.ShowDialog("Изменить значение опции " + value.name,
+ value.parameterVariants)) {
+ value.parameterValue = dialog.Result;
+ setText(value.parameterValue.isEmpty() ? "не задано" : value.parameterValue);
+ }
+ } else {
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.UnknownState));
+ setText("нет");
+ }
+ }
+ @Override
+ public Object getCellEditorValue() {
+ return value.parameterValue;
+ }
+}
diff --git a/src/GlobalData/CompilerOption/UI/CompilerOptionParameterValueRenderer.java b/src/GlobalData/CompilerOption/UI/CompilerOptionParameterValueRenderer.java
new file mode 100644
index 00000000..9fc2fcb0
--- /dev/null
+++ b/src/GlobalData/CompilerOption/UI/CompilerOptionParameterValueRenderer.java
@@ -0,0 +1,20 @@
+package GlobalData.CompilerOption.UI;
+import Common.Current;
+import Common.UI.Tables.DBObjectRenderer;
+import Common.UI.Themes.VisualiserFonts;
+import GlobalData.CompilerOption.CompilerOption;
+public class CompilerOptionParameterValueRenderer extends DBObjectRenderer {
+ @Override
+ public void Display() {
+ if (value != null) {
+ CompilerOption option = (CompilerOption) value;
+ if (option.hasParameter()) {
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.Hyperlink));
+ setText(option.parameterValue.isEmpty() ? "не задано" : option.parameterValue);
+ } else {
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.UnknownState));
+ setText("нет");
+ }
+ }
+ }
+}
diff --git a/src/GlobalData/CompilerOption/UI/CompilerOptionsFields.form b/src/GlobalData/CompilerOption/UI/CompilerOptionsFields.form
new file mode 100644
index 00000000..51bec3b4
--- /dev/null
+++ b/src/GlobalData/CompilerOption/UI/CompilerOptionsFields.form
@@ -0,0 +1,11 @@
+
+
diff --git a/src/GlobalData/CompilerOption/UI/CompilerOptionsFields.java b/src/GlobalData/CompilerOption/UI/CompilerOptionsFields.java
new file mode 100644
index 00000000..80e6612b
--- /dev/null
+++ b/src/GlobalData/CompilerOption/UI/CompilerOptionsFields.java
@@ -0,0 +1,12 @@
+package GlobalData.CompilerOption.UI;
+import Common.UI.Windows.Dialog.DialogFields;
+
+import javax.swing.*;
+import java.awt.*;
+public class CompilerOptionsFields implements DialogFields {
+ private JPanel content;
+ @Override
+ public Component getContent() {
+ return content;
+ }
+}
diff --git a/src/GlobalData/Credentials/Credentials.java b/src/GlobalData/Credentials/Credentials.java
new file mode 100644
index 00000000..795ccc8e
--- /dev/null
+++ b/src/GlobalData/Credentials/Credentials.java
@@ -0,0 +1,18 @@
+package GlobalData.Credentials;
+import Common.Database.iDBObject;
+import Common.Utils.Utils;
+import com.sun.org.glassfish.gmbal.Description;
+public class Credentials extends iDBObject {
+ @Description("DEFAULT -1")
+ public int machine_id = Utils.Nan;
+ @Description("DEFAULT -1")
+ public int user_id = Utils.Nan;
+ @Description("DEFAULT -1")
+ public int compiler_id = Utils.Nan;
+ @Description("DEFAULT -1")
+ public int makefile_id = Utils.Nan;
+ @Description("DEFAULT -1")
+ public int runconfiguration_id = Utils.Nan;
+ @Description("DEFAULT -1")
+ public int remotesapfor_id = Utils.Nan;
+}
diff --git a/src/GlobalData/Credentials/CredentialsDBTable.java b/src/GlobalData/Credentials/CredentialsDBTable.java
new file mode 100644
index 00000000..2297cc58
--- /dev/null
+++ b/src/GlobalData/Credentials/CredentialsDBTable.java
@@ -0,0 +1,7 @@
+package GlobalData.Credentials;
+import Common.Database.iDBTable;
+public class CredentialsDBTable extends iDBTable {
+ public CredentialsDBTable() {
+ super(Credentials.class);
+ }
+}
diff --git a/src/GlobalData/DBLastProject/DBLastProject.java b/src/GlobalData/DBLastProject/DBLastProject.java
new file mode 100644
index 00000000..14a9b694
--- /dev/null
+++ b/src/GlobalData/DBLastProject/DBLastProject.java
@@ -0,0 +1,24 @@
+package GlobalData.DBLastProject;
+import Common.Database.DBObject;
+import ProjectData.Project.db_project_info;
+import com.sun.org.glassfish.gmbal.Description;
+
+import java.util.Date;
+public class DBLastProject extends DBObject {
+ @Description("PRIMARY KEY, UNIQUE")
+ public String HomePath = "";
+ public long lastOpened = 0;
+ public DBLastProject() {
+ }
+ public DBLastProject(db_project_info project) {
+ HomePath = project.Home.getAbsolutePath();
+ RefreshOpenTime();
+ }
+ public void RefreshOpenTime() {
+ lastOpened = new Date().toInstant().getEpochSecond();
+ }
+ @Override
+ public Object getPK() {
+ return HomePath;
+ }
+}
\ No newline at end of file
diff --git a/src/GlobalData/DBLastProject/LastProjectsDBTable.java b/src/GlobalData/DBLastProject/LastProjectsDBTable.java
new file mode 100644
index 00000000..229984e0
--- /dev/null
+++ b/src/GlobalData/DBLastProject/LastProjectsDBTable.java
@@ -0,0 +1,22 @@
+package GlobalData.DBLastProject;
+import Common.Database.DBTable;
+
+import java.util.Comparator;
+import java.util.Vector;
+class SortByDate implements Comparator {
+ public int compare(DBLastProject p1, DBLastProject p2) {
+ return (int) (p2.lastOpened - p1.lastOpened);
+ }
+}
+public class LastProjectsDBTable extends DBTable {
+ public LastProjectsDBTable() {
+ super(String.class, DBLastProject.class);
+ }
+ public Vector getOrdered() {
+ return getOrderedRecords(new SortByDate());
+ }
+ @Override
+ public String getSingleDescription() {
+ return "путь к проекту";
+ }
+}
diff --git a/src/GlobalData/DVMParameter/DVMParameter.java b/src/GlobalData/DVMParameter/DVMParameter.java
new file mode 100644
index 00000000..08103163
--- /dev/null
+++ b/src/GlobalData/DVMParameter/DVMParameter.java
@@ -0,0 +1,8 @@
+package GlobalData.DVMParameter;
+import GlobalData.EnvironmentValue.EnvironmentValue;
+public class DVMParameter extends EnvironmentValue {
+ @Override
+ public String toString() {
+ return name + "=" + value + ";";
+ }
+}
diff --git a/src/GlobalData/DVMParameter/DVMParameterDBTable.java b/src/GlobalData/DVMParameter/DVMParameterDBTable.java
new file mode 100644
index 00000000..a34599db
--- /dev/null
+++ b/src/GlobalData/DVMParameter/DVMParameterDBTable.java
@@ -0,0 +1,98 @@
+package GlobalData.DVMParameter;
+import Common.Current;
+import Common.Database.iDBTable;
+import Common.Global;
+import Common.UI.DataSetControlForm;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.DBObjectDialog;
+import Common.Utils.Utils;
+import GlobalData.DVMParameter.UI.DVMParameterFields;
+public class DVMParameterDBTable extends iDBTable {
+ public DVMParameterDBTable() {
+ super(DVMParameter.class);
+ }
+ @Override
+ public String getSingleDescription() {
+ return "параметр DVM системы";
+ }
+ @Override
+ public String getPluralDescription() {
+ return "параметры DVM";
+ }
+ @Override
+ public String[] getUIColumnNames() {
+ return new String[]{"имя", "значение"};
+ }
+ @Override
+ public Object getFieldAt(DVMParameter object, int columnIndex) {
+ switch (columnIndex) {
+ case 1:
+ return object.name;
+ case 2:
+ return object.value;
+ }
+ return null;
+ }
+ @Override
+ public Current CurrentName() {
+ return Current.DVMParameterValue;
+ }
+ @Override
+ protected DataSetControlForm createUI() {
+ return new DataSetControlForm(this){
+ @Override
+ protected void AdditionalInitColumns() {
+ columns.get(0).setVisible(false);
+ }
+
+ };
+ }
+ @Override
+ public DBObjectDialog getDialog() {
+ return new DBObjectDialog(DVMParameterFields.class) {
+ @Override
+ public void fillFields() {
+ UI.TrySelect(fields.cbName, Result.name);
+ fields.tfValue.setText(Result.value);
+ }
+ //https://javarush.ru/groups/posts/regulyarnye-vyrazheniya-v-java
+ @Override
+ public void validateFields() {
+ String name = (String) fields.cbName.getSelectedItem();
+ String value = fields.tfValue.getText();
+ if (name.isEmpty())
+ Log.Writeln("Имя параметра DVM системы не может быть пустым.");
+ /*
+ if (!name.matches("\\w*")) {
+ Log.Writeln("Имя переменной окружения может содержать только латинские буквы, цифры и подчёркивания");
+ }
+ */
+ if (Utils.isLinuxSystemCommand(name))
+ Log.Writeln(Utils.DQuotes(name) + " является системной командой Linux,\nи не может быть задано в качестве имени переменной окружения.");
+
+ /*
+ if (value.contains("\"")) {
+ Log.Writeln("Значение переменной окружения не может содержать двойные кавычки");
+ }
+ */
+ for (DVMParameter par : Global.db.dvmParameters.Data.values()) {
+ if (par.isVisible() && (Result.id != par.id) && (par.name.equals(name))) {
+ Log.Writeln("В конфигурации запуска уже задан параметр DVM системы с именем " + Utils.Brackets(name));
+ break;
+ }
+ }
+ }
+ @Override
+ public void ProcessResult() {
+ Result.machine_id = Current.getMachine().id;
+ Result.run_configuration_id = Current.getRunConfiguration().id;
+ Result.name = (String) fields.cbName.getSelectedItem();
+ Result.value = fields.tfValue.getText();
+ }
+ @Override
+ public int getDefaultHeight() {
+ return 200;
+ }
+ };
+ }
+}
diff --git a/src/GlobalData/DVMParameter/UI/DVMParameterFields.form b/src/GlobalData/DVMParameter/UI/DVMParameterFields.form
new file mode 100644
index 00000000..764588ba
--- /dev/null
+++ b/src/GlobalData/DVMParameter/UI/DVMParameterFields.form
@@ -0,0 +1,58 @@
+
+
diff --git a/src/GlobalData/DVMParameter/UI/DVMParameterFields.java b/src/GlobalData/DVMParameter/UI/DVMParameterFields.java
new file mode 100644
index 00000000..7428ac87
--- /dev/null
+++ b/src/GlobalData/DVMParameter/UI/DVMParameterFields.java
@@ -0,0 +1,21 @@
+package GlobalData.DVMParameter.UI;
+import Common.UI.ComboBox.StyledTextComboBox;
+import Common.UI.TextField.StyledTextField;
+import Common.UI.Windows.Dialog.DialogFields;
+
+import javax.swing.*;
+import java.awt.*;
+public class DVMParameterFields implements DialogFields {
+ public JTextField tfValue;
+ public JComboBox cbName;
+ private JPanel content;
+ @Override
+ public Component getContent() {
+ return content;
+ }
+ private void createUIComponents() {
+ // TODO: place custom component creation code here
+ cbName = new StyledTextComboBox();
+ tfValue = new StyledTextField();
+ }
+}
diff --git a/src/GlobalData/EnvironmentValue/EnvironmentValue.java b/src/GlobalData/EnvironmentValue/EnvironmentValue.java
new file mode 100644
index 00000000..80208dda
--- /dev/null
+++ b/src/GlobalData/EnvironmentValue/EnvironmentValue.java
@@ -0,0 +1,18 @@
+package GlobalData.EnvironmentValue;
+import Common.Current;
+import Common.Database.iDBObject;
+import Common.Utils.Utils;
+public class EnvironmentValue extends iDBObject {
+ public String name = "";
+ public String value = "";
+ public int machine_id = Utils.Nan; //для удаления машин
+ public int run_configuration_id = Utils.Nan;
+ @Override
+ public boolean isVisible() {
+ return Current.HasRunConfiguration() && (run_configuration_id == Current.getRunConfiguration().id);
+ }
+ @Override
+ public String toString() {
+ return name + "=" + Utils.DQuotes(value);
+ }
+}
diff --git a/src/GlobalData/EnvironmentValue/EnvironmentValuesDBTable.java b/src/GlobalData/EnvironmentValue/EnvironmentValuesDBTable.java
new file mode 100644
index 00000000..5cf4391b
--- /dev/null
+++ b/src/GlobalData/EnvironmentValue/EnvironmentValuesDBTable.java
@@ -0,0 +1,98 @@
+package GlobalData.EnvironmentValue;
+import Common.Current;
+import Common.Database.iDBTable;
+import Common.Global;
+import Common.UI.DataSetControlForm;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.DBObjectDialog;
+import Common.Utils.Utils;
+import GlobalData.EnvironmentValue.UI.EnvironmentValueFields;
+public class EnvironmentValuesDBTable extends iDBTable {
+ public EnvironmentValuesDBTable() {
+ super(EnvironmentValue.class);
+ }
+ @Override
+ public String getSingleDescription() {
+ return "переменная окружения";
+ }
+ @Override
+ public String getPluralDescription() {
+ return "переменные окружения";
+ }
+ @Override
+ public DBObjectDialog getDialog() {
+ return new DBObjectDialog(EnvironmentValueFields.class) {
+ @Override
+ public void fillFields() {
+ UI.TrySelect(fields.cbName, Result.name);
+ fields.tfValue.setText(Result.value);
+ }
+ //https://javarush.ru/groups/posts/regulyarnye-vyrazheniya-v-java
+ @Override
+ public void validateFields() {
+ String name = (String) fields.cbName.getSelectedItem();
+ String value = fields.tfValue.getText();
+ if (name.isEmpty())
+ Log.Writeln("Имя переменной окружения не может быть пустым.");
+ if (!name.matches("\\w*")) {
+ Log.Writeln("Имя переменной окружения может содержать только латинские буквы, цифры и подчёркивания");
+ }
+ if (Utils.isLinuxSystemCommand(name))
+ Log.Writeln(Utils.DQuotes(name) + " является системной командой Linux,\nи не может быть задано в качестве имени переменной окружения.");
+ if (value.contains("\"")) {
+ Log.Writeln("Значение переменной окружения не может содержать двойные кавычки");
+ }
+ for (EnvironmentValue env : Global.db.environmentValues.Data.values()) {
+ if (env.isVisible() && (Result.id != env.id) && (env.name.equals(name))) {
+ Log.Writeln("В конфигурации запуска уже задана переменная окружения с именем " + Utils.Brackets(name));
+ break;
+ }
+ }
+ }
+ @Override
+ public void ProcessResult() {
+ Result.machine_id = Current.getMachine().id;
+ Result.run_configuration_id = Current.getRunConfiguration().id;
+ Result.name = (String) fields.cbName.getSelectedItem();
+ Result.value = fields.tfValue.getText();
+ }
+ @Override
+ public int getDefaultHeight() {
+ return 200;
+ }
+ };
+ }
+ @Override
+ protected DataSetControlForm createUI() {
+ return new DataSetControlForm(this){
+ @Override
+ protected void AdditionalInitColumns() {
+ columns.get(0).setVisible(false);
+ }
+
+ };
+ }
+ @Override
+ public String[] getUIColumnNames() {
+ return new String[]{"имя", "значение"};
+ }
+ @Override
+ public Object getFieldAt(EnvironmentValue object, int columnIndex) {
+ switch (columnIndex) {
+ case 1:
+ return object.name;
+ case 2:
+ return object.value;
+ }
+ return null;
+ }
+ @Override
+ public Current CurrentName() {
+ return Current.EnvironmentValue;
+ }
+ public EnvironmentValue getEnvByName(String name_in) {
+ for (EnvironmentValue environmentValue : Data.values())
+ if (environmentValue.name.equalsIgnoreCase(name_in)) return environmentValue;
+ return null;
+ }
+}
diff --git a/src/GlobalData/EnvironmentValue/UI/EnvironmentValueFields.form b/src/GlobalData/EnvironmentValue/UI/EnvironmentValueFields.form
new file mode 100644
index 00000000..eafc8850
--- /dev/null
+++ b/src/GlobalData/EnvironmentValue/UI/EnvironmentValueFields.form
@@ -0,0 +1,55 @@
+
+
diff --git a/src/GlobalData/EnvironmentValue/UI/EnvironmentValueFields.java b/src/GlobalData/EnvironmentValue/UI/EnvironmentValueFields.java
new file mode 100644
index 00000000..6b39cb8c
--- /dev/null
+++ b/src/GlobalData/EnvironmentValue/UI/EnvironmentValueFields.java
@@ -0,0 +1,22 @@
+package GlobalData.EnvironmentValue.UI;
+import Common.UI.TextField.StyledTextField;
+import Common.UI.Windows.Dialog.DialogFields;
+
+import javax.swing.*;
+import java.awt.*;
+public class EnvironmentValueFields implements DialogFields {
+ public JPanel content;
+ public JComboBox cbName;
+ public JTextField tfValue;
+ public EnvironmentValueFields() {
+ cbName.addItem("");
+ }
+ @Override
+ public Component getContent() {
+ return content;
+ }
+ private void createUIComponents() {
+ // TODO: place custom component creation code here
+ tfValue = new StyledTextField();
+ }
+}
diff --git a/src/GlobalData/FormsParams/DBForm.java b/src/GlobalData/FormsParams/DBForm.java
new file mode 100644
index 00000000..3f53ea80
--- /dev/null
+++ b/src/GlobalData/FormsParams/DBForm.java
@@ -0,0 +1,34 @@
+package GlobalData.FormsParams;
+import Common.Database.DBObject;
+import Common.UI.Windows.FormType;
+import com.sun.org.glassfish.gmbal.Description;
+
+import java.awt.*;
+public class DBForm extends DBObject {
+ @Description("PRIMARY KEY,UNIQUE, NOT NULL")
+ public FormType type = FormType.Undefined;
+ public int X = 0;
+ public int Y = 0;
+ public int Width = 0;
+ public int Height = 0;
+ public DBForm(FormType type_, Window window) {
+ type = type_;
+ Init(window);
+ }
+ public DBForm() {
+ }
+ public void Init(Window window) {
+ X = window.getX();
+ Y = window.getY();
+ Width = window.getWidth();
+ Height = window.getHeight();
+ }
+ public void Apply(Window window) {
+ window.setSize(Width, Height);
+ window.setLocation(X, Y);
+ }
+ @Override
+ public Object getPK() {
+ return type;
+ }
+}
diff --git a/src/GlobalData/FormsParams/DBMainFormParams.java b/src/GlobalData/FormsParams/DBMainFormParams.java
new file mode 100644
index 00000000..81d76af3
--- /dev/null
+++ b/src/GlobalData/FormsParams/DBMainFormParams.java
@@ -0,0 +1,53 @@
+package GlobalData.FormsParams;
+import Common.Database.DBObject;
+import com.sun.org.glassfish.gmbal.Description;
+public class DBMainFormParams extends DBObject {
+ //todo вместо этого кошмара сделать объект DBSC для сплит контейнера,
+ // и включить туда все палки в проекте, а не только в главном окне.
+ @Description("PRIMARY KEY,UNIQUE, NOT NULL")
+ public int id;
+ public int SC1 = -1;
+ public int SC2 = -1;
+ public int SC3 = -1;
+ public int SC4 = -1;
+ public int SC5 = -1;
+ public int SC6 = -1;
+ public int SC7 = -1;
+ public int SC8 = -1;
+ public int SC9 = -1;
+ public int SC10 = -1;
+ public int SC11 = -1;
+ public DBMainFormParams() {
+ }
+ public DBMainFormParams(int SC1_, int SC2_, int SC3_, int SC4_, int SC5_, int SC6_, int SC7_, int SC8_, int SC9_, int SC10_, int SC11_) {
+ id = 0;
+ SC1 = SC1_;
+ SC2 = SC2_;
+ SC3 = SC3_;
+ SC4 = SC4_;
+ SC5 = SC5_;
+ SC6 = SC6_;
+ SC7 = SC7_;
+ SC8 = SC8_;
+ SC9 = SC9_;
+ SC10 = SC10_;
+ SC11 = SC11_;
+ }
+ public void Validate() {
+ if (SC1 == 0) SC1 = -1;
+ if (SC2 == 0) SC2 = -1;
+ if (SC3 == 0) SC3 = -1;
+ if (SC4 == 0) SC4 = -1;
+ if (SC5 == 0) SC5 = -1;
+ if (SC6 == 0) SC6 = -1;
+ if (SC7 == 0) SC7 = -1;
+ if (SC8 == 0) SC8 = -1;
+ if (SC9 == 0) SC9 = -1;
+ if (SC10 == 0) SC10 = -1;
+ if (SC11 == 0) SC11 = -1;
+ }
+ @Override
+ public Object getPK() {
+ return id;
+ }
+}
diff --git a/src/GlobalData/FormsParams/FormsDBTable.java b/src/GlobalData/FormsParams/FormsDBTable.java
new file mode 100644
index 00000000..f35089b9
--- /dev/null
+++ b/src/GlobalData/FormsParams/FormsDBTable.java
@@ -0,0 +1,12 @@
+package GlobalData.FormsParams;
+import Common.Database.DBTable;
+import Common.UI.Windows.FormType;
+public class FormsDBTable extends DBTable {
+ public FormsDBTable() {
+ super(FormType.class, DBForm.class);
+ }
+ @Override
+ public String getSingleDescription() {
+ return "параметры окны";
+ }
+}
diff --git a/src/GlobalData/FormsParams/MainFormParamsDBTable.java b/src/GlobalData/FormsParams/MainFormParamsDBTable.java
new file mode 100644
index 00000000..fffe4919
--- /dev/null
+++ b/src/GlobalData/FormsParams/MainFormParamsDBTable.java
@@ -0,0 +1,11 @@
+package GlobalData.FormsParams;
+import Common.Database.DBTable;
+public class MainFormParamsDBTable extends DBTable {
+ public MainFormParamsDBTable() {
+ super(Integer.class, DBMainFormParams.class);
+ }
+ @Override
+ public String getSingleDescription() {
+ return "параметры главного окна";
+ }
+}
diff --git a/src/GlobalData/GlobalDatabase.java b/src/GlobalData/GlobalDatabase.java
new file mode 100644
index 00000000..f1c104be
--- /dev/null
+++ b/src/GlobalData/GlobalDatabase.java
@@ -0,0 +1,324 @@
+package GlobalData;
+import Common.Current;
+import Common.Database.DBObject;
+import Common.Database.DataSet;
+import Common.Database.SQLITE.SQLiteDatabase;
+import Common.Global;
+import Common.UI.DataSetControlForm;
+import GlobalData.Account.Account;
+import GlobalData.Account.AccountsDBTable;
+import GlobalData.Compiler.CompilersDBTable;
+import GlobalData.Credentials.Credentials;
+import GlobalData.Credentials.CredentialsDBTable;
+import GlobalData.DBLastProject.LastProjectsDBTable;
+import GlobalData.DVMParameter.DVMParameterDBTable;
+import GlobalData.EnvironmentValue.EnvironmentValuesDBTable;
+import GlobalData.FormsParams.FormsDBTable;
+import GlobalData.FormsParams.MainFormParamsDBTable;
+import GlobalData.Grid.GridsDBTable;
+import GlobalData.Machine.MachinesDBTable;
+import GlobalData.Makefile.MakefilesDBTable;
+import GlobalData.Module.ModulesDBTable;
+import GlobalData.RemoteSapfor.RemoteSapforsDBTable;
+import GlobalData.RunConfiguration.RunConfigurationsDBTable;
+import GlobalData.SapforProfile.SapforProfile;
+import GlobalData.SapforProfile.SapforProfilesDBTable;
+import GlobalData.SapforProfileSetting.SapforProfileSetting;
+import GlobalData.SapforProfileSetting.SapforProfileSettingsDBTable;
+import GlobalData.Settings.DBSetting;
+import GlobalData.Settings.SettingName;
+import GlobalData.Settings.SettingsDBTable;
+import GlobalData.Splitter.SplittersDBTable;
+import GlobalData.Tasks.CompilationTask.CompilationTasksDBTable;
+import GlobalData.Tasks.RunTask.RunTasksDBTable;
+import GlobalData.User.UsersDBTable;
+import Repository.Component.ComponentType;
+import TestingSystem.Sapfor.SapforTask.SapforTaskResult;
+import TestingSystem.Sapfor.SapforTask.SapforTask_2023;
+import TestingSystem.Sapfor.SapforTask.SapforTasksDBTable;
+import TestingSystem.Sapfor.SapforTasksPackage.SapforTasksPackage_2023;
+import TestingSystem.Sapfor.SapforTasksPackage.SapforTasksPackagesDBTable;
+import TestingSystem.TaskKey.TaskKeysDBTable;
+import Visual_DVM_2021.PassStats.PassStatsDBTable;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+
+import java.nio.file.Paths;
+import java.util.Date;
+import java.util.LinkedHashMap;
+
+import static Common.UI.Tables.TableRenderers.RendererStatusEnum;
+public class GlobalDatabase extends SQLiteDatabase {
+ //---------СЕАНС----------------------------------------------
+ public MachinesDBTable machines;
+ public UsersDBTable users;
+ public CompilersDBTable compilers;
+ public RemoteSapforsDBTable remoteSapfors;
+ public MakefilesDBTable makefiles;
+ public ModulesDBTable modules;
+ public CompilationTasksDBTable compilationTasks;
+ public RunTasksDBTable runTasks;
+ public RunConfigurationsDBTable runConfigurations;
+ public EnvironmentValuesDBTable environmentValues;
+ public DVMParameterDBTable dvmParameters;
+ public CredentialsDBTable credentials;
+ //----- ДАННЫЕ ВИЗУАЛИЗАТОРА---------------------------------
+ public FormsDBTable forms;
+ public MainFormParamsDBTable mainFormParams;
+ public SettingsDBTable settings;
+ public LastProjectsDBTable lastProjects;
+ public AccountsDBTable accounts;
+ public PassStatsDBTable passStats;
+ public SplittersDBTable splitters;
+ public GridsDBTable grids;
+ //-
+ public TaskKeysDBTable tasksKeys;
+ //---------
+ public SapforTasksPackagesDBTable sapforTasksPackages;
+ public SapforTasksDBTable sapforTasks = null;
+ public SapforProfilesDBTable sapforProfiles = null;
+ //---------
+ public SapforProfileSettingsDBTable sapforProfilesSettings = null;
+ //-
+ public GlobalDatabase() {
+ super(Paths.get(System.getProperty("user.dir"), "Data", Global.properties.GlobalDBName).toFile());
+ }
+ @Override
+ protected void initAllTables() throws Exception {
+ addTable(machines = new MachinesDBTable());
+ addTable(users = new UsersDBTable());
+ addTable(compilers = new CompilersDBTable());
+ addTable(remoteSapfors = new RemoteSapforsDBTable());
+ addTable(makefiles = new MakefilesDBTable());
+ addTable(modules = new ModulesDBTable());
+ addTable(compilationTasks = new CompilationTasksDBTable());
+ addTable(runTasks = new RunTasksDBTable());
+ addTable(runConfigurations = new RunConfigurationsDBTable());
+ addTable(environmentValues = new EnvironmentValuesDBTable());
+ addTable(credentials = new CredentialsDBTable());
+ addTable(forms = new FormsDBTable());
+ addTable(settings = new SettingsDBTable());
+ addTable(mainFormParams = new MainFormParamsDBTable());
+ addTable(lastProjects = new LastProjectsDBTable());
+ addTable(accounts = new AccountsDBTable());
+ addTable(passStats = new PassStatsDBTable());
+ addTable(splitters = new SplittersDBTable());
+ addTable(dvmParameters = new DVMParameterDBTable());
+ addTable(grids = new GridsDBTable());
+ addTable(tasksKeys = new TaskKeysDBTable());
+ //--
+ addTable(sapforTasksPackages = new SapforTasksPackagesDBTable());
+ addTable(sapforTasks = new SapforTasksDBTable());
+ //--
+ addTable(sapforProfiles = new SapforProfilesDBTable());
+ addTable(sapforProfilesSettings = new SapforProfileSettingsDBTable());
+ }
+ //---------------------------------------------------------------------------------
+ @Override
+ public void Init() throws Exception {
+ Current.set(Current.Account,
+ accounts.Data.isEmpty() ? Insert(new Account()) :
+ accounts.getFirstRecord()
+ );
+ Current.set(Current.Credentials,
+ credentials.Data.isEmpty() ? Insert(new Credentials()) :
+ credentials.getFirstRecord());
+ //настройки компонент
+ settings.AddAll();
+ runConfigurations.Patch();
+ }
+ public void SaveCredentials() throws Exception {
+ Credentials credentials = (Credentials) Current.get(Current.Credentials);
+ if (Current.HasMachine())
+ credentials.machine_id = Current.getMachine().id;
+ if (Current.HasUser())
+ credentials.user_id = Current.getUser().id;
+ if (Current.HasCompiler())
+ credentials.compiler_id = Current.getCompiler().id;
+ if (Current.HasMakefile())
+ credentials.makefile_id = Current.getMakefile().id;
+ if (Current.HasRunConfiguration())
+ credentials.runconfiguration_id = Current.getRunConfiguration().id;
+ if (Current.HasRemoteSapfor())
+ credentials.remotesapfor_id = Current.getRemoteSapfor().id;
+ Update(credentials);
+ }
+ public void UpdateCredentials() {
+ try {
+ Global.db.Update((DBObject) Current.get(Current.Credentials));
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ }
+ public long IncSapforMaxTaskId() {
+ long res = Global.properties.SapforTaskMaxId;
+ Global.properties.SapforTaskMaxId++;
+ Global.properties.Update();
+ return res;
+ }
+ public LinkedHashMap getSapforPackageTasks(int package_id) throws Exception {
+ LinkedHashMap res = new LinkedHashMap<>();
+ for (SapforTask_2023 task : sapforTasks.Data.values()) {
+ if (task.sapfortaskspackage_2023_id == package_id) {
+ res.put(task.id, task);
+ }
+ }
+ return res;
+ }
+ public DataSet getSapforPackagesMasterDataSet(SapforTasksPackage_2023 package_in) throws Exception {
+ DataSet res = new DataSet(String.class, SapforTaskResult.class) {
+ @Override
+ protected DataSetControlForm createUI() {
+ return new DataSetControlForm(this) {
+ @Override
+ protected void AdditionalInitColumns() {
+ columns.get(1).setRenderer(RendererStatusEnum);
+ }
+ @Override
+ public void MouseAction2() throws Exception {
+ Pass_2021.passes.get(PassCode_2021.OpenSapforTest).Do(Current.SapforEtalonTaskResult);
+ }
+ @Override
+ public void ShowCurrentObject() throws Exception {
+ System.out.println(Current.get(Current.SapforEtalonTaskResult));
+ }
+ };
+ }
+ @Override
+ public String[] getUIColumnNames() {
+ return new String[]{
+ "Статус"
+ };
+ }
+ @Override
+ public Object getFieldAt(SapforTaskResult object, int columnIndex) {
+ switch (columnIndex) {
+ case 1:
+ return object.task.state;
+ default:
+ return null;
+ }
+ }
+ @Override
+ public Current CurrentName() {
+ return Current.SapforEtalonTaskResult;
+ }
+ };
+ for (SapforTask_2023 task : sapforTasks.Data.values())
+ if (task.sapfortaskspackage_2023_id == package_in.id)
+ res.put(task.test_description, new SapforTaskResult(package_in, task));
+ return res;
+ }
+ //--
+ public DataSet getSapforPackagesSlaveDataSet(SapforTasksPackage_2023 package_in) throws Exception {
+ DataSet res = new DataSet(String.class, SapforTaskResult.class) {
+ @Override
+ protected DataSetControlForm createUI() {
+ return new DataSetControlForm(this) {
+ @Override
+ protected void AdditionalInitColumns() {
+ columns.get(1).setRenderer(RendererStatusEnum);
+ columns.get(2).setRenderer(RendererStatusEnum);
+ }
+ @Override
+ public void MouseAction2() throws Exception {
+ Pass_2021.passes.get(PassCode_2021.OpenSapforTest).Do(Current.SapforTaskResult);
+ }
+ @Override
+ public void ShowCurrentObject() throws Exception {
+ System.out.println(Current.get(Current.SapforTaskResult));
+ }
+ };
+ }
+ @Override
+ public String[] getUIColumnNames() {
+ return new String[]{
+ "Статус",
+ "Совпадение"
+ };
+ }
+ @Override
+ public Object getFieldAt(SapforTaskResult object, int columnIndex) {
+ switch (columnIndex) {
+ case 1:
+ return object.task.state;
+ case 2:
+ return object.match_state;
+ default:
+ return null;
+ }
+ }
+ @Override
+ public Current CurrentName() {
+ return Current.SapforTaskResult;
+ }
+ };
+ for (SapforTask_2023 task : sapforTasks.Data.values())
+ if (task.sapfortaskspackage_2023_id == package_in.id)
+ res.put(task.test_description, new SapforTaskResult(package_in, task));
+ return res;
+ }
+ //--
+ public LinkedHashMap getSapforSettingsForProfile() {
+ LinkedHashMap res = new LinkedHashMap<>();
+ for (DBSetting setting : Global.db.settings.getSettingsByOwner(ComponentType.SapforOptions))
+ if (setting.Visible)
+ res.put(setting.Name, setting.Value);
+ return res;
+ }
+ //проверить, есть ли профиль с таким же набором настроек.
+ public SapforProfile checkProfileForCurrentSettings() {
+ LinkedHashMap current_values = getSapforSettingsForProfile();
+ for (SapforProfile profile : sapforProfiles.Data.values()) {
+ //--получить все настройки профиля
+ LinkedHashMap profileValues = new LinkedHashMap<>();
+ for (SapforProfileSetting setting : sapforProfilesSettings.Data.values())
+ if (setting.sapforprofile_id == profile.id) profileValues.put(setting.name, setting.value);
+ //--
+ if (current_values.equals(profileValues)) return profile;
+ }
+ return null;
+ }
+ public void insertProfileSettings(SapforProfile profile) throws Exception {
+ LinkedHashMap current_values = getSapforSettingsForProfile();
+ for (SettingName name : current_values.keySet()) {
+ //--
+ SapforProfileSetting sapforProfileSetting = new SapforProfileSetting();
+ sapforProfileSetting.name = name;
+ sapforProfileSetting.value = current_values.get(name);
+ sapforProfileSetting.sapforprofile_id = profile.id;
+ //--
+ Insert(sapforProfileSetting);
+ }
+ }
+ public void saveCurrentProfile(String name_in) throws Exception {
+ if (Global.db.checkProfileForCurrentSettings() == null) {
+ SapforProfile profile = new SapforProfile();
+ profile.description = name_in;
+ profile.creationDate = new Date().getTime();
+ Global.db.Insert(profile);
+ Global.db.insertProfileSettings(profile);
+ }
+ }
+ public void rewriteProfileByDescription(String description_in) throws Exception {
+ SapforProfile old = null;
+ //ищем профиль с именем бага
+ for (SapforProfile p : Global.db.sapforProfiles.Data.values())
+ if (p.description.equalsIgnoreCase(description_in)) {
+ old = p;
+ break;
+ }
+ if (old != null) {
+ //удалить профиль с именем бага,если есть, чтобы не множить кроликов.
+ //при условии что не видно окна профилей!!
+ Global.db.Delete(old);
+ Global.db.DeleteByFK(old, SapforProfileSetting.class);
+ }
+ //---
+ SapforProfile profile = new SapforProfile();
+ profile.description = description_in;
+ profile.creationDate = new Date().getTime();
+ Global.db.Insert(profile);
+ Global.db.insertProfileSettings(profile);
+ }
+}
diff --git a/src/GlobalData/Grid/Grid.java b/src/GlobalData/Grid/Grid.java
new file mode 100644
index 00000000..9ae9edf1
--- /dev/null
+++ b/src/GlobalData/Grid/Grid.java
@@ -0,0 +1,27 @@
+package GlobalData.Grid;
+import Common.Current;
+import Common.Database.DBObject;
+import com.sun.org.glassfish.gmbal.Description;
+
+import java.util.Arrays;
+import java.util.Vector;
+import java.util.stream.Collectors;
+public class Grid extends DBObject {
+ @Description("PRIMARY KEY, UNIQUE") //имя таблицы
+ public Current name = Current.Undefined;
+ @Description("DEFAULT ''")
+ public String sizes = ""; //ширины столбцов запакованные через |. вводить объекты ради них нецелесообразно.
+ public Grid() {
+ }
+ public Grid(Current name_in) {
+ name = name_in;
+ sizes = "";
+ }
+ @Override
+ public Object getPK() {
+ return name;
+ }
+ public Vector unpack() {
+ return Arrays.stream(sizes.split("\\|")).map(Integer::parseInt).collect(Collectors.toCollection(Vector::new));
+ }
+}
diff --git a/src/GlobalData/Grid/GridsDBTable.java b/src/GlobalData/Grid/GridsDBTable.java
new file mode 100644
index 00000000..66cedcab
--- /dev/null
+++ b/src/GlobalData/Grid/GridsDBTable.java
@@ -0,0 +1,8 @@
+package GlobalData.Grid;
+import Common.Current;
+import Common.Database.DBTable;
+public class GridsDBTable extends DBTable {
+ public GridsDBTable() {
+ super(Current.class, Grid.class);
+ }
+}
diff --git a/src/GlobalData/Machine/Machine.java b/src/GlobalData/Machine/Machine.java
new file mode 100644
index 00000000..6e3de62c
--- /dev/null
+++ b/src/GlobalData/Machine/Machine.java
@@ -0,0 +1,66 @@
+package GlobalData.Machine;
+import Common.Database.iDBObject;
+import Common.Global;
+import Common.Utils.Utils;
+import GlobalData.Compiler.Compiler;
+import GlobalData.User.User;
+import Visual_DVM_2021.Passes.SSH.ConnectionPass;
+
+import java.util.LinkedHashMap;
+public class Machine extends iDBObject {
+ public MachineType type = MachineType.Server;
+ public String name = "";
+ public String address = "";
+ public int port = 22;
+ public Machine(String name_in, String address_in, int port_in, MachineType type_in) {
+ name = name_in;
+ address = address_in;
+ port = port_in;
+ type = type_in;
+ }
+ public Machine() {
+ }
+ public String getURL() {
+ return type.equals(MachineType.Local) ? name : (address + ":" + port);
+ }
+ public String getFullDescription() {
+ return this.equals(ConnectionPass.rep_machine) ? "Репозиторий визуализатора" : "Машина по адресу " + Utils.Brackets(getURL());
+ }
+ public LinkedHashMap getCompilers() {
+ return Global.db.getMapByFKi(this, Compiler.class);
+ }
+ public LinkedHashMap getUsers() {
+ return Global.db.getMapByFKi(this, User.class);
+ }
+ @Override
+ public String getDialogName() {
+ return super.getDialogName() + ":" + getURL();
+ }
+/* инициализация компиляторов по умолчанию. добавить в отдельный проход.
+ //todo если машина локальная и винда, их не добавлять.
+ Visualiser.db.Insert(new Compiler(
+ (Machine)Target,
+ "gfortran",
+ CompilerType.gnu,
+ "gfortran",
+ "--version",
+ "--help"
+ ));
+ Visualiser.db.Insert(new Compiler(
+ (Machine)Target,
+ "gcc",
+ CompilerType.gnu,
+ "gcc",
+ "--version",
+ "--help"
+ ));
+ Visualiser.db.Insert(new Compiler(
+ (Machine)Target,
+ "g++",
+ CompilerType.gnu,
+ "g++",
+ "--version",
+ "--help"
+ ));
+ */
+}
diff --git a/src/GlobalData/Machine/MachineType.java b/src/GlobalData/Machine/MachineType.java
new file mode 100644
index 00000000..de32fdea
--- /dev/null
+++ b/src/GlobalData/Machine/MachineType.java
@@ -0,0 +1,20 @@
+package GlobalData.Machine;
+public enum MachineType {
+ Undefined,
+ Server,
+ MVS_cluster,
+ Local;
+ public String getDescription() {
+ switch (this) {
+ case Undefined:
+ return "?";
+ case Server:
+ return "одиночный сервер";
+ case MVS_cluster:
+ return "MVS кластер";
+ case Local:
+ return "локальная";
+ }
+ return "";
+ }
+}
diff --git a/src/GlobalData/Machine/MachinesDBTable.java b/src/GlobalData/Machine/MachinesDBTable.java
new file mode 100644
index 00000000..4e75d3b6
--- /dev/null
+++ b/src/GlobalData/Machine/MachinesDBTable.java
@@ -0,0 +1,123 @@
+package GlobalData.Machine;
+import Common.Current;
+import Common.Database.*;
+import Common.UI.DataSetControlForm;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.DBObjectDialog;
+import GlobalData.Compiler.Compiler;
+import GlobalData.DVMParameter.DVMParameter;
+import GlobalData.EnvironmentValue.EnvironmentValue;
+import GlobalData.Machine.UI.MachineFields;
+import GlobalData.Makefile.Makefile;
+import GlobalData.Module.Module;
+import GlobalData.RemoteSapfor.RemoteSapfor;
+import GlobalData.RunConfiguration.RunConfiguration;
+import GlobalData.Tasks.CompilationTask.CompilationTask;
+import GlobalData.Tasks.RunTask.RunTask;
+import GlobalData.User.User;
+
+import java.util.LinkedHashMap;
+public class MachinesDBTable extends iDBTable {
+ public MachinesDBTable() {
+ super(Machine.class);
+ }
+ @Override
+ public String getSingleDescription() {
+ return "машина";
+ }
+ @Override
+ public String getPluralDescription() {
+ return "машины";
+ }
+ @Override
+ public DBObjectDialog getDialog() {
+ return new DBObjectDialog(MachineFields.class) {
+ @Override
+ public int getDefaultHeight() {
+ return 250;
+ }
+ @Override
+ public void validateFields() {
+ if (fields.tfAddress.getText().isEmpty())
+ Log.Writeln("Адрес машины не может быть пустым");
+ }
+ @Override
+ public void fillFields() {
+ fields.tfName.setText(Result.name);
+ fields.tfAddress.setText(Result.address);
+ fields.sPort.setValue(Result.port);
+ UI.TrySelect(fields.cbMachineType, Result.type);
+ }
+ @Override
+ public void ProcessResult() {
+ Result.name = fields.tfName.getText();
+ Result.address = fields.tfAddress.getText();
+ Result.port = (int) fields.sPort.getValue();
+ Result.type = (MachineType) fields.cbMachineType.getSelectedItem();
+ }
+ @Override
+ public void SetEditLimits() {
+ fields.cbMachineType.setEnabled(false);
+ }
+ };
+ }
+ @Override
+ public LinkedHashMap, FKBehaviour> getFKDependencies() {
+ LinkedHashMap, FKBehaviour> res = new LinkedHashMap<>();
+ //-
+ res.put(User.class, new FKBehaviour(FKDataBehaviour.DELETE, FKCurrentObjectBehaviuor.ACTIVE));
+ res.put(Compiler.class, new FKBehaviour(FKDataBehaviour.DELETE, FKCurrentObjectBehaviuor.ACTIVE));
+ res.put(RemoteSapfor.class, new FKBehaviour(FKDataBehaviour.DELETE, FKCurrentObjectBehaviuor.ACTIVE));
+ res.put(Makefile.class, new FKBehaviour(FKDataBehaviour.DELETE, FKCurrentObjectBehaviuor.ACTIVE));
+ res.put(RunConfiguration.class, new FKBehaviour(FKDataBehaviour.DELETE, FKCurrentObjectBehaviuor.ACTIVE));
+ //-
+ res.put(Module.class, new FKBehaviour(FKDataBehaviour.DELETE, FKCurrentObjectBehaviuor.PASSIVE));
+ res.put(EnvironmentValue.class, new FKBehaviour(FKDataBehaviour.DELETE, FKCurrentObjectBehaviuor.PASSIVE));
+ res.put(DVMParameter.class, new FKBehaviour(FKDataBehaviour.DELETE, FKCurrentObjectBehaviuor.PASSIVE));
+ res.put(CompilationTask.class, new FKBehaviour(FKDataBehaviour.DELETE, FKCurrentObjectBehaviuor.ACTIVE));
+ res.put(RunTask.class, new FKBehaviour(FKDataBehaviour.DELETE, FKCurrentObjectBehaviuor.PASSIVE));
+ return res;
+ }
+ @Override
+ protected DataSetControlForm createUI() {
+ return new DataSetControlForm(this) {
+ @Override
+ public void ShowCurrentObject() throws Exception {
+ super.ShowCurrentObject();
+ UI.getMainWindow().getTestingWindow().ShowCurrentMachine();
+ UI.getMainWindow().getTestingWindow().ShowCredentials();
+ }
+ @Override
+ public void ShowNoCurrentObject() throws Exception {
+ super.ShowNoCurrentObject();
+ UI.getMainWindow().getTestingWindow().ShowNoCurrentMachine();
+ UI.getMainWindow().getTestingWindow().ShowCredentials();
+ }
+ @Override
+ protected void AdditionalInitColumns() {
+ columns.get(0).setVisible(false);
+ }
+
+ };
+ }
+ @Override
+ public String[] getUIColumnNames() {
+ return new String[]{"URL"};
+ }
+ @Override
+ public Object getFieldAt(Machine object, int columnIndex) {
+ switch (columnIndex) {
+ case 1:
+ return object.getURL();
+ default:
+ return null;
+ }
+ }
+ @Override
+ public Current CurrentName() {
+ return Current.Machine;
+ }
+ public boolean LocalMachineExists() {
+ return Data.values().stream().anyMatch(machine -> machine.type.equals(MachineType.Local));
+ }
+}
diff --git a/src/GlobalData/Machine/UI/MachineFields.form b/src/GlobalData/Machine/UI/MachineFields.form
new file mode 100644
index 00000000..5740a240
--- /dev/null
+++ b/src/GlobalData/Machine/UI/MachineFields.form
@@ -0,0 +1,84 @@
+
+
diff --git a/src/GlobalData/Machine/UI/MachineFields.java b/src/GlobalData/Machine/UI/MachineFields.java
new file mode 100644
index 00000000..1064cec2
--- /dev/null
+++ b/src/GlobalData/Machine/UI/MachineFields.java
@@ -0,0 +1,43 @@
+package GlobalData.Machine.UI;
+import Common.UI.TextField.StyledTextField;
+import Common.UI.Windows.Dialog.DialogFields;
+import GlobalData.Machine.MachineType;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+public class MachineFields implements DialogFields {
+ private static final String localName = "этот компьютер";
+ public JTextField tfName;
+ public JTextField tfAddress;
+ public JSpinner sPort;
+ public JPanel content;
+ public JComboBox cbMachineType;
+ public MachineFields() {
+ sPort.setModel(new SpinnerNumberModel(22, 1, 65535, 1));
+ cbMachineType.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if ((cbMachineType.getSelectedItem() != null) && (cbMachineType.getSelectedItem().equals(MachineType.Local))) {
+ tfName.setText(localName);
+ tfAddress.setText(localName);
+ }
+ }
+ });
+ }
+ private void createUIComponents() {
+ // TODO: place custom component creation code here
+ tfName = new StyledTextField();
+ tfAddress = new StyledTextField();
+ //-
+ cbMachineType = new JComboBox<>();
+ cbMachineType.addItem(MachineType.Server);
+ cbMachineType.addItem(MachineType.MVS_cluster);
+ cbMachineType.addItem(MachineType.Local);
+ }
+ @Override
+ public Component getContent() {
+ return content;
+ }
+}
diff --git a/src/GlobalData/Makefile/Makefile.java b/src/GlobalData/Makefile/Makefile.java
new file mode 100644
index 00000000..2108c04d
--- /dev/null
+++ b/src/GlobalData/Makefile/Makefile.java
@@ -0,0 +1,202 @@
+package GlobalData.Makefile;
+import Common.Current;
+import Common.Global;
+import Common.Utils.TextLog;
+import Common.Utils.Utils;
+import GlobalData.Compiler.Compiler;
+import GlobalData.Compiler.CompilerType;
+import GlobalData.Machine.Machine;
+import GlobalData.Module.Module;
+import GlobalData.Module.ModuleAnchestor;
+import ProjectData.Files.DBProjectFile;
+import ProjectData.LanguageName;
+import ProjectData.Project.db_project_info;
+
+import java.util.LinkedHashMap;
+import java.util.Vector;
+import java.util.stream.Collectors;
+//мейкфайл. цепочка модулей. он сам отвечает за линковку.
+//И по одному модулю на каждый язык.
+public class Makefile extends ModuleAnchestor {
+ public Makefile() {
+ }
+ @Override
+ public boolean isVisible() {
+ return Current.HasMachine() && (machine_id == Current.getMachine().id);
+ }
+ public LinkedHashMap getActiveModules() {
+ return Global.db.getByFKAndGroupBy(this, Module.class, "language", LanguageName.class).values().stream().filter(Module::isSelected).collect(Collectors.toMap(module -> module.language, module -> module, (a, b) -> b, LinkedHashMap::new));
+ }
+ public LinkedHashMap getModules() {
+ return Global.db.getByFKAndGroupBy(this, Module.class, "language", LanguageName.class);
+ }
+ public String Generate(db_project_info project, boolean useFilesOrder, LinkedHashMap modules) throws Exception {
+ Compiler linker = getCompiler();
+ if (linker == null) return "";
+ LinkedHashMap> programs = project.getPrograms();
+ Vector titles = new Vector<>();
+ Vector objects = new Vector<>();
+ Vector bodies = new Vector<>();
+ String binary = Utils.DQuotes("0"); // Utils.DQuotes(project.name);
+ for (Module module : modules.values()) {
+ //определить а активен ли модуль.
+ //выбран ли он. есть ли у него компилятор. есть ли для него программы.
+ Compiler module_compiler;
+ if (module.isSelected() &&
+ ((module_compiler = module.getCompiler()) != null)
+ && (!programs.get(module.language).isEmpty())) {
+ //---------------------------------------------------------
+ String LANG_ = module.language.toString().toUpperCase() + "_";
+ Vector module_objects = new Vector<>();
+ String module_body = "";
+ int i = 1;
+//-------------------------------------------------------------------------
+ Vector programsToAssembly = new Vector<>();
+ if (module.language.equals(LanguageName.fortran) && useFilesOrder) {
+ //для фортрана берем порядок с парсера.
+ for (String progName : project.files_order)
+ programsToAssembly.add(project.db.files.get(progName));
+ } else programsToAssembly = programs.get(module.language);
+//--------------------------------------------------------------------------
+ for (DBProjectFile program : programsToAssembly) {
+ //--
+ program.last_assembly_name = module.language.toString() + "_" + i + ".o";
+ String object = Utils.DQuotes(program.last_assembly_name);
+ module_objects.add(object);
+ module_body +=
+ object + ":\n" +
+ "\t" +
+ String.join(" ",
+ Utils.MFVar(LANG_ + "COMMAND"),
+ Utils.MFVar(LANG_ + "FLAGS"),
+ module_compiler.getStyleOptions(program),
+ "-c",
+ program.getQSourceName(),
+ "-o",
+ object + "\n\n"
+ );
+ ++i;
+ }
+ titles.add(String.join("\n",
+ LANG_ + "COMMAND=" + Utils.DQuotes(module_compiler.call_command) + " " + module.command,
+ LANG_ + "FLAGS=" + module.flags,
+ LANG_ + "OBJECTS=" + String.join(" ", module_objects),
+ ""
+ ));
+ objects.add(Utils.MFVar(LANG_ + "OBJECTS"));
+ bodies.add(module_body);
+ }
+ }
+ return String.join("\n",
+ "LINK_COMMAND=" + Utils.DQuotes(linker.call_command) + " " + command,
+ "LINK_FLAGS=" + flags + "\n",
+ String.join("\n", titles),
+ "all: " + binary,
+ binary + " : " + String.join(" ", objects),
+ "\t" + Utils.MFVar("LINK_COMMAND") + " " + Utils.MFVar("LINK_FLAGS") + " " + String.join(" ", objects) + " -o " + binary,
+ String.join(" ", bodies));
+ }
+ public String Generate(db_project_info project_info) throws Exception {
+ return Generate(project_info, true, getActiveModules());
+ }
+ public String GenerateForPrecompilation(db_project_info project, LinkedHashMap modules) {
+ Compiler linker = getCompiler();
+ if (linker == null) return "";
+ LinkedHashMap> programs = project.getPrograms();
+ Vector titles = new Vector<>();
+ Vector objects = new Vector<>();
+ Vector bodies = new Vector<>();
+ for (Module module : modules.values()) {
+ //определить а активен ли модуль.
+ //выбран ли он. есть ли у него компилятор. есть ли для него программы.
+ Compiler module_compiler;
+ if (module.isSelected() &&
+ ((module_compiler = module.getCompiler()) != null)
+ && (!programs.get(module.language).isEmpty())) {
+ //---------------------------------------------------------
+ String LANG_ = module.language.toString().toUpperCase() + "_";
+ Vector module_objects = new Vector<>();
+ String module_body = "";
+ int i = 1;
+//-------------------------------------------------------------------------
+ Vector programsToAssembly = programs.get(module.language);
+//--------------------------------------------------------------------------
+ for (DBProjectFile program : programsToAssembly) {
+ //--
+ program.last_assembly_name = module.language.toString() + "_" + i + ".o";
+ String object = Utils.DQuotes(program.last_assembly_name);
+ module_objects.add(object);
+ module_body +=
+ object + ":\n" +
+ "\t" +
+ String.join(" ",
+ Utils.MFVar(LANG_ + "COMMAND"),
+ Utils.MFVar(LANG_ + "FLAGS"),
+ module_compiler.getStyleOptions(program),
+ "-c",
+ program.getQSourceName() + "\n\n"
+ // "-o",
+ // object
+ );
+ ++i;
+ }
+ titles.add(String.join("\n",
+ LANG_ + "COMMAND=" + Utils.DQuotes(module_compiler.call_command) + " " + module.command,
+ LANG_ + "FLAGS=" + module.flags,
+ LANG_ + "OBJECTS=" + String.join(" ", module_objects),
+ ""
+ ));
+ objects.add(Utils.MFVar(LANG_ + "OBJECTS"));
+ bodies.add(module_body);
+ }
+ }
+ return String.join("\n",
+ String.join("\n", titles),
+ "all: " + String.join(" ", objects),
+ String.join(" ", bodies));
+ }
+ //---------------------------------------
+ //todo возможно улучшить
+ //https://habr.com/ru/post/211751/
+ public Machine getMachine() {
+ return Global.db.getById(Machine.class, machine_id);
+ }
+ public boolean DependsToCompiler(Compiler compiler) {
+ if (compiler_id == compiler.id) return true;
+ else {
+ LinkedHashMap modules = getModules();
+ for (Module module : modules.values())
+ if (module.compiler_id == compiler.id) return true;
+ }
+ return false;
+ }
+ public void Validate(TextLog Log) {
+ Compiler linker;
+ if ((linker = getCompiler()) == null)
+ Log.Writeln("Линковщик не выбран");
+ else {
+ if (linker.type.equals(CompilerType.dvm)) {
+ if (!Current.getProject().languageName.getDVMLink().equals(command))
+ Log.Writeln("команда линковки " +
+ Utils.Quotes(command) +
+ " не соответствует языку текущего проекта "
+ + Current.getProject().languageName.getDescription() + "\n" +
+ "Используйте команду " + Current.getProject().languageName.getDVMLink());
+ }
+ }
+ LinkedHashMap modules = getModules();
+ for (Module module : modules.values()) {
+ boolean isMain = module.language.equals(Current.getProject().languageName);
+ if (module.isSelected()) {
+ if (module.getCompiler() == null)
+ Log.Writeln("Не назначен компилятор для языка " + module.language.getDescription());
+ if (isMain && Current.getProject().getPrograms().get(module.language).isEmpty())
+ Log.Writeln("В текущем проекте не найдено ни одной программы на языке " + module.language.getDescription());
+ } else {
+ if (isMain)
+ Log.Writeln("Языковой модуль, соответствующий языку текущего проекта " +
+ Current.getProject().languageName.getDescription() + " не помечен как активный.");
+ }
+ }
+ }
+}
diff --git a/src/GlobalData/Makefile/MakefilesDBTable.java b/src/GlobalData/Makefile/MakefilesDBTable.java
new file mode 100644
index 00000000..98719077
--- /dev/null
+++ b/src/GlobalData/Makefile/MakefilesDBTable.java
@@ -0,0 +1,70 @@
+package GlobalData.Makefile;
+import Common.Current;
+import Common.Database.*;
+import Common.UI.DataSetControlForm;
+import Common.UI.Windows.Dialog.DBObjectDialog;
+import GlobalData.Module.Module;
+import GlobalData.Module.UI.ModuleAnchestorFields;
+import GlobalData.Module.UI.ModuleAnchestorForm;
+import GlobalData.Tasks.CompilationTask.CompilationTask;
+
+import java.util.LinkedHashMap;
+public class MakefilesDBTable extends iDBTable {
+ public MakefilesDBTable() {
+ super(Makefile.class);
+ }
+ @Override
+ public String getSingleDescription() {
+ return "мейкфайл";
+ }
+ @Override
+ public String getPluralDescription() {
+ return "мейкфайлы";
+ }
+ @Override
+ public DBObjectDialog getDialog() {
+ return new ModuleAnchestorForm<>();
+ }
+ @Override
+ public LinkedHashMap, FKBehaviour> getFKDependencies() {
+ LinkedHashMap, FKBehaviour> res = new LinkedHashMap<>();
+ res.put(Module.class, new FKBehaviour(FKDataBehaviour.DELETE, FKCurrentObjectBehaviuor.ACTIVE));
+ res.put(CompilationTask.class, new FKBehaviour(FKDataBehaviour.DELETE, FKCurrentObjectBehaviuor.ACTIVE));
+ return res;
+ }
+ @Override
+ protected DataSetControlForm createUI() {
+ return new DataSetControlForm(this) {
+ @Override
+ protected void AdditionalInitColumns() {
+ columns.get(0).setVisible(false);
+ }
+
+ };
+ }
+ @Override
+ public String[] getUIColumnNames() {
+ return new String[]{
+ "Линковщик",
+ "Команда",
+ "Флаги"
+ };
+ }
+ @Override
+ public Object getFieldAt(Makefile object, int columnIndex) {
+ switch (columnIndex) {
+ case 1:
+ return object.getCompilerDescription();
+ case 2:
+ return object.command;
+ case 3:
+ return object.flags;
+ default:
+ return null;
+ }
+ }
+ @Override
+ public Current CurrentName() {
+ return Current.Makefile;
+ }
+}
diff --git a/src/GlobalData/Makefile/UI/MakefilePreviewForm.java b/src/GlobalData/Makefile/UI/MakefilePreviewForm.java
new file mode 100644
index 00000000..46a99064
--- /dev/null
+++ b/src/GlobalData/Makefile/UI/MakefilePreviewForm.java
@@ -0,0 +1,22 @@
+package GlobalData.Makefile.UI;
+import Common.UI.Editor.Viewer;
+import Common.UI.Windows.Dialog.Text.TextDialog;
+public class MakefilePreviewForm extends TextDialog {
+ public MakefilePreviewForm() {
+ super(Viewer.class);
+ }
+ @Override
+ public void InitFields() {
+ fields.setSyntaxEditingStyle("text/makefile");
+ fields.setWhitespaceVisible(true);
+ fields.setEditable(false);
+ }
+ @Override
+ public void setText(String text_in) {
+ fields.setText(text_in);
+ }
+ @Override
+ public void CreateButtons() {
+ //кнопок нет.
+ }
+}
diff --git a/src/GlobalData/Module/Module.java b/src/GlobalData/Module/Module.java
new file mode 100644
index 00000000..ccaadd6e
--- /dev/null
+++ b/src/GlobalData/Module/Module.java
@@ -0,0 +1,37 @@
+package GlobalData.Module;
+import Common.Current;
+import Common.Global;
+import Common.Utils.Utils;
+import GlobalData.Makefile.Makefile;
+import ProjectData.LanguageName;
+public class Module extends ModuleAnchestor {
+ public int makefile_id = Utils.Nan;
+ public LanguageName language = LanguageName.n;
+ public int on = 1; //учитывать ли модуль при сборке. указание пользователя. если файлы отсутствуют - игнорится
+ public Module() {
+ }
+ public Module(LanguageName language_in, Makefile makefile) {
+ language = language_in;
+ if (makefile != null) {
+ makefile_id = makefile.id;
+ machine_id = makefile.machine_id;
+ }
+ }
+ @Override
+ public boolean isVisible() {
+ return Current.HasMakefile() && (makefile_id == Current.getMakefile().id);
+ }
+ @Override
+ public boolean isSelected() {
+ return on > 0;
+ }
+ @Override
+ public void Select(boolean flag) {
+ on = flag ? 1 : 0;
+ try {
+ Global.db.Update(this);
+ } catch (Exception e) {
+ Global.Log.PrintException(e);
+ }
+ }
+}
diff --git a/src/GlobalData/Module/ModuleAnchestor.java b/src/GlobalData/Module/ModuleAnchestor.java
new file mode 100644
index 00000000..fc6e88f5
--- /dev/null
+++ b/src/GlobalData/Module/ModuleAnchestor.java
@@ -0,0 +1,36 @@
+package GlobalData.Module;
+import Common.Database.iDBObject;
+import Common.Global;
+import Common.Utils.Utils;
+import GlobalData.Compiler.Compiler;
+public class ModuleAnchestor extends iDBObject {
+ //--------------------------------------------------------------------------------------
+ public int machine_id = Utils.Nan;
+ public int compiler_id = Utils.Nan;
+ public String command = ""; //дополнительная команда компилятору. между вызовом и флагами.
+ public String flags = ""; //последовательность флагов
+ //---------------------------------------------------------------------------------------
+ //для таблиц
+ public String getCompilerDescription() {
+ Compiler compiler;
+ return ((compiler = getCompiler()) == null) ? "" : compiler.getDescription();
+ }
+ public Compiler getCompiler() {
+ return Global.db.getById(Compiler.class, compiler_id);
+ }
+ public String getDescription() {
+ String res = "";
+ if (getCompiler() != null) {
+ res += Utils.Brackets(getCompiler().getDescription());
+ if (!command.isEmpty())
+ res += " " + Utils.Brackets(command);
+ if (!flags.isEmpty())
+ res += " " + Utils.Brackets(flags);
+ }
+ return res;
+ }
+ public String getStatCommand() {
+ Compiler compiler = getCompiler();
+ return ((compiler != null) ? (compiler.call_command) : "");
+ }
+}
diff --git a/src/GlobalData/Module/ModulesDBTable.java b/src/GlobalData/Module/ModulesDBTable.java
new file mode 100644
index 00000000..31d39b06
--- /dev/null
+++ b/src/GlobalData/Module/ModulesDBTable.java
@@ -0,0 +1,65 @@
+package GlobalData.Module;
+import Common.Current;
+import Common.Database.iDBTable;
+import Common.UI.DataSetControlForm;
+import Common.UI.Windows.Dialog.DBObjectDialog;
+import Common.UI.Windows.Dialog.DialogFields;
+import GlobalData.Module.UI.ModuleAnchestorForm;
+public class ModulesDBTable extends iDBTable {
+ public ModulesDBTable() {
+ super(Module.class);
+ }
+ @Override
+ public String getSingleDescription() {
+ return "языковой модуль";
+ }
+ @Override
+ public String getPluralDescription() {
+ return "языковые модули";
+ }
+ @Override
+ public DBObjectDialog getDialog() {
+ return new ModuleAnchestorForm<>();
+ }
+ @Override
+ protected DataSetControlForm createUI() {
+ return new DataSetControlForm(this) {
+ @Override
+ public boolean hasCheckBox() {
+ return true;
+ }
+ @Override
+ protected void AdditionalInitColumns() {
+ columns.get(0).setVisible(false);
+ }
+ };
+ }
+ @Override
+ public Object getFieldAt(Module object, int columnIndex) {
+ switch (columnIndex) {
+ case 2:
+ return object.language.getDescription();
+ case 3:
+ return object.getCompilerDescription();
+ case 4:
+ return object.command;
+ case 5:
+ return object.flags;
+ default:
+ return null;
+ }
+ }
+ @Override
+ public String[] getUIColumnNames() {
+ return new String[]{
+ "Язык",
+ "Компилятор",
+ "Команда",
+ "Флаги"
+ };
+ }
+ @Override
+ public Current CurrentName() {
+ return Current.Module;
+ }
+}
diff --git a/src/GlobalData/Module/UI/ModuleAnchestorFields.form b/src/GlobalData/Module/UI/ModuleAnchestorFields.form
new file mode 100644
index 00000000..b8ede03a
--- /dev/null
+++ b/src/GlobalData/Module/UI/ModuleAnchestorFields.form
@@ -0,0 +1,111 @@
+
+
diff --git a/src/GlobalData/Module/UI/ModuleAnchestorFields.java b/src/GlobalData/Module/UI/ModuleAnchestorFields.java
new file mode 100644
index 00000000..502b7940
--- /dev/null
+++ b/src/GlobalData/Module/UI/ModuleAnchestorFields.java
@@ -0,0 +1,74 @@
+package GlobalData.Module.UI;
+import Common.Current;
+import Common.UI.ComboBox.StyledTextComboBox;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.DialogFields;
+import GlobalData.Compiler.Compiler;
+import GlobalData.Makefile.Makefile;
+import GlobalData.Module.Module;
+import GlobalData.Module.ModuleAnchestor;
+import ProjectData.LanguageName;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.LinkedHashMap;
+public class ModuleAnchestorFields implements DialogFields {
+ public JPanel content;
+ public JComboBox cbCompilers;
+ public JComboBox cbCommands;
+ public JComboBox cbFlags;
+ private JButton bHelp;
+ private JButton BPickOptions;
+ private Compiler compiler;
+ //считаем что машина есть.
+ public ModuleAnchestorFields() {
+ //-
+ LinkedHashMap compilers = Current.getMachine().getCompilers();
+ compilers.values().forEach(compiler -> cbCompilers.addItem(compiler));
+ bHelp.addActionListener(e -> {
+ if (cbCompilers.getSelectedItem() != null) {
+ Pass_2021.passes.get(PassCode_2021.ShowCompilerHelp).Do(compiler, true);
+ } else UI.Info("Компилятор не выбран");
+ });
+ BPickOptions.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Pass_2021 pass = Pass_2021.passes.get(PassCode_2021.PickCompilerOptions);
+ if (pass.Do(compiler)) {
+ UI.TrySelect(cbFlags, pass.target);
+ }
+ }
+ });
+ cbCompilers.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ compiler = (Compiler) cbCompilers.getSelectedItem();
+ }
+ });
+ }
+ public void setListeners(ModuleAnchestor target) {
+ boolean linker = (target instanceof Makefile);
+ LanguageName languageName = linker ?
+ (Current.HasProject() ? Current.getProject().languageName : LanguageName.n) :
+ ((Module) target).language;
+ cbCompilers.addActionListener(e -> {
+ if (cbCompilers.getSelectedItem() instanceof Compiler) {
+ Compiler compiler = ((Compiler) cbCompilers.getSelectedItem());
+ UI.TrySelect(cbCommands,
+ linker ? compiler.getSpecialLinkCommand(languageName) : compiler.getSpecialCompilationCommand(languageName));
+ }
+ });
+ }
+ @Override
+ public Component getContent() {
+ return content;
+ }
+ private void createUIComponents() {
+ // TODO: place custom component creation code here
+ cbFlags = new StyledTextComboBox();
+ }
+}
diff --git a/src/GlobalData/Module/UI/ModuleAnchestorForm.java b/src/GlobalData/Module/UI/ModuleAnchestorForm.java
new file mode 100644
index 00000000..925a7918
--- /dev/null
+++ b/src/GlobalData/Module/UI/ModuleAnchestorForm.java
@@ -0,0 +1,107 @@
+package GlobalData.Module.UI;
+import Common.Current;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.DBObjectDialog;
+import Common.Utils.Utils;
+import GlobalData.Compiler.Compiler;
+import GlobalData.Compiler.CompilerType;
+import GlobalData.Makefile.Makefile;
+import GlobalData.Module.Module;
+import GlobalData.Module.ModuleAnchestor;
+import ProjectData.LanguageName;
+public class ModuleAnchestorForm extends DBObjectDialog {
+ public static String[] banned_flags = new String[]{
+ "-c", "-o",
+ "-ffree-form", "-ffixed-line-length-132", "-ffixed-form",
+ "-FI", "-f90",
+ "-fixed", "-free"
+ };
+ String command;
+ String flags;
+ public ModuleAnchestorForm() {
+ super(ModuleAnchestorFields.class);
+ }
+ @Override
+ public int getDefaultHeight() {
+ return 250;
+ }
+ @Override
+ public void validateFields() {
+ Compiler compiler = (Compiler) fields.cbCompilers.getSelectedItem();
+ command = (String) fields.cbCommands.getSelectedItem();
+ if (command == null) {
+ Log.Writeln("команда компиляции не выбрана");
+ } else {
+ if ((compiler != null) && compiler.type.equals(CompilerType.dvm)) {
+ //проверим команду.
+ if (Result instanceof Makefile) {
+ //могут быть только flink/clink
+ if (!command.equals("flink") && !command.equals("clink")) {
+ Log.Writeln("При линковке DVM системой допустимы\n" +
+ "только команды flink или clink");
+ }
+ } else if (Result instanceof Module) {
+ //могут быть только f/c
+ LanguageName languageName = ((Module) Result).language;
+ switch (languageName) {
+ case fortran:
+ case c:
+ if (!command.equals(languageName.getDVMCompile()))
+ Log.Writeln("компиляция " + languageName.getDescription() +
+ " программ DVM системой осуществляется только командой " +
+ languageName.getDVMCompile()
+ );
+ break;
+ default:
+ Log.Writeln("язык " + languageName + " не поддерживается DVM системой");
+ break;
+ }
+ }
+ } else {
+ if (!command.isEmpty())
+ Log.Writeln("Для всех компиляторов, кроме DVM системы, команда компиляции/линковки должна быть пуста.");
+ }
+ }
+ flags = (String) fields.cbFlags.getSelectedItem();
+ if (flags == null) Log.Writeln("флаги компиляции не выбраны");
+ else {
+ //проверка на служебные флаги
+ String[] data = flags.split(" ");
+ for (String flag : data) {
+ if (!flag.isEmpty()) {
+ /*
+ if (!flag.startsWith("-")) {
+ Log.Writeln("неверный формат флага " + Utils.Brackets(flag));
+ } else {
+ */
+ for (String banned_flag : banned_flags) {
+ if (flag.equalsIgnoreCase(banned_flag)) {
+ Log.Writeln("флаги:\n" +
+ String.join(",", banned_flags) +
+ "\nзарезервированы системой.");
+ return;
+ }
+ // }
+ }
+ }
+ }
+ }
+ //проврка команды
+ }
+ @Override
+ public void fillFields() {
+ UI.TrySelect(fields.cbFlags, Result.flags);
+ UI.TrySelect(fields.cbCommands, Result.command);
+ UI.TrySelect(fields.cbCompilers, Result.getCompiler());
+ //--------------------------------------------
+ fields.setListeners(Result);
+ }
+ @Override
+ public void ProcessResult() {
+ Result.machine_id = Current.getMachine().id;
+ Compiler compiler = (Compiler) fields.cbCompilers.getSelectedItem();
+ Result.compiler_id = (compiler != null) ? compiler.id : Utils.Nan;
+ Result.command = command;
+ Result.flags = flags;
+ }
+}
diff --git a/src/GlobalData/RemoteFile/RemoteFile.java b/src/GlobalData/RemoteFile/RemoteFile.java
new file mode 100644
index 00000000..6d7ffba2
--- /dev/null
+++ b/src/GlobalData/RemoteFile/RemoteFile.java
@@ -0,0 +1,37 @@
+package GlobalData.RemoteFile;
+import java.io.Serializable;
+public class RemoteFile implements Serializable {
+ public String name;
+ public String full_name;
+ public String parent;
+ public boolean isDirectory;
+ public long updateTime;
+ public RemoteFile(String path, boolean isDirectory_in) {
+ full_name = path;
+ isDirectory = isDirectory_in;
+ String[] data = full_name.split("/");
+ name = (data.length > 0) ? data[data.length - 1] : "";
+ int i = full_name.lastIndexOf('/');
+ parent = (i > 0) ? full_name.substring(0, i) : "/";
+ }
+ public RemoteFile(String parent_in, String name_in, boolean isDirectory_in) {
+ parent = parent_in;
+ full_name = parent + (parent.endsWith("/") ? "" : "/") + name_in;
+ name = name_in;
+ isDirectory = isDirectory_in;
+ }
+ public RemoteFile(RemoteFile parent_in, String name_in){
+ this(parent_in.full_name, name_in);
+ }
+ public RemoteFile(String parent_in, String name_in) {
+ this(parent_in, name_in, false);
+ }
+ public static long convertUpdateTime(int mtime) {
+ return (long) mtime * 1000L;
+ }
+ public boolean isDirectory() {
+ return isDirectory;
+ }
+}
+
+
diff --git a/src/GlobalData/RemoteFile/UI/RemoteFileChooser.java b/src/GlobalData/RemoteFile/UI/RemoteFileChooser.java
new file mode 100644
index 00000000..ade860ad
--- /dev/null
+++ b/src/GlobalData/RemoteFile/UI/RemoteFileChooser.java
@@ -0,0 +1,96 @@
+package GlobalData.RemoteFile.UI;
+import Common.Current;
+import Common.Global;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.Dialog;
+import GlobalData.RemoteFile.RemoteFile;
+import Visual_DVM_2021.Passes.SSH.ConnectionPass;
+import com.jcraft.jsch.ChannelSftp.LsEntry;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Vector;
+public class RemoteFileChooser extends Dialog {
+ public DefaultMutableTreeNode root = new DefaultMutableTreeNode("нет данных");
+ ConnectionPass session;
+ RemoteFile root_file;
+ boolean target_is_directory = false;
+ public RemoteFileChooser() {
+ super(RemoteFileChooserFields.class);
+ }
+ @Override
+ public boolean NeedsScroll() {
+ return false;
+ }
+ @Override
+ public void Init(Object... params) {
+ session = (ConnectionPass) params[0];
+ target_is_directory = (boolean) params[1];
+ try {
+ Refresh(session.getSftpChannel().pwd());
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ onCancel(); //закрываем окно.
+ }
+ }
+ public void ShowCurrentRemoteFile() {
+ fields.lCurrentFile.setText(Current.getRemoteFile().full_name);
+ }
+ public void Refresh(String path) {
+ try {
+ Current.set(Current.RemoteFile, null);//сброс текущего файла перед любым обновлением.
+ fields.lCurrentFile.setText("?");
+ //-------------------------------------------------------------------
+ root_file = new RemoteFile(path, true);
+ root = new DefaultMutableTreeNode(root_file);
+ //-------------------------------------------------------
+ Vector files = session.getSftpChannel().ls(path);
+ Vector directories_ = new Vector<>();
+ Vector files_ = new Vector<>();
+ //отсортировать по принадлежности.
+ for (LsEntry file : files) {
+ if (!file.getFilename().equals(".") && !file.getFilename().equals("")) {
+ if (file.getAttrs().isDir())
+ directories_.add(new RemoteFile(root_file.full_name, file.getFilename(), true));
+ else
+ files_.add(new RemoteFile(root_file.full_name, file.getFilename(), false));
+ }
+ }
+ //отсортировать по алфавиту
+ Collections.sort(directories_, Comparator.comparing(o -> o.name));
+ Collections.sort(files_, Comparator.comparing(o -> o.name));
+ for (RemoteFile f : directories_)
+ root.add(new DefaultMutableTreeNode(f));
+ for (RemoteFile f : files_)
+ root.add(new DefaultMutableTreeNode(f));
+ //просто пересоздаем дерево
+ fields.treeForm.Show();
+ fields.lCurrentFolder.setText(path);
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ onCancel();
+ }
+ }
+ public void goHome() {
+ try {
+ Refresh(session.getSftpChannel().getHome());
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ onCancel(); //закрываем окно.
+ }
+ }
+ public void goUp() {
+ if (!root_file.full_name.equals("/")) {
+ Refresh(root_file.parent);
+ } else UI.Info("Корневая папка файловой системы достигнута.");
+ }
+ @Override
+ public void validateFields() {
+ String target_name = target_is_directory ? "папка" : "файл";
+ if (Current.HasRemoteFile()) {
+ if (target_is_directory != Current.getRemoteFile().isDirectory)
+ Log.Writeln("Выбранный объект - не " + target_name);
+ } else Log.Writeln(target_name + " не выбран(а)");
+ }
+}
diff --git a/src/GlobalData/RemoteFile/UI/RemoteFileChooserFields.form b/src/GlobalData/RemoteFile/UI/RemoteFileChooserFields.form
new file mode 100644
index 00000000..98bceb1c
--- /dev/null
+++ b/src/GlobalData/RemoteFile/UI/RemoteFileChooserFields.form
@@ -0,0 +1,109 @@
+
+
diff --git a/src/GlobalData/RemoteFile/UI/RemoteFileChooserFields.java b/src/GlobalData/RemoteFile/UI/RemoteFileChooserFields.java
new file mode 100644
index 00000000..e75c8ddd
--- /dev/null
+++ b/src/GlobalData/RemoteFile/UI/RemoteFileChooserFields.java
@@ -0,0 +1,40 @@
+package GlobalData.RemoteFile.UI;
+import Common.UI.Trees.TreeForm;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.DialogFields;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+public class RemoteFileChooserFields implements DialogFields {
+ public JPanel MainPanel;
+ public JLabel lCurrentFolder;
+ public JLabel lCurrentFile;
+ public TreeForm treeForm;
+ private JPanel TreePanel;
+ private JButton bBack;
+ private JButton bHome;
+ public RemoteFileChooserFields() {
+ bBack.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ UI.getRemoteFileChooser().goUp();
+ }
+ });
+ bHome.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ UI.getRemoteFileChooser().goHome();
+ }
+ });
+ }
+ private void createUIComponents() {
+ // TODO: place custom component creation code here
+ TreePanel = (treeForm = new TreeForm(RemoteFilesTree.class)).getContent();
+ }
+ @Override
+ public Component getContent() {
+ return MainPanel;
+ }
+}
diff --git a/src/GlobalData/RemoteFile/UI/RemoteFileRenderer.java b/src/GlobalData/RemoteFile/UI/RemoteFileRenderer.java
new file mode 100644
index 00000000..75f1403f
--- /dev/null
+++ b/src/GlobalData/RemoteFile/UI/RemoteFileRenderer.java
@@ -0,0 +1,26 @@
+package GlobalData.RemoteFile.UI;
+import Common.Current;
+import Common.UI.Themes.VisualiserFonts;
+import Common.UI.Trees.StyledTreeCellRenderer;
+import GlobalData.RemoteFile.RemoteFile;
+
+import javax.swing.*;
+import javax.swing.tree.DefaultMutableTreeNode;
+public class RemoteFileRenderer extends StyledTreeCellRenderer {
+ public java.awt.Component getTreeCellRendererComponent(
+ JTree tree, Object value,
+ boolean selected, boolean expanded,
+ boolean leaf, int row, boolean hasFocus) {
+ super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
+ Object o = ((DefaultMutableTreeNode) value).getUserObject();
+ if (o instanceof RemoteFile) {
+ RemoteFile file = (RemoteFile) o;
+ setText(file.name);
+ setFont(Current.getTheme().Fonts.get(VisualiserFonts.TreePlain));
+ if (file.isDirectory())
+ setIcon(new ImageIcon(getClass().getResource("/icons/Folder.png")));
+ }
+ setForeground(tree.getForeground());
+ return this;
+ }
+}
diff --git a/src/GlobalData/RemoteFile/UI/RemoteFilesTree.java b/src/GlobalData/RemoteFile/UI/RemoteFilesTree.java
new file mode 100644
index 00000000..fece598d
--- /dev/null
+++ b/src/GlobalData/RemoteFile/UI/RemoteFilesTree.java
@@ -0,0 +1,28 @@
+package GlobalData.RemoteFile.UI;
+import Common.Current;
+import Common.UI.Trees.DataTree;
+import Common.UI.Trees.TreeRenderers;
+import Common.UI.UI;
+public class RemoteFilesTree extends DataTree {
+ public RemoteFilesTree() {
+ super(UI.getRemoteFileChooser().root);
+ }
+ @Override
+ public TreeRenderers getRenderer() {
+ return TreeRenderers.RendererRemoteFile;
+ }
+ @Override
+ public Current getCurrent() {
+ return Current.RemoteFile;
+ }
+ @Override
+ public void ShowCurrentObject() {
+ UI.getRemoteFileChooser().ShowCurrentRemoteFile();
+ }
+ @Override
+ public void LeftMouseAction2() {
+ if (Current.HasRemoteFile() && Current.getRemoteFile().isDirectory()) {
+ UI.getRemoteFileChooser().Refresh(Current.getRemoteFile().full_name);
+ }
+ }
+}
diff --git a/src/GlobalData/RemoteSapfor/RemoteSapfor.java b/src/GlobalData/RemoteSapfor/RemoteSapfor.java
new file mode 100644
index 00000000..7ae5aba4
--- /dev/null
+++ b/src/GlobalData/RemoteSapfor/RemoteSapfor.java
@@ -0,0 +1,47 @@
+package GlobalData.RemoteSapfor;
+import Common.Current;
+import Common.Database.iDBObject;
+import Common.Utils.Utils;
+import GlobalData.Machine.Machine;
+import ProjectData.LanguageName;
+import com.sun.org.glassfish.gmbal.Description;
+public class RemoteSapfor extends iDBObject {
+ //---------------------------------------------------------------------
+ @Description("IGNORE")
+ public static String version_command = "-ver";//команда запроса версии компилятора.
+ @Description("IGNORE")
+ public static String help_command = "-help";// команда запроса help
+ //----------------------------------------------------------------------
+ public int machine_id = -1;
+ public String description = "";
+ public LanguageName languageName = LanguageName.fortran;
+ public String home_path = ""; //домашняя папка.
+ public String call_command = ""; //полная команда вызова.
+ public String version = "?";
+ public RemoteSapfor() {
+ }
+ public RemoteSapfor(Machine machine,
+ String description_in,
+ LanguageName languageName_in,
+ String call_command_in
+ ) {
+ machine_id = machine.id;
+ description = description_in;
+ languageName = languageName_in;
+ call_command = call_command_in;
+ }
+ @Override
+ public boolean isVisible() {
+ return Current.HasMachine() && Current.getMachine().id == machine_id;
+ }
+ @Override
+ public String toString() {
+ return call_command;
+ }
+ public String getDescription() {
+ return description;
+ }
+ public String getVersionCommand() {
+ return Utils.DQuotes(call_command) + " " + version_command;
+ }
+}
diff --git a/src/GlobalData/RemoteSapfor/RemoteSapforsDBTable.java b/src/GlobalData/RemoteSapfor/RemoteSapforsDBTable.java
new file mode 100644
index 00000000..605c0f6f
--- /dev/null
+++ b/src/GlobalData/RemoteSapfor/RemoteSapforsDBTable.java
@@ -0,0 +1,126 @@
+package GlobalData.RemoteSapfor;
+import Common.Current;
+import Common.Database.iDBTable;
+import Common.UI.DataSetControlForm;
+import Common.UI.UI;
+import Common.UI.Windows.Dialog.DBObjectDialog;
+import Common.Utils.Utils;
+import Common.Utils.Validators.PathValidator;
+import GlobalData.RemoteSapfor.UI.RemoteSapforFields;
+import ProjectData.LanguageName;
+public class RemoteSapforsDBTable extends iDBTable {
+ public RemoteSapforsDBTable() {
+ super(RemoteSapfor.class);
+ }
+ @Override
+ public String getSingleDescription() {
+ return "SAPFOR";
+ }
+ @Override
+ public String getPluralDescription() {
+ return "SAPFOR";
+ }
+ @Override
+ public Current CurrentName() {
+ return Current.RemoteSapfor;
+ }
+ @Override
+ public String[] getUIColumnNames() {
+ return new String[]{"описание", "команда вызова", "версия"};
+ }
+ @Override
+ public Object getFieldAt(RemoteSapfor object, int columnIndex) {
+ switch (columnIndex) {
+ case 1:
+ return object.description;
+ case 2:
+ return object.call_command;
+ case 3:
+ return object.version;
+ }
+ return null;
+ }
+ @Override
+ protected DataSetControlForm createUI() {
+ return new DataSetControlForm(this) {
+ @Override
+ protected void AdditionalInitColumns() {
+ columns.get(0).setVisible(false);
+ }
+ };
+ }
+ //---
+ @Override
+ public DBObjectDialog getDialog() {
+ return new DBObjectDialog(RemoteSapforFields.class) {
+ @Override
+ public void validateFields() {
+ //
+ String home = fields.tfHome.getText();
+ if (!home.isEmpty()) {
+ if (home.startsWith("/")) {
+ if (Utils.ContainsCyrillic(home))
+ Log.Writeln("Расположение системы SAPFOR не может содержать кириллицу");
+ else {
+ new PathValidator(home, "Расположение системы SAPFOR", Log).Validate();
+ }
+ } else
+ Log.Writeln("Расположение системы SAPFOR может быть либо пустой строкой, либо путём к файлу");
+ }
+ //
+ //
+ String call_command = fields.tfCallCommand.getText();
+ if (call_command.isEmpty()) Log.Writeln("Команда вызова системы SAPFOR не может быть пустой");
+ else if (Utils.ContainsCyrillic(call_command))
+ Log.Writeln("Команда вызова системы SAPFOR не может содержать кириллицу");
+ else {
+ switch (call_command.charAt(0)) {
+ case ' ':
+ Log.Writeln("Команда вызова системы SAPFOR не может начинаться с пробела.");
+ break;
+ case '/':
+ if (call_command.endsWith("/"))
+ Log.Writeln("Каталог не может быть указан в качестве команды.");
+ else new PathValidator(call_command, "Команда вызова системы SAPFOR", Log).Validate();
+ break;
+ default:
+ //это команда.
+ //самое опасное место. теоретически тут можно ввести любую команду ОС, в том числе rm -rf
+ if (call_command.contains(" "))
+ Log.Writeln("Прямая команда вызова системы SAPFOR не может содержать пробелы");
+ if (!call_command.contains("+") && Utils.ContainsForbiddenName(call_command))
+ Log.Writeln("Прямая команда вызова системы SAPFOR содержит запрещённые символы");
+ else {
+ if (Utils.isLinuxSystemCommand(call_command))
+ Log.Writeln(Utils.DQuotes(call_command) + " является системной командой Linux");
+ }
+ break;
+ }
+ }
+ //
+ }
+ @Override
+ public void fillFields() {
+ fields.tfDescription.setText(Result.description);
+ fields.tfCallCommand.setText(Result.call_command);
+ fields.tfHome.setText(Result.home_path);
+ UI.TrySelect(fields.cbLanguageName, Result.languageName);
+ fields.tfVersion.setText(Result.version);
+ fields.events_on = true;
+ }
+ @Override
+ public void ProcessResult() {
+ Result.machine_id = Current.getMachine().id;
+ Result.description = fields.tfDescription.getText();
+ Result.call_command = fields.tfCallCommand.getText();
+ Result.home_path = fields.tfHome.getText();
+ Result.languageName = (LanguageName) fields.cbLanguageName.getSelectedItem();
+ Result.version = fields.tfVersion.getText();
+ }
+ @Override
+ public int getDefaultHeight() {
+ return 300;
+ }
+ };
+ }
+}
diff --git a/src/GlobalData/RemoteSapfor/UI/RemoteSapforFields.form b/src/GlobalData/RemoteSapfor/UI/RemoteSapforFields.form
new file mode 100644
index 00000000..f93db10e
--- /dev/null
+++ b/src/GlobalData/RemoteSapfor/UI/RemoteSapforFields.form
@@ -0,0 +1,113 @@
+
+
diff --git a/src/GlobalData/RemoteSapfor/UI/RemoteSapforFields.java b/src/GlobalData/RemoteSapfor/UI/RemoteSapforFields.java
new file mode 100644
index 00000000..3a9a4b30
--- /dev/null
+++ b/src/GlobalData/RemoteSapfor/UI/RemoteSapforFields.java
@@ -0,0 +1,65 @@
+package GlobalData.RemoteSapfor.UI;
+import Common.Current;
+import Common.UI.TextField.StyledTextField;
+import Common.UI.Windows.Dialog.DialogFields;
+import ProjectData.LanguageName;
+import Visual_DVM_2021.Passes.PassCode_2021;
+import Visual_DVM_2021.Passes.Pass_2021;
+
+import javax.swing.*;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import java.awt.*;
+public class RemoteSapforFields implements DialogFields {
+ private JPanel content;
+ public JTextField tfDescription;
+ public JTextField tfHome;
+ private JButton bBrowse;
+ public JTextField tfCallCommand;
+ public JComboBox cbLanguageName;
+ public JTextField tfVersion;
+ public boolean events_on = false;
+ @Override
+ public Component getContent() {
+ return content;
+ }
+ private void createUIComponents() {
+ // TODO: place custom component creation code here
+ tfDescription = new StyledTextField();
+ tfHome = new StyledTextField();
+ tfCallCommand = new StyledTextField();
+ cbLanguageName = new JComboBox<>();
+ cbLanguageName.addItem(LanguageName.fortran);
+ tfVersion = new StyledTextField();
+ }
+ public RemoteSapforFields() {
+ bBrowse.addActionListener(e -> {
+ // LanguageName languageName = (LanguageName) cbLanguageName.getSelectedItem();
+ String dst = null;
+ if (Pass_2021.passes.get(PassCode_2021.SelectRemoteFile).Do(true))
+ dst = Current.getRemoteFile().full_name;
+ if (dst != null)
+ tfHome.setText(dst);
+ });
+ tfHome.getDocument().addDocumentListener(new DocumentListener() {
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ TryRestoreCallCommand();
+ }
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ TryRestoreCallCommand();
+ }
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ }
+ }
+ );
+ }
+ public void TryRestoreCallCommand() {
+ if (events_on && (cbLanguageName.getSelectedItem() != null))
+ tfCallCommand.setText(tfHome.getText() +
+ (tfHome.getText().endsWith("/") ? "" : "/") +
+ "Sapfor_F");
+ }
+}
diff --git a/src/GlobalData/RunConfiguration/RunConfiguration.java b/src/GlobalData/RunConfiguration/RunConfiguration.java
new file mode 100644
index 00000000..8ea3fe01
--- /dev/null
+++ b/src/GlobalData/RunConfiguration/RunConfiguration.java
@@ -0,0 +1,270 @@
+package GlobalData.RunConfiguration;
+import Common.Current;
+import Common.Database.iDBObject;
+import Common.Global;
+import Common.Utils.TextLog;
+import Common.Utils.Utils;
+import GlobalData.Compiler.Compiler;
+import GlobalData.DVMParameter.DVMParameter;
+import GlobalData.EnvironmentValue.EnvironmentValue;
+import GlobalData.Tasks.CompilationTask.CompilationTask;
+import GlobalData.Tasks.RunTask.RunTask;
+import GlobalData.Tasks.TaskState;
+import ProjectData.Project.db_project_info;
+import Visual_DVM_2021.Passes.PassException;
+import com.sun.org.glassfish.gmbal.Description;
+
+import java.util.LinkedHashMap;
+import java.util.Vector;
+import java.util.stream.IntStream;
+public class RunConfiguration extends iDBObject {
+ public static final int maxProc = 16;
+ public int machine_id;
+ //---------------------------------------->
+ @Description("DEFAULT -1")
+ public int compiler_id = Utils.Nan;
+ public String LauncherCall = ""; //например DVM или mpirun
+ public String LauncherOptions = ""; //например run
+ //--------------------------------------
+ //---------------------------------------
+ //в случае mpi всегда одномерная. в случае DVM может быть многомерной
+ //------------------------>>
+ @Description("DEFAULT ''")
+ public String matrix = ""; //решетка. устаревшее поле.
+ //------------------------>>
+ @Description("DEFAULT ''")
+ public String minMatrix = "";
+ @Description("DEFAULT ''")
+ public String maxMatrix = "";
+ @Description("DEFAULT 0")
+ public int dim = 0;
+ @Description("DEFAULT 1")
+ public int cube = 1;
+ //------------------------>>
+ //аргументы командной строки - в линию- для запуска
+ public String args = ""; //аргументы КС
+ //---------------------------------------
+ @Description("DEFAULT 0")
+ public int gcov = 0; //совместимость. гков отныне только на локалке.
+ public static Vector getBounds(String bounds) {
+ String[] dims_ = bounds.split(" ");
+ Vector res = new Vector<>();
+ for (String dim_ : dims_) {
+ int dim = 1;
+ try {
+ dim = Integer.parseInt(dim_);
+ } catch (Exception ex) {
+ Global.Log.PrintException(ex);
+ }
+ res.add(dim);
+ }
+ return res;
+ }
+ public static boolean checkCube(Vector m) {
+ return IntStream.range(1, m.size()).allMatch(j -> m.get(j).equals(m.get(0)));
+ }
+ public static void gen_rec(Vector from, Vector to, Vector> res, int index, int dim_, boolean cube_) {
+ if (index < dim_) {
+ Vector> old = new Vector<>();
+ for (Vector L : res)
+ old.add(L);
+ res.clear();
+ for (int i = from.get(index); i <= to.get(index); ++i) {
+ for (Vector L : old) {
+ Vector buffer = new Vector<>(L);
+ buffer.add(i);
+ if (!cube_ || checkCube(buffer))
+ res.add(buffer);
+ }
+ }
+ gen_rec(from, to, res, index + 1, dim_, cube_);
+ }
+ }
+ //для окна конфигурации.
+ public static void validateMatrixes(String minMatrix_, String maxMatrix_, int dim_, boolean cube_, TextLog log) {
+ Vector> res_ = new Vector<>();
+ Vector res = new Vector<>();
+ if (dim_ > 0) {
+ Vector from = getBounds(minMatrix_);
+ Vector