diff --git a/.idea/artifacts/VisualSapfor_jar.xml b/.idea/artifacts/VisualSapfor_jar.xml new file mode 100644 index 00000000..c7a9ffa0 --- /dev/null +++ b/.idea/artifacts/VisualSapfor_jar.xml @@ -0,0 +1,16 @@ + + + $PROJECT_DIR$/Components + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..a55e7a17 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/dictionaries/misha.xml b/.idea/dictionaries/misha.xml new file mode 100644 index 00000000..adcecc0f --- /dev/null +++ b/.idea/dictionaries/misha.xml @@ -0,0 +1,54 @@ + + + + anchestor + borov + decl + declarated + decls + distr + dvmuser + enddo + existense + ffixed + ffree + formtype + freenas + gcda + gcno + gcov + gfortran + gotos + ident + identificators + inexisting + iter + jdbc + maxdeg + maxdim + maxtime + mcancel + mprit + mqtest + mtime + nigga + pppa + preproc + preprocessing + proj + sapfor + sapfors + slen + splited + sqlite + subdir + subdirs + templ + testuser + tripple + uniq + unparse + unselect + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..9caf446d --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/libraries/autocomplete_3_1_1_SNAPSHOT.xml b/.idea/libraries/autocomplete_3_1_1_SNAPSHOT.xml new file mode 100644 index 00000000..66eaaa94 --- /dev/null +++ b/.idea/libraries/autocomplete_3_1_1_SNAPSHOT.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/commons_io_2_5.xml b/.idea/libraries/commons_io_2_5.xml new file mode 100644 index 00000000..9a8678ca --- /dev/null +++ b/.idea/libraries/commons_io_2_5.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/gson_2_8_1.xml b/.idea/libraries/gson_2_8_1.xml new file mode 100644 index 00000000..1f3943b6 --- /dev/null +++ b/.idea/libraries/gson_2_8_1.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/jsch_0_1_55.xml b/.idea/libraries/jsch_0_1_55.xml new file mode 100644 index 00000000..f0ae23ec --- /dev/null +++ b/.idea/libraries/jsch_0_1_55.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/mail.xml b/.idea/libraries/mail.xml new file mode 100644 index 00000000..85082279 --- /dev/null +++ b/.idea/libraries/mail.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/mxgraphx_all_4_2_0.xml b/.idea/libraries/mxgraphx_all_4_2_0.xml new file mode 100644 index 00000000..c16eeefc --- /dev/null +++ b/.idea/libraries/mxgraphx_all_4_2_0.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/rsyntaxtextarea_3_0_5_SNAPSHOT.xml b/.idea/libraries/rsyntaxtextarea_3_0_5_SNAPSHOT.xml new file mode 100644 index 00000000..44e52fe8 --- /dev/null +++ b/.idea/libraries/rsyntaxtextarea_3_0_5_SNAPSHOT.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/sqlite_jdbc_3_7_2.xml b/.idea/libraries/sqlite_jdbc_3_7_2.xml new file mode 100644 index 00000000..c2a6df9c --- /dev/null +++ b/.idea/libraries/sqlite_jdbc_3_7_2.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..05483570 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..1675bddd --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 00000000..aabf42e9 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..94a25f7f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/visual_dvm_2020.iml b/.idea/visual_dvm_2020.iml new file mode 100644 index 00000000..d6ebd480 --- /dev/null +++ b/.idea/visual_dvm_2020.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 00000000..418e266f --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 getObjectsCopies(Class table_class, Vector keys) { + Vector res = new Vector<>(); + DBTable table = tables.get(table_class); + for (Object key : keys) + if (table.containsKey(key)) + res.add(table.Data.get(key)); + return res; + } + public void Delete(DBObject o) throws Exception { + DBTable table = tables.get(o.getClass()); + delete(table, o); + table.Data.remove(o.getPK()); + } + public void DeleteAll(Class c) throws Exception { + DBTable table = tables.get(c); + deleteAll(table); + table.Data.clear(); + } + //не вполне обычный случай. подразумевается что поле объекта изменено + //этот же метод закрепляет изменение в бд + //в дальнейшем возможно сделать новое значение поля 2 параметром метода? + public void Update(DBObject o) throws Exception { + DBTable table = tables.get(o.getClass()); + update(table, o); + } + public void ResetAI(Class c) throws Exception { + resetAI(tables.get(c)); + } + // + // + 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: + *

+     *      ...
+     *      MyCoolClass myObj = new MyCoolClass();
+     *      Transferable xfer = new TransferableObject( myObj );
+     *      ...
+     * 
+ * 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +