studium 0.18.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (821) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +3310 -0
  3. data/bin/all_passed_exams +14 -0
  4. data/bin/check_description_of_these_lectures +7 -0
  5. data/bin/curriculum_module_displayer +7 -0
  6. data/bin/cycle +7 -0
  7. data/bin/d10 +7 -0
  8. data/bin/d100 +7 -0
  9. data/bin/d15 +7 -0
  10. data/bin/d150 +7 -0
  11. data/bin/d20 +7 -0
  12. data/bin/d25 +7 -0
  13. data/bin/d3 +7 -0
  14. data/bin/d30 +7 -0
  15. data/bin/d5 +7 -0
  16. data/bin/determine_curricula +7 -0
  17. data/bin/display_lecture_url +7 -0
  18. data/bin/exam_registration_at +7 -0
  19. data/bin/exam_statistics +7 -0
  20. data/bin/exams_per_month +9 -0
  21. data/bin/finished_exams_at_this_university +7 -0
  22. data/bin/flashcards +7 -0
  23. data/bin/from_curriculum_id_to_university +9 -0
  24. data/bin/location_to_this_exam_topic.rb +7 -0
  25. data/bin/mandatory_continuous_assessment +7 -0
  26. data/bin/mandatory_upcoming_courses +10 -0
  27. data/bin/n_ECTS +7 -0
  28. data/bin/n_exam_questions_already_answered +15 -0
  29. data/bin/names_of_all_solved_exams +7 -0
  30. data/bin/not_completed_exams +7 -0
  31. data/bin/nquestions +7 -0
  32. data/bin/nsolved +7 -0
  33. data/bin/open_last_exam_question_asked_file +7 -0
  34. data/bin/passed_exams +7 -0
  35. data/bin/passed_pr/303/274fungsimmanente_courses +7 -0
  36. data/bin/passed_this_exam_on +10 -0
  37. data/bin/pdf_for +7 -0
  38. data/bin/question_answer +7 -0
  39. data/bin/random_exam_topic +7 -0
  40. data/bin/registered_for_this_exam +15 -0
  41. data/bin/report_solved_topics +7 -0
  42. data/bin/return_n_ects_from_this_file +7 -0
  43. data/bin/return_n_questions_solved_in_total +7 -0
  44. data/bin/rti_conflict +7 -0
  45. data/bin/search_for_n_ects +7 -0
  46. data/bin/show_lectures_on_the_commandline +7 -0
  47. data/bin/show_passed_exams_having_this_grade +7 -0
  48. data/bin/show_themes +7 -0
  49. data/bin/solved +9 -0
  50. data/bin/solved_ects +7 -0
  51. data/bin/studienkennzahl +7 -0
  52. data/bin/studium +7 -0
  53. data/bin/studium_actions +7 -0
  54. data/bin/studium_skeleton +7 -0
  55. data/bin/ufind +7 -0
  56. data/bin/upcoming_exams +7 -0
  57. data/bin/week_parser +7 -0
  58. data/doc/ECTS_CONSIDERATIONS/ECTS_CONSIDERATIONS.md +85 -0
  59. data/doc/HOW_TO_DETERMINE_WHICH_PART_IS_THE_QUESTION_AND_WHICH_PART_IS_THE_ANSWER/HOW_TO_DETERMINE_WHICH_PART_IS_THE_QUESTION_AND_WHICH_PART_IS_THE_ANSWER.md +44 -0
  60. data/doc/README.gen +3263 -0
  61. data/doc/SQL_database_specification/SQL_database_specification.md +46 -0
  62. data/doc/deprecated_components/deprecated_components.md +46 -0
  63. data/doc/documentation_for_the_file_lecture_information/documentation_for_the_file_lecture_information.md +311 -0
  64. data/doc/elegant_colours/elegant_colours.md +21 -0
  65. data/doc/statistics/yearly_statistics.md +8 -0
  66. data/doc/todo/todo_for_the_graphical_parts_of_the_studium_gem_including_www_related_aspects.md +92 -0
  67. data/doc/todo/todo_for_the_studium_gem.md +55 -0
  68. data/img/STUDIES.png +0 -0
  69. data/lib/studium/actions/actions.rb +134 -0
  70. data/lib/studium/autoinclude.rb +7 -0
  71. data/lib/studium/base/base.rb +3554 -0
  72. data/lib/studium/base/commandline_arguments_module/commandline_arguments_module.rb +115 -0
  73. data/lib/studium/base/html_colours_module.rb +632 -0
  74. data/lib/studium/base/runmode_module/runmode_module.rb +103 -0
  75. data/lib/studium/c/README.md +2 -0
  76. data/lib/studium/c/a.out +0 -0
  77. data/lib/studium/c/obtain_random_entry.c +11 -0
  78. data/lib/studium/check_and_sanitize/README.md +15 -0
  79. data/lib/studium/check_and_sanitize/check_curriculum_for_correct_separation_of_bachelor_and_master.rb +141 -0
  80. data/lib/studium/check_and_sanitize/check_for_all_exam_topics_being_registered.rb +118 -0
  81. data/lib/studium/check_and_sanitize/check_for_correct_themes_of_each_course.rb +100 -0
  82. data/lib/studium/check_and_sanitize/check_for_existing_description_of_this_lecture.rb +194 -0
  83. data/lib/studium/check_and_sanitize/check_important_exams.rb +138 -0
  84. data/lib/studium/check_and_sanitize/check_the_lecture_information_file.rb +166 -0
  85. data/lib/studium/check_and_sanitize/correct_all_dates_in_the_file_lecture_information.rb +115 -0
  86. data/lib/studium/check_and_sanitize/date_sanitizer.rb +350 -0
  87. data/lib/studium/check_and_sanitize/find_duplicate_lectures.rb +124 -0
  88. data/lib/studium/check_and_sanitize/missing_priority_entry.rb +44 -0
  89. data/lib/studium/check_and_sanitize/sanitize_lecture_information.rb +434 -0
  90. data/lib/studium/colours/colours.rb +1711 -0
  91. data/lib/studium/commandline/commandline.rb +1848 -0
  92. data/lib/studium/constants/constants.rb +2063 -0
  93. data/lib/studium/css/project.css +273 -0
  94. data/lib/studium/curricula/attribute_lecture_to_curriculum/attribute_boku_lecture_to_curriculum.rb +384 -0
  95. data/lib/studium/curricula/attribute_lecture_to_curriculum/attribute_lecture_to_curriculum.rb +238 -0
  96. data/lib/studium/curricula/curricula_from_this_website/curricula_from_this_website.rb +141 -0
  97. data/lib/studium/curricula/curriculum.rb +213 -0
  98. data/lib/studium/curricula/curriculum_as_string.rb +280 -0
  99. data/lib/studium/curricula/curriculum_module_displayer/constants.rb +33 -0
  100. data/lib/studium/curricula/curriculum_module_displayer/curriculum_module_displayer.rb +417 -0
  101. data/lib/studium/curricula/curriculum_module_displayer/initialize.rb +25 -0
  102. data/lib/studium/curricula/curriculum_module_displayer/menu.rb +45 -0
  103. data/lib/studium/curricula/curriculum_module_displayer/reset.rb +74 -0
  104. data/lib/studium/curricula/curriculum_module_displayer/run.rb +20 -0
  105. data/lib/studium/curricula/curriculum_module_displayer/set_use_this_curriculum.rb +93 -0
  106. data/lib/studium/curricula/curriculum_module_displayer/show_and_report.rb +190 -0
  107. data/lib/studium/curricula/determine_curricula/constants.rb +11 -0
  108. data/lib/studium/curricula/determine_curricula/determine_curricula.rb +36 -0
  109. data/lib/studium/curricula/determine_curricula/help.rb +39 -0
  110. data/lib/studium/curricula/determine_curricula/initialize.rb +48 -0
  111. data/lib/studium/curricula/determine_curricula/menu.rb +151 -0
  112. data/lib/studium/curricula/determine_curricula/misc.rb +403 -0
  113. data/lib/studium/curricula/determine_curricula/report.rb +141 -0
  114. data/lib/studium/curricula/determine_curricula/reset.rb +59 -0
  115. data/lib/studium/curricula/determine_curricula/run.rb +19 -0
  116. data/lib/studium/curricula/determine_elective_courses_in_this_curriculum.rb +112 -0
  117. data/lib/studium/curricula/display_bachelor_curricula.rb +90 -0
  118. data/lib/studium/curricula/handle_curricula/README.md +9 -0
  119. data/lib/studium/curricula/handle_curricula/handle_curricula.rb +99 -0
  120. data/lib/studium/curricula/handle_curricula/misc.rb +798 -0
  121. data/lib/studium/curricula/mitteilungsbl/303/244tter/mitteilungsbl/303/244tter.rb +323 -0
  122. data/lib/studium/curricula/modules/display_on_the_commandline.rb +319 -0
  123. data/lib/studium/curricula/modules/return_n_ects_in_this_module.rb +74 -0
  124. data/lib/studium/curricula/n_percent_solved_in_this_curriculum.rb +73 -0
  125. data/lib/studium/curricula/prepare_individual_curriculum.rb +304 -0
  126. data/lib/studium/curricula/random_curriculum_creator/random_curriculum_creator.rb +164 -0
  127. data/lib/studium/curricula/show_all_unfinished_courses_of_this_curriculum/show_all_unfinished_courses_of_this_curriculum.rb +116 -0
  128. data/lib/studium/curricula/show_lectures_of_this_curriculum.rb +114 -0
  129. data/lib/studium/curricula/show_lectures_of_this_curriculum_id/show_lectures_of_this_curriculum_id.rb +554 -0
  130. data/lib/studium/curricula/show_solved_percentage_among_the_registered_curricula.rb +87 -0
  131. data/lib/studium/curricula/sorted_individual_curricula.rb +121 -0
  132. data/lib/studium/ects/boku_ects_splitter.rb +128 -0
  133. data/lib/studium/ects/ects_per_university/ects_per_university.rb +179 -0
  134. data/lib/studium/ects/ects_scanner.rb +141 -0
  135. data/lib/studium/ects/ects_to_university_parser.rb +142 -0
  136. data/lib/studium/ects/last_entry_is_curriculum.rb +150 -0
  137. data/lib/studium/ects/n_ects_in_these_lectures.rb +196 -0
  138. data/lib/studium/ects/n_ects_points_in_mandatory_presence_courses.rb +47 -0
  139. data/lib/studium/ects/return_n_ects_from_this_file.rb +59 -0
  140. data/lib/studium/ects/return_n_ects_from_this_url.rb +197 -0
  141. data/lib/studium/ects/search_for_n_ects/search_for_n_ects.rb +719 -0
  142. data/lib/studium/ects/show_completed_ects_in_all_curricula.rb +245 -0
  143. data/lib/studium/ects/show_passed_credits_per_curriculum.rb +276 -0
  144. data/lib/studium/ects/simple_total_ects_points.rb +135 -0
  145. data/lib/studium/ects/solved_ects/constants.rb +19 -0
  146. data/lib/studium/ects/solved_ects/reset.rb +50 -0
  147. data/lib/studium/ects/solved_ects/solved_ects.rb +325 -0
  148. data/lib/studium/ects/solved_ects_per_university/reset.rb +25 -0
  149. data/lib/studium/ects/solved_ects_per_university/solved_ects_per_university.rb +116 -0
  150. data/lib/studium/ects/still_missing.rb +129 -0
  151. data/lib/studium/ects/sum_of_ects.rb +144 -0
  152. data/lib/studium/encoding/encoding.rb +109 -0
  153. data/lib/studium/exam_topics/RNAi_siRNA_and_miRNA +100 -0
  154. data/lib/studium/exam_topics/abfall_als_ressource +86 -0
  155. data/lib/studium/exam_topics/advanced_biochemistry +937 -0
  156. data/lib/studium/exam_topics/advanced_biotechnology +234 -0
  157. data/lib/studium/exam_topics/advanced_cellbiology +251 -0
  158. data/lib/studium/exam_topics/advanced_chemistry +547 -0
  159. data/lib/studium/exam_topics/advanced_immunology +225 -0
  160. data/lib/studium/exam_topics/advanced_microbiology +49 -0
  161. data/lib/studium/exam_topics/advanced_topics_in_plant_sciences +117 -0
  162. data/lib/studium/exam_topics/advanced_virology +273 -0
  163. data/lib/studium/exam_topics/ageing +154 -0
  164. data/lib/studium/exam_topics/agrar_ecology +67 -0
  165. data/lib/studium/exam_topics/agrarmarkt +73 -0
  166. data/lib/studium/exam_topics/agrarphysik +35 -0
  167. data/lib/studium/exam_topics/alcohols +30 -0
  168. data/lib/studium/exam_topics/algorithms +104 -0
  169. data/lib/studium/exam_topics/allergie +76 -0
  170. data/lib/studium/exam_topics/allgemeine_genetik +1006 -0
  171. data/lib/studium/exam_topics/allgemeine_mikrobiologie +1012 -0
  172. data/lib/studium/exam_topics/aminoacids +469 -0
  173. data/lib/studium/exam_topics/analytische_chemie_1 +134 -0
  174. data/lib/studium/exam_topics/analytische_chemie_2 +31 -0
  175. data/lib/studium/exam_topics/anatomie +378 -0
  176. data/lib/studium/exam_topics/anorganische_chemie +357 -0
  177. data/lib/studium/exam_topics/anthropologie +239 -0
  178. data/lib/studium/exam_topics/antibodies_and_antigens +790 -0
  179. data/lib/studium/exam_topics/apoptosis +35 -0
  180. data/lib/studium/exam_topics/archaea +112 -0
  181. data/lib/studium/exam_topics/archaeo_viruses +7 -0
  182. data/lib/studium/exam_topics/archaeology +5 -0
  183. data/lib/studium/exam_topics/architecture +8 -0
  184. data/lib/studium/exam_topics/artificial_intelligence +90 -0
  185. data/lib/studium/exam_topics/atomemissionsspektrometrie +6 -0
  186. data/lib/studium/exam_topics/audio +11 -0
  187. data/lib/studium/exam_topics/bacteriophages +266 -0
  188. data/lib/studium/exam_topics/basic_biochemistry +1008 -0
  189. data/lib/studium/exam_topics/basic_biotechnology +1011 -0
  190. data/lib/studium/exam_topics/basic_chemistry +1007 -0
  191. data/lib/studium/exam_topics/basic_virology +1008 -0
  192. data/lib/studium/exam_topics/bauwesen +6 -0
  193. data/lib/studium/exam_topics/betriebssysteme +128 -0
  194. data/lib/studium/exam_topics/betriebswirtschaftslehre +29 -0
  195. data/lib/studium/exam_topics/bioanalytik_und_biosensoren +451 -0
  196. data/lib/studium/exam_topics/biochips +80 -0
  197. data/lib/studium/exam_topics/bioelektrochemie +57 -0
  198. data/lib/studium/exam_topics/biofilms +58 -0
  199. data/lib/studium/exam_topics/bioinformatics +523 -0
  200. data/lib/studium/exam_topics/biological_therapeutics +156 -0
  201. data/lib/studium/exam_topics/biologie +152 -0
  202. data/lib/studium/exam_topics/biomarkers +137 -0
  203. data/lib/studium/exam_topics/biomaterials +90 -0
  204. data/lib/studium/exam_topics/biomedical_studies +16 -0
  205. data/lib/studium/exam_topics/biomembranes +6 -0
  206. data/lib/studium/exam_topics/bionik +65 -0
  207. data/lib/studium/exam_topics/biophysik +34 -0
  208. data/lib/studium/exam_topics/biopolymers +10 -0
  209. data/lib/studium/exam_topics/bioprozesstechnik +149 -0
  210. data/lib/studium/exam_topics/bioressourcenmanagement +78 -0
  211. data/lib/studium/exam_topics/birds +5 -0
  212. data/lib/studium/exam_topics/bodenkunde +384 -0
  213. data/lib/studium/exam_topics/bodenmikrobiologie +40 -0
  214. data/lib/studium/exam_topics/cancerbiology +488 -0
  215. data/lib/studium/exam_topics/cell_cultures +229 -0
  216. data/lib/studium/exam_topics/cellbiology +1011 -0
  217. data/lib/studium/exam_topics/cellular_transport_and_protein_secretion +27 -0
  218. data/lib/studium/exam_topics/cellular_vesicles +11 -0
  219. data/lib/studium/exam_topics/cellulose +6 -0
  220. data/lib/studium/exam_topics/chemische_technologie_anorganischer_stoffe +210 -0
  221. data/lib/studium/exam_topics/chemische_technologie_organischer_stoffe +25 -0
  222. data/lib/studium/exam_topics/chemisches_labor +60 -0
  223. data/lib/studium/exam_topics/chemokines_and_cytokines +45 -0
  224. data/lib/studium/exam_topics/chemotaxis_quorum_sensing_and_motility_in_prokaryotes +116 -0
  225. data/lib/studium/exam_topics/citric_acid_cycle +84 -0
  226. data/lib/studium/exam_topics/clinical_microbiology +520 -0
  227. data/lib/studium/exam_topics/computer_science +309 -0
  228. data/lib/studium/exam_topics/computer_vision_and_computer_graphics +15 -0
  229. data/lib/studium/exam_topics/crispr +51 -0
  230. data/lib/studium/exam_topics/cyanobacteria +45 -0
  231. data/lib/studium/exam_topics/cytogenetics_and_chromosome_biology +598 -0
  232. data/lib/studium/exam_topics/databases_and_sql +126 -0
  233. data/lib/studium/exam_topics/dna_mutation_and_dna_repair +186 -0
  234. data/lib/studium/exam_topics/dna_replication +80 -0
  235. data/lib/studium/exam_topics/ecogenetics +26 -0
  236. data/lib/studium/exam_topics/ecological_agriculture +12 -0
  237. data/lib/studium/exam_topics/ecology +332 -0
  238. data/lib/studium/exam_topics/economy +226 -0
  239. data/lib/studium/exam_topics/electron_microscopy +7 -0
  240. data/lib/studium/exam_topics/elektronenmikroskopie +356 -0
  241. data/lib/studium/exam_topics/elektrophorese +132 -0
  242. data/lib/studium/exam_topics/elektrotechnik_und_elektrizit/303/244t +42 -0
  243. data/lib/studium/exam_topics/elisa +55 -0
  244. data/lib/studium/exam_topics/embryologie_und_entwicklung +657 -0
  245. data/lib/studium/exam_topics/endospores_and_spores +104 -0
  246. data/lib/studium/exam_topics/enzymes_and_cofactors +395 -0
  247. data/lib/studium/exam_topics/epigenetik +188 -0
  248. data/lib/studium/exam_topics/erste_hilfe +414 -0
  249. data/lib/studium/exam_topics/ethik +143 -0
  250. data/lib/studium/exam_topics/evolution_and_evolutionary_genetics +372 -0
  251. data/lib/studium/exam_topics/excel +7 -0
  252. data/lib/studium/exam_topics/fish +19 -0
  253. data/lib/studium/exam_topics/fluorescence_microscopy +10 -0
  254. data/lib/studium/exam_topics/food_microbiology_and_food_biotechnology +92 -0
  255. data/lib/studium/exam_topics/forensik +65 -0
  256. data/lib/studium/exam_topics/forstwirtschaft +53 -0
  257. data/lib/studium/exam_topics/fortgeschrittene_genetik +692 -0
  258. data/lib/studium/exam_topics/fortgeschrittene_gentechnik +221 -0
  259. data/lib/studium/exam_topics/fortgeschrittene_physik +6 -0
  260. data/lib/studium/exam_topics/fungi +119 -0
  261. data/lib/studium/exam_topics/genetische_krankheiten +209 -0
  262. data/lib/studium/exam_topics/genexpression +1008 -0
  263. data/lib/studium/exam_topics/genomics_and_metagenomics +290 -0
  264. data/lib/studium/exam_topics/gentechnik_und_praktische_biochemie +961 -0
  265. data/lib/studium/exam_topics/geochemistry +67 -0
  266. data/lib/studium/exam_topics/geography +9 -0
  267. data/lib/studium/exam_topics/geologie_und_mineralogie +624 -0
  268. data/lib/studium/exam_topics/geometrie +56 -0
  269. data/lib/studium/exam_topics/geschichte +95 -0
  270. data/lib/studium/exam_topics/gluconeogenesis +72 -0
  271. data/lib/studium/exam_topics/glycogen +45 -0
  272. data/lib/studium/exam_topics/glycolysis +118 -0
  273. data/lib/studium/exam_topics/glykomik +131 -0
  274. data/lib/studium/exam_topics/glyoxylatzyklus +31 -0
  275. data/lib/studium/exam_topics/grassland_cultivation +32 -0
  276. data/lib/studium/exam_topics/hormone +152 -0
  277. data/lib/studium/exam_topics/html +8 -0
  278. data/lib/studium/exam_topics/human_ecology +8 -0
  279. data/lib/studium/exam_topics/hygiene +224 -0
  280. data/lib/studium/exam_topics/imaging_and_microscopy +270 -0
  281. data/lib/studium/exam_topics/immunanalytik +94 -0
  282. data/lib/studium/exam_topics/immunologie +1011 -0
  283. data/lib/studium/exam_topics/informatik +117 -0
  284. data/lib/studium/exam_topics/innate_immunity +52 -0
  285. data/lib/studium/exam_topics/insekten +66 -0
  286. data/lib/studium/exam_topics/insulin_and_diabetes +57 -0
  287. data/lib/studium/exam_topics/java +624 -0
  288. data/lib/studium/exam_topics/javascript +29 -0
  289. data/lib/studium/exam_topics/klima +6 -0
  290. data/lib/studium/exam_topics/kryptographie +10 -0
  291. data/lib/studium/exam_topics/landtechnik +26 -0
  292. data/lib/studium/exam_topics/lebensmittel_und_getr/303/244nke +224 -0
  293. data/lib/studium/exam_topics/lebensmitteltechnologie +16 -0
  294. data/lib/studium/exam_topics/light_microscopy +19 -0
  295. data/lib/studium/exam_topics/linux_and_unix +36 -0
  296. data/lib/studium/exam_topics/lipids +145 -0
  297. data/lib/studium/exam_topics/macroeconomics +39 -0
  298. data/lib/studium/exam_topics/marketing +53 -0
  299. data/lib/studium/exam_topics/mathematics +311 -0
  300. data/lib/studium/exam_topics/medizin_und_biomedizinische_technik +254 -0
  301. data/lib/studium/exam_topics/medizinische_chemie_und_pharmazie +441 -0
  302. data/lib/studium/exam_topics/messtechnik_und_regeltechnik +104 -0
  303. data/lib/studium/exam_topics/metabolismus +482 -0
  304. data/lib/studium/exam_topics/meteorologie_und_atmosph/303/244re +120 -0
  305. data/lib/studium/exam_topics/microbial_ecology +37 -0
  306. data/lib/studium/exam_topics/microcontrollers +11 -0
  307. data/lib/studium/exam_topics/mikrobielle_lebensgemeinschaften +58 -0
  308. data/lib/studium/exam_topics/mikrobielle_physiologie +313 -0
  309. data/lib/studium/exam_topics/mitochondria +57 -0
  310. data/lib/studium/exam_topics/mixed +287 -0
  311. data/lib/studium/exam_topics/molecular_biology_of_plants +281 -0
  312. data/lib/studium/exam_topics/molekulare_medizin +133 -0
  313. data/lib/studium/exam_topics/nanotechnologie +456 -0
  314. data/lib/studium/exam_topics/nature_conservation_and_biodiversity +247 -0
  315. data/lib/studium/exam_topics/naturstoffe +9 -0
  316. data/lib/studium/exam_topics/netzwerke +63 -0
  317. data/lib/studium/exam_topics/neuroanatomie +25 -0
  318. data/lib/studium/exam_topics/neurobiology +356 -0
  319. data/lib/studium/exam_topics/nucleotide_sequencing +41 -0
  320. data/lib/studium/exam_topics/nutztierethologie +11 -0
  321. data/lib/studium/exam_topics/object_oriented_modeling +15 -0
  322. data/lib/studium/exam_topics/obstbau +249 -0
  323. data/lib/studium/exam_topics/organische_chemie +1007 -0
  324. data/lib/studium/exam_topics/organische_chemie_2 +137 -0
  325. data/lib/studium/exam_topics/paleobiology +39 -0
  326. data/lib/studium/exam_topics/parasitic_diseases_and_molecular_infection_biology +336 -0
  327. data/lib/studium/exam_topics/patent_law +55 -0
  328. data/lib/studium/exam_topics/pathologie +761 -0
  329. data/lib/studium/exam_topics/pcr +155 -0
  330. data/lib/studium/exam_topics/pentosephosphatweg +61 -0
  331. data/lib/studium/exam_topics/peroxisomes_glycosomes_and_lysosomes +66 -0
  332. data/lib/studium/exam_topics/pflanzenanatomie +262 -0
  333. data/lib/studium/exam_topics/pflanzenbau +24 -0
  334. data/lib/studium/exam_topics/pflanzenschutz +35 -0
  335. data/lib/studium/exam_topics/pflanzenwissenschaften +1009 -0
  336. data/lib/studium/exam_topics/pharmaceutical_biotechnology +252 -0
  337. data/lib/studium/exam_topics/physik +449 -1
  338. data/lib/studium/exam_topics/physikalische_chemie +79 -0
  339. data/lib/studium/exam_topics/physiology_and_histology +592 -0
  340. data/lib/studium/exam_topics/phytochemie +33 -0
  341. data/lib/studium/exam_topics/plant_biotechnology +132 -0
  342. data/lib/studium/exam_topics/plant_breeding +64 -0
  343. data/lib/studium/exam_topics/plant_development +50 -0
  344. data/lib/studium/exam_topics/populationsgenetik +143 -0
  345. data/lib/studium/exam_topics/posttranslationale_modifikation_von_proteinen +198 -0
  346. data/lib/studium/exam_topics/programming +41 -0
  347. data/lib/studium/exam_topics/projektmanagement +226 -0
  348. data/lib/studium/exam_topics/prokaryote_genetics +587 -0
  349. data/lib/studium/exam_topics/protein_engineering +35 -0
  350. data/lib/studium/exam_topics/proteolyse +39 -0
  351. data/lib/studium/exam_topics/proteomik +42 -0
  352. data/lib/studium/exam_topics/protozoans +24 -0
  353. data/lib/studium/exam_topics/prozesstechnik +95 -0
  354. data/lib/studium/exam_topics/psychologie +21 -0
  355. data/lib/studium/exam_topics/python +391 -0
  356. data/lib/studium/exam_topics/quality_management +266 -0
  357. data/lib/studium/exam_topics/rechtsgrundlagen +126 -0
  358. data/lib/studium/exam_topics/research_topics_in_immunobiology +42 -0
  359. data/lib/studium/exam_topics/rna_and_dna +535 -0
  360. data/lib/studium/exam_topics/rna_seq +13 -0
  361. data/lib/studium/exam_topics/robotics +12 -0
  362. data/lib/studium/exam_topics/ruby +240 -0
  363. data/lib/studium/exam_topics/ruby_on_rails +63 -0
  364. data/lib/studium/exam_topics/scientific_writing_and_publishing +38 -0
  365. data/lib/studium/exam_topics/semisynthese_von_proteinen_und_nukleotiden +120 -0
  366. data/lib/studium/exam_topics/sexualbiologie +327 -0
  367. data/lib/studium/exam_topics/signal_transduction_and_laser_systems +215 -0
  368. data/lib/studium/exam_topics/sozialbiologie +17 -0
  369. data/lib/studium/exam_topics/soziologie +5 -0
  370. data/lib/studium/exam_topics/splicing_exons_and_introns +67 -0
  371. data/lib/studium/exam_topics/sport_und_sportverletzungen +6 -0
  372. data/lib/studium/exam_topics/statistik +306 -0
  373. data/lib/studium/exam_topics/stemcells +182 -0
  374. data/lib/studium/exam_topics/stickstofffixierung +91 -0
  375. data/lib/studium/exam_topics/structural_bioinformatics +54 -0
  376. data/lib/studium/exam_topics/strukturbiologie +445 -0
  377. data/lib/studium/exam_topics/system_biology_and_synthetic_biology +108 -0
  378. data/lib/studium/exam_topics/systematische_zoologie +446 -0
  379. data/lib/studium/exam_topics/technical_ecology +144 -0
  380. data/lib/studium/exam_topics/technik +5 -0
  381. data/lib/studium/exam_topics/technische_chemie +208 -0
  382. data/lib/studium/exam_topics/technische_grundlagen_der_informatik +43 -0
  383. data/lib/studium/exam_topics/technische_mikrobiologie +393 -0
  384. data/lib/studium/exam_topics/technisches_zeichnen +5 -0
  385. data/lib/studium/exam_topics/the_bacterial_cell_wall +98 -0
  386. data/lib/studium/exam_topics/the_c_plus_plus_programming_language +531 -0
  387. data/lib/studium/exam_topics/the_c_programming_language +133 -0
  388. data/lib/studium/exam_topics/the_cellcycle +102 -0
  389. data/lib/studium/exam_topics/the_european_union +121 -0
  390. data/lib/studium/exam_topics/the_interferon_system +40 -0
  391. data/lib/studium/exam_topics/the_microbiome +164 -0
  392. data/lib/studium/exam_topics/the_universe +32 -0
  393. data/lib/studium/exam_topics/theoretische_chemie +5 -0
  394. data/lib/studium/exam_topics/theoretische_informatik +161 -0
  395. data/lib/studium/exam_topics/thermodynamics +21 -0
  396. data/lib/studium/exam_topics/tierzucht +139 -0
  397. data/lib/studium/exam_topics/toxikologie +508 -0
  398. data/lib/studium/exam_topics/transcription +188 -0
  399. data/lib/studium/exam_topics/translation_ribosomes_and_translational_control +155 -0
  400. data/lib/studium/exam_topics/umweltbiotechnologie +64 -0
  401. data/lib/studium/exam_topics/umweltchemie +233 -0
  402. data/lib/studium/exam_topics/urbanism_and_traffic +19 -0
  403. data/lib/studium/exam_topics/urea_cycle +56 -0
  404. data/lib/studium/exam_topics/vaccines_and_vaccination +253 -0
  405. data/lib/studium/exam_topics/vectors_and_gene_therapy +247 -0
  406. data/lib/studium/exam_topics/verfahrenstechnik +37 -0
  407. data/lib/studium/exam_topics/verhaltensbiologie +79 -0
  408. data/lib/studium/exam_topics/veterinary_medicine +10 -0
  409. data/lib/studium/exam_topics/vitamine +32 -0
  410. data/lib/studium/exam_topics/wasserkunde +144 -0
  411. data/lib/studium/exam_topics/weinbau +86 -0
  412. data/lib/studium/exam_topics/wissenschaft +20 -0
  413. data/lib/studium/exam_topics/yeast +104 -0
  414. data/lib/studium/exam_topics/zoologie +338 -0
  415. data/lib/studium/exams/afterburn/afterburn.rb +304 -0
  416. data/lib/studium/exams/ask_exam_from_the_upcoming_exams_pool.rb +150 -0
  417. data/lib/studium/exams/ask_exam_topic_question.rb +112 -0
  418. data/lib/studium/exams/ask_question_from_alias.rb +141 -0
  419. data/lib/studium/exams/ask_question_from_any_of_the_still_missing_lectures.rb +130 -0
  420. data/lib/studium/exams/ask_question_from_grouped_themes.rb +141 -0
  421. data/lib/studium/exams/ask_question_from_last_topic.rb +91 -0
  422. data/lib/studium/exams/ask_random_question.rb +195 -0
  423. data/lib/studium/exams/autoinclude.rb +7 -0
  424. data/lib/studium/exams/average_grade/average_grade.rb +404 -0
  425. data/lib/studium/exams/csv/create_csv_passed_exams_file.rb +217 -0
  426. data/lib/studium/exams/cycle.rb +291 -0
  427. data/lib/studium/exams/dataset/dataset.rb +126 -0
  428. data/lib/studium/exams/designate_ten_random_exam_topics/designate_ten_random_exam_topics.rb +88 -0
  429. data/lib/studium/exams/exam/exam.rb +130 -0
  430. data/lib/studium/exams/exam_bubble/exam_bubble.rb +444 -0
  431. data/lib/studium/exams/exam_bubble/menu_for_the_main_loop.rb +111 -0
  432. data/lib/studium/exams/exam_question/README.md +3 -0
  433. data/lib/studium/exams/exam_question/exam_question.rb +434 -0
  434. data/lib/studium/exams/exam_registration_at/constants.rb +49 -0
  435. data/lib/studium/exams/exam_registration_at/exam_registration_at.rb +242 -0
  436. data/lib/studium/exams/exam_registration_at/help.rb +46 -0
  437. data/lib/studium/exams/exam_registration_at/menu.rb +81 -0
  438. data/lib/studium/exams/exam_registration_at/report_and_show.rb +133 -0
  439. data/lib/studium/exams/exam_registration_at/reset.rb +54 -0
  440. data/lib/studium/exams/exam_statistics_from_this_file/exam_statistics_from_this_file.rb +119 -0
  441. data/lib/studium/exams/exam_topics.rb +194 -0
  442. data/lib/studium/exams/exams.rb +20 -0
  443. data/lib/studium/exams/exams_per_month/exams_per_month.rb +2442 -0
  444. data/lib/studium/exams/exams_this_week.rb +182 -0
  445. data/lib/studium/exams/fix_exam_dates.rb +121 -0
  446. data/lib/studium/exams/frozen.rb +36 -0
  447. data/lib/studium/exams/last_exams/last_exams.rb +479 -0
  448. data/lib/studium/exams/lectures_without_exam_entry.rb +137 -0
  449. data/lib/studium/exams/mandatory_continuous_assessment/mandatory_continuous_assessment.rb +1358 -0
  450. data/lib/studium/exams/move_all_unsolved_exam_questions_to_the_top_of_the_file.rb +173 -0
  451. data/lib/studium/exams/move_the_last_exam_question_to_the_top_of_the_file/move_the_last_exam_question_to_the_top_of_the_file.rb +111 -0
  452. data/lib/studium/exams/n_exams_in_these_topics.rb +477 -0
  453. data/lib/studium/exams/next_exam.rb +106 -0
  454. data/lib/studium/exams/next_exams.rb +378 -0
  455. data/lib/studium/exams/not_completed/README.md +5 -0
  456. data/lib/studium/exams/not_completed/not_completed.rb +143 -0
  457. data/lib/studium/exams/open_exam_associated_url/open_exam_associated_url.rb +154 -0
  458. data/lib/studium/exams/open_last_exam_question_asked_file/constants.rb +15 -0
  459. data/lib/studium/exams/open_last_exam_question_asked_file/initialize.rb +29 -0
  460. data/lib/studium/exams/open_last_exam_question_asked_file/open_last_exam_question_asked_file.rb +110 -0
  461. data/lib/studium/exams/push_solved_questions_on_top.rb +180 -0
  462. data/lib/studium/exams/question_answer/question_answer.rb +2936 -0
  463. data/lib/studium/exams/questions_solved_from_day_to_day/questions_solved_from_day_to_day.rb +379 -0
  464. data/lib/studium/exams/remote_ftp_url.rb +52 -0
  465. data/lib/studium/exams/repeat_last_question.rb +78 -0
  466. data/lib/studium/exams/report_total_amount_of_questions_and_answers_for.rb +116 -0
  467. data/lib/studium/exams/show_all_passed_exams_of_this_university.rb +252 -0
  468. data/lib/studium/exams/show_backlog_of_exams/show_backlog_of_exams.rb +114 -0
  469. data/lib/studium/exams/show_exams_for/show_exams_for.rb +172 -0
  470. data/lib/studium/exams/show_themes/constants.rb +28 -0
  471. data/lib/studium/exams/show_themes/menu.rb +61 -0
  472. data/lib/studium/exams/show_themes/misc.rb +538 -0
  473. data/lib/studium/exams/show_themes/reset.rb +62 -0
  474. data/lib/studium/exams/show_themes/show_themes.rb +27 -0
  475. data/lib/studium/exams/show_upcoming_exams/show_upcoming_exams.rb +1537 -0
  476. data/lib/studium/exams/solve_all_questions_from_this_topic.rb +114 -0
  477. data/lib/studium/exams/solved/solved.rb +434 -0
  478. data/lib/studium/exams/timetable/constants.rb +142 -0
  479. data/lib/studium/exams/timetable/timetable.rb +448 -0
  480. data/lib/studium/exams/unsolve_all_questions_from_this_topic.rb +163 -0
  481. data/lib/studium/exams/upcoming_exams/upcoming_exams.rb +555 -0
  482. data/lib/studium/exams/upcoming_exams_at_the_boku/constants.rb +23 -0
  483. data/lib/studium/exams/upcoming_exams_at_the_boku/html.rb +64 -0
  484. data/lib/studium/exams/upcoming_exams_at_the_boku/upcoming_exams_at_the_boku.rb +194 -0
  485. data/lib/studium/exams/upcoming_exams_dataset.rb +247 -0
  486. data/lib/studium/exams/upcoming_registered_exams/upcoming_registered_exams.rb +257 -0
  487. data/lib/studium/exams/upload_exam_topics.rb +360 -0
  488. data/lib/studium/graphviz/README.md +4 -0
  489. data/lib/studium/graphviz/bachelor_vector_based_strategies.dot +160 -0
  490. data/lib/studium/graphviz/master_vector_based_strategies.dot +46 -0
  491. data/lib/studium/gui/gtk3/control_panel/control_panel.rb +40 -0
  492. data/lib/studium/gui/gtk3/lecture_information/lecture_information.rb +191 -0
  493. data/lib/studium/gui/java/exam_question/ExamQuestion$1.class +0 -0
  494. data/lib/studium/gui/java/exam_question/ExamQuestion.class +0 -0
  495. data/lib/studium/gui/java/exam_question/ExamQuestion.java +215 -0
  496. data/lib/studium/gui/javafx/exam_question_widget/exam_question_widget.rb +58 -0
  497. data/lib/studium/gui/jruby/exam_trainer/exam_trainer.rb +637 -0
  498. data/lib/studium/gui/jruby/show_upcoming_exams/show_upcoming_exams.rb +85 -0
  499. data/lib/studium/gui/libui/ask_exam_question/ask_exam_question.rb +347 -0
  500. data/lib/studium/gui/shared_code/control_panel/control_panel_module.rb +305 -0
  501. data/lib/studium/gui/shared_code/exam_trainer/exam_trainer_widget_module.rb +0 -0
  502. data/lib/studium/gui/shared_code/information_about_a_lecture/information_about_a_lecture_module.rb +0 -0
  503. data/lib/studium/gui/shared_code/show_upcoming_exams/show_upcoming_exams_module.rb +129 -0
  504. data/lib/studium/gui/universal_widgets/curriculum_viewer/curriculum_viewer.rb +549 -0
  505. data/lib/studium/gui/universal_widgets/ects_per_university/ects_per_university.rb +302 -0
  506. data/lib/studium/gui/universal_widgets/exam_trainer/exam_trainer.config +6 -0
  507. data/lib/studium/gui/universal_widgets/exam_trainer/exam_trainer.rb +3266 -0
  508. data/lib/studium/gui/universal_widgets/exam_trainer/manifest.yml +12 -0
  509. data/lib/studium/gui/universal_widgets/expand_time_range/expand_time_range.rb +309 -0
  510. data/lib/studium/gui/universal_widgets/information_about_a_lecture/information_about_a_lecture.rb +242 -0
  511. data/lib/studium/gui/universal_widgets/show_upcoming_exams/show_upcoming_exams.rb +252 -0
  512. data/lib/studium/images/libui_ask_exam_question.png +0 -0
  513. data/lib/studium/images/outdated.png +0 -0
  514. data/lib/studium/images/small_logos/DNA.png +0 -0
  515. data/lib/studium/images/small_logos/README.md +2 -0
  516. data/lib/studium/images/small_logos/solved.png +0 -0
  517. data/lib/studium/images/studies_favicon.png +0 -0
  518. data/lib/studium/java/README.md +5 -0
  519. data/lib/studium/java/studium/AskExamQuestion.java +461 -0
  520. data/lib/studium/java/studium/Base.java +123 -0
  521. data/lib/studium/java/studium/Constants.java +122 -0
  522. data/lib/studium/java/studium/EnsureThatTheLogDirectoryExists.java +57 -0
  523. data/lib/studium/java/studium/Mkdir.java +13 -0
  524. data/lib/studium/java/studium/OpenLastExamQuestionurlLinkViaTheBrowser.java +90 -0
  525. data/lib/studium/java/studium/ReturnNQuestionsSolvedInTotal.java +69 -0
  526. data/lib/studium/java/studium/Solved.java +112 -0
  527. data/lib/studium/java/studium/Test.java +60 -0
  528. data/lib/studium/java/studium/studium/AskExamQuestion.class +0 -0
  529. data/lib/studium/java/studium/studium/Base.class +0 -0
  530. data/lib/studium/java/studium/studium/Constants.class +0 -0
  531. data/lib/studium/java/studium/studium/EnsureThatTheLogDirectoryExists.class +0 -0
  532. data/lib/studium/java/studium/studium/Mkdir.class +0 -0
  533. data/lib/studium/java/studium/studium/OpenLastExamQuestionurlLinkViaTheBrowser.class +0 -0
  534. data/lib/studium/java/studium/studium/ReturnNQuestionsSolvedInTotal.class +0 -0
  535. data/lib/studium/java/studium/studium/Solved.class +0 -0
  536. data/lib/studium/java/studium/studium/Test.class +0 -0
  537. data/lib/studium/jobs/jobs.rb +80 -0
  538. data/lib/studium/logging/README.md +2 -0
  539. data/lib/studium/logging/ensure_that_the_log_directory_exists.rb +58 -0
  540. data/lib/studium/logging/html_log_directory.rb +42 -0
  541. data/lib/studium/logging/log_directory.rb +112 -0
  542. data/lib/studium/logging/store_last_question_asked_into_file.rb +138 -0
  543. data/lib/studium/parsers/README.md +2 -0
  544. data/lib/studium/parsers/custom_exam_results_parser.rb +209 -0
  545. data/lib/studium/parsers/parse_remote_lecture.rb +331 -0
  546. data/lib/studium/project/project.rb +88 -0
  547. data/lib/studium/requires/common_popular_requires.rb +37 -0
  548. data/lib/studium/requires/commonly_used_requires.rb +14 -0
  549. data/lib/studium/requires/require_class_exams_solved.rb +7 -0
  550. data/lib/studium/requires/require_ects_scripts.rb +27 -0
  551. data/lib/studium/requires/require_encoding.rb +7 -0
  552. data/lib/studium/requires/require_the_check_and_sanitize_files.rb +31 -0
  553. data/lib/studium/requires/require_the_curricula_files.rb +28 -0
  554. data/lib/studium/requires/require_the_exam_question_class.rb +7 -0
  555. data/lib/studium/requires/require_the_exams_files.rb +46 -0
  556. data/lib/studium/requires/require_the_logging_files.rb +23 -0
  557. data/lib/studium/requires/require_the_parsers.rb +28 -0
  558. data/lib/studium/requires/require_the_studium_constants.rb +7 -0
  559. data/lib/studium/requires/require_the_studium_project.rb +72 -0
  560. data/lib/studium/requires/require_the_toplevel_methods.rb +27 -0
  561. data/lib/studium/requires/require_the_utility_scripts.rb +34 -0
  562. data/lib/studium/requires/require_upcoming_exams.rb +7 -0
  563. data/lib/studium/requires/require_yaml.rb +7 -0
  564. data/lib/studium/requires/return_remote_homepage_of_this_lecture.rb +7 -0
  565. data/lib/studium/requires/with_GUI.rb +13 -0
  566. data/lib/studium/requires/www_mode.rb +17 -0
  567. data/lib/studium/statistics/README.md +4 -0
  568. data/lib/studium/statistics/best_exam_months.rb +92 -0
  569. data/lib/studium/statistics/curriculum_comparer/curriculum_comparer.rb +423 -0
  570. data/lib/studium/statistics/determine_exam_statistics_from_this_file.rb +142 -0
  571. data/lib/studium/statistics/exam_topics_that_are_about_to_be_completed.rb +117 -0
  572. data/lib/studium/statistics/max_stats.rb +169 -0
  573. data/lib/studium/statistics/new_questions_per_year.rb +147 -0
  574. data/lib/studium/statistics/report_how_many_ects_points_per_curriculum_were_completed.rb +167 -0
  575. data/lib/studium/statistics/report_how_many_exam_questions_were_answered.rb +473 -0
  576. data/lib/studium/statistics/show_exam_statistics.rb +75 -0
  577. data/lib/studium/statistics/show_which_courses_are_in_a_bachelor_or_master_curriculum_respectively.rb +104 -0
  578. data/lib/studium/statistics/top_stats.rb +126 -0
  579. data/lib/studium/toplevel_methods/e_and_esystem.rb +34 -0
  580. data/lib/studium/toplevel_methods/find_exam_topic_and_exam_title.rb +3986 -0
  581. data/lib/studium/toplevel_methods/install_the_project_on_the_given_hostsystem.rb +31 -0
  582. data/lib/studium/toplevel_methods/return_remote_homepage_of_this_lecture.rb +11611 -0
  583. data/lib/studium/toplevel_methods/return_remote_moodle_link_of_this_lecture.rb +2405 -0
  584. data/lib/studium/toplevel_methods/roebe.rb +16 -0
  585. data/lib/studium/toplevel_methods/runmode.rb +45 -0
  586. data/lib/studium/toplevel_methods/toplevel_methods.rb +7295 -0
  587. data/lib/studium/universities_in_austria/README.md +2 -0
  588. data/lib/studium/universities_in_austria/boku/README.md +4 -0
  589. data/lib/studium/universities_in_austria/boku/boku_/303/266ffnungszeiten.rb +28 -0
  590. data/lib/studium/universities_in_austria/boku/show_three_pillars_of_these_lectures.rb +110 -0
  591. data/lib/studium/universities_in_austria/boku/three_pillars.rb +237 -0
  592. data/lib/studium/universities_in_austria/tu_vienna/README.md +6 -0
  593. data/lib/studium/universities_in_austria/tu_vienna/tu_ferien.rb +42 -0
  594. data/lib/studium/universities_in_austria/tu_vienna/tu_/303/266ffnungszeiten.rb +34 -0
  595. data/lib/studium/university_course/university_course.rb +409 -0
  596. data/lib/studium/utility_scripts/attribute_lectures_to_university/attribute_lectures_to_university.rb +375 -0
  597. data/lib/studium/utility_scripts/audio_stats.rb +171 -0
  598. data/lib/studium/utility_scripts/auto_stud/auto_stud.rb +252 -0
  599. data/lib/studium/utility_scripts/auto_stud/constants.rb +18 -0
  600. data/lib/studium/utility_scripts/auto_stud/initialize.rb +23 -0
  601. data/lib/studium/utility_scripts/auto_stud/misc.rb +18 -0
  602. data/lib/studium/utility_scripts/autogeneration/autogeneration.rb +158 -0
  603. data/lib/studium/utility_scripts/autopurge_this_lecture_date.rb +100 -0
  604. data/lib/studium/utility_scripts/average_grade_of_this_curriculum.rb +153 -0
  605. data/lib/studium/utility_scripts/blocked_courses.rb +146 -0
  606. data/lib/studium/utility_scripts/calendar/README.md +2 -0
  607. data/lib/studium/utility_scripts/calendar/calendar.rb +251 -0
  608. data/lib/studium/utility_scripts/calendar/misc.rb +35 -0
  609. data/lib/studium/utility_scripts/check_description_of_these_lectures.rb +221 -0
  610. data/lib/studium/utility_scripts/course_registrations/course_registrations.rb +98 -0
  611. data/lib/studium/utility_scripts/courses/courses.rb +177 -0
  612. data/lib/studium/utility_scripts/create/README.md +2 -0
  613. data/lib/studium/utility_scripts/create/webpage_of_university.rb +129 -0
  614. data/lib/studium/utility_scripts/create/webpage_of_university_BOKU.rb +61 -0
  615. data/lib/studium/utility_scripts/create/webpage_of_university_TU.rb +60 -0
  616. data/lib/studium/utility_scripts/create/webpage_of_university_UniWien.rb +60 -0
  617. data/lib/studium/utility_scripts/create_database/create_database.rb +126 -0
  618. data/lib/studium/utility_scripts/current_lectures_belonging_to_both_bachelor_and_master_curriculum.rb +113 -0
  619. data/lib/studium/utility_scripts/currently_participating_in_these_lectures/currently_participating_in_these_lectures.rb +104 -0
  620. data/lib/studium/utility_scripts/display_lecture_url/display_lecture_url.rb +176 -0
  621. data/lib/studium/utility_scripts/expand_time_range/expand_time_range.rb +521 -0
  622. data/lib/studium/utility_scripts/finished_exams_at_this_university/finished_exams_at_this_university.rb +171 -0
  623. data/lib/studium/utility_scripts/foreign_language_percentage/constants.rb +23 -0
  624. data/lib/studium/utility_scripts/foreign_language_percentage/foreign_language_percentage.rb +149 -0
  625. data/lib/studium/utility_scripts/foreign_language_percentage/help.rb +31 -0
  626. data/lib/studium/utility_scripts/foreign_language_percentage/initialize.rb +25 -0
  627. data/lib/studium/utility_scripts/foreign_language_percentage/menu.rb +158 -0
  628. data/lib/studium/utility_scripts/foreign_language_percentage/report.rb +62 -0
  629. data/lib/studium/utility_scripts/foreign_language_percentage/reset.rb +50 -0
  630. data/lib/studium/utility_scripts/foreign_language_percentage/run.rb +19 -0
  631. data/lib/studium/utility_scripts/generate_spreadsheet/generate_spreadsheet.rb +353 -0
  632. data/lib/studium/utility_scripts/generate_spreadsheet/misc.rb +144 -0
  633. data/lib/studium/utility_scripts/holidays/holidays.rb +154 -0
  634. data/lib/studium/utility_scripts/homepage_of_these_courses/homepage_of_these_courses.rb +125 -0
  635. data/lib/studium/utility_scripts/lectures_attributed_to_universities/lectures_attributed_to_universities.rb +336 -0
  636. data/lib/studium/utility_scripts/lva_dates_of_the_important_courses.rb +111 -0
  637. data/lib/studium/utility_scripts/lva_nummer/lva_nummer.rb +427 -0
  638. data/lib/studium/utility_scripts/mandatory_lectures_in_this_month/mandatory_lectures_in_this_month.rb +316 -0
  639. data/lib/studium/utility_scripts/moodle/moodle.rb +214 -0
  640. data/lib/studium/utility_scripts/name_of_this_lva_id/name_of_this_lva_id.rb +110 -0
  641. data/lib/studium/utility_scripts/new_stud.rb +324 -0
  642. data/lib/studium/utility_scripts/next_week/next_week.rb +103 -0
  643. data/lib/studium/utility_scripts/not_yet_registered/not_yet_registered.rb +120 -0
  644. data/lib/studium/utility_scripts/open_last_exam_question_url_link_via_the_browser.rb +76 -0
  645. data/lib/studium/utility_scripts/passed_ects_per_year/passed_ects_per_year.rb +313 -0
  646. data/lib/studium/utility_scripts/passed_pr/303/274fungsimmanente_courses/passed_pr/303/274fungsimmanente_courses.rb +181 -0
  647. data/lib/studium/utility_scripts/pdf/README.md +2 -0
  648. data/lib/studium/utility_scripts/pdf/create_pdf_file_for_this_exam_topic.rb +352 -0
  649. data/lib/studium/utility_scripts/pdf/hexapdf_support.rb +50 -0
  650. data/lib/studium/utility_scripts/preparatory_meetings/preparatory_meetings.rb +317 -0
  651. data/lib/studium/utility_scripts/priority/priority.rb +164 -0
  652. data/lib/studium/utility_scripts/priority_points/priority_points.rb +261 -0
  653. data/lib/studium/utility_scripts/publish_my_exams/publish_my_exams.rb +174 -0
  654. data/lib/studium/utility_scripts/regexes/README.md +1 -0
  655. data/lib/studium/utility_scripts/regexes/generate_regex.rb +314 -0
  656. data/lib/studium/utility_scripts/regexes/generate_regexes_for_the_available_moodle_links.rb +55 -0
  657. data/lib/studium/utility_scripts/regexes/generate_regexes_for_the_registered_lectures.rb +48 -0
  658. data/lib/studium/utility_scripts/report_outdated_timetable_entries/report_outdated_timetable_entries.rb +142 -0
  659. data/lib/studium/utility_scripts/report_whether_this_lecture_is_registered_in_the_file_lecture_information/report_whether_this_lecture_is_registered_in_the_file_lecture_information.rb +129 -0
  660. data/lib/studium/utility_scripts/resolve_practical_courses_date_conflicts/individual_resolve_practical_courses_date_conflicts.rb +254 -0
  661. data/lib/studium/utility_scripts/resolve_practical_courses_date_conflicts/resolve_practical_courses_date_conflicts.rb +265 -0
  662. data/lib/studium/utility_scripts/scrape_remote_university_url.rb +138 -0
  663. data/lib/studium/utility_scripts/semester_schedule_creator/semester_container.rb +144 -0
  664. data/lib/studium/utility_scripts/semester_schedule_creator/semester_schedule_creator.rb +373 -0
  665. data/lib/studium/utility_scripts/semesterplaner/semesterplaner.rb +311 -0
  666. data/lib/studium/utility_scripts/set_aliases_based_on_this_file.rb +96 -0
  667. data/lib/studium/utility_scripts/show_all_passed_master_lectures/show_all_passed_master_lectures.rb +126 -0
  668. data/lib/studium/utility_scripts/show_conflicting_lva_lectures/show_conflicting_lva_lectures.rb +1385 -0
  669. data/lib/studium/utility_scripts/show_descriptions_of_lectures_belonging_to_this_module/constants.rb +23 -0
  670. data/lib/studium/utility_scripts/show_descriptions_of_lectures_belonging_to_this_module/menu.rb +63 -0
  671. data/lib/studium/utility_scripts/show_descriptions_of_lectures_belonging_to_this_module/reset.rb +33 -0
  672. data/lib/studium/utility_scripts/show_descriptions_of_lectures_belonging_to_this_module/run.rb +50 -0
  673. data/lib/studium/utility_scripts/show_descriptions_of_lectures_belonging_to_this_module/show_descriptions_of_lectures_belonging_to_this_module.rb +145 -0
  674. data/lib/studium/utility_scripts/show_lecturers/show_lecturers.rb +147 -0
  675. data/lib/studium/utility_scripts/show_lectures/show_lectures.rb +906 -0
  676. data/lib/studium/utility_scripts/show_lectures_fitting_to_this_language/show_lectures_fitting_to_this_language.rb +121 -0
  677. data/lib/studium/utility_scripts/show_lectures_fitting_to_this_theme/show_lectures_fitting_to_this_theme.rb +105 -0
  678. data/lib/studium/utility_scripts/show_lectures_on_the_commandline/show_lectures_on_the_commandline.rb +3160 -0
  679. data/lib/studium/utility_scripts/show_lectures_on_this_day/show_lectures_on_this_day.rb +150 -0
  680. data/lib/studium/utility_scripts/show_lva_dates_of_this_lecture/show_lva_dates_of_this_lecture.rb +182 -0
  681. data/lib/studium/utility_scripts/show_mixed_bachelor_master_courses/show_mixed_bachelor_master_courses.rb +92 -0
  682. data/lib/studium/utility_scripts/show_outdated_lva_dates/show_outdated_lva_dates.rb +214 -0
  683. data/lib/studium/utility_scripts/show_passed_exams_having_this_grade/show_passed_exams_having_this_grade.rb +91 -0
  684. data/lib/studium/utility_scripts/show_solved_english_lectures/show_solved_english_lectures.rb +139 -0
  685. data/lib/studium/utility_scripts/steop/README.md +4 -0
  686. data/lib/studium/utility_scripts/steop/show_all_steop_lectures.rb +93 -0
  687. data/lib/studium/utility_scripts/steop/steop_lectures_in_this_curriculum.rb +284 -0
  688. data/lib/studium/utility_scripts/steop/steop_lva_dates.rb +119 -0
  689. data/lib/studium/utility_scripts/studienkennzahl/studienkennzahl.rb +116 -0
  690. data/lib/studium/utility_scripts/studium_skeleton/studium_skeleton.rb +241 -0
  691. data/lib/studium/utility_scripts/stundenplan.rb +600 -0
  692. data/lib/studium/utility_scripts/sync_studium_relevant_entries_one_level_downwards.rb +217 -0
  693. data/lib/studium/utility_scripts/ufind/ufind.rb +106 -0
  694. data/lib/studium/utility_scripts/upcoming_mandatory_presence_courses/constants.rb +26 -0
  695. data/lib/studium/utility_scripts/upcoming_mandatory_presence_courses/run.rb +20 -0
  696. data/lib/studium/utility_scripts/upcoming_mandatory_presence_courses/upcoming_mandatory_presence_courses.rb +187 -0
  697. data/lib/studium/utility_scripts/video_lecture_downloader/video_lecture_downloader.rb +107 -0
  698. data/lib/studium/utility_scripts/week_parser/constants.rb +23 -0
  699. data/lib/studium/utility_scripts/week_parser/help.rb +32 -0
  700. data/lib/studium/utility_scripts/week_parser/menu.rb +59 -0
  701. data/lib/studium/utility_scripts/week_parser/misc.rb +373 -0
  702. data/lib/studium/utility_scripts/week_parser/reset.rb +65 -0
  703. data/lib/studium/utility_scripts/week_parser/run.rb +18 -0
  704. data/lib/studium/utility_scripts/week_parser/show.rb +236 -0
  705. data/lib/studium/utility_scripts/week_parser/week_parser.rb +49 -0
  706. data/lib/studium/utility_scripts/weekday_parser.rb +155 -0
  707. data/lib/studium/utility_scripts/weekly_schedule.rb +198 -0
  708. data/lib/studium/utility_scripts/wochenplanung/wochenplanung.rb +267 -0
  709. data/lib/studium/version/version.rb +46 -0
  710. data/lib/studium/www/exams/exams.cgi +54 -0
  711. data/lib/studium/www/fast_ask_exam_question/fast_ask_exam_question.cgi +156 -0
  712. data/lib/studium/www/handle_curricula/handle_curricula.cgi +154 -0
  713. data/lib/studium/www/next_generation_exam_question_trainer/next_generation_exam_question_trainer.cgi +112 -0
  714. data/lib/studium/www/next_generation_exam_question_trainer/solved.cgi +26 -0
  715. data/lib/studium/www/sinatra/app.rb +231 -0
  716. data/lib/studium/www/sinatra/curriculum_displayer/curriculum_displayer.rb +162 -0
  717. data/lib/studium/www/sinatra/misc.rb +115 -0
  718. data/lib/studium/www/statistics/statistics.cgi +82 -0
  719. data/lib/studium/www/upcoming_exams/upcoming_exams.cgi +36 -0
  720. data/lib/studium/yaml/ad_hoc_trainer/README.md +2 -0
  721. data/lib/studium/yaml/ad_hoc_trainer/exam_topics.md +22 -0
  722. data/lib/studium/yaml/allowed_themes_for_courses/allowed_themes_for_courses.yml +348 -0
  723. data/lib/studium/yaml/array_allowed_entries_for_the_file_lecture_information/array_allowed_entries_for_the_file_lecture_information.yml +71 -0
  724. data/lib/studium/yaml/available_exam_topics/available_exam_topics.yml +234 -0
  725. data/lib/studium/yaml/backlog_of_exams.yml +37 -0
  726. data/lib/studium/yaml/colours/custom_colours.yml +50 -0
  727. data/lib/studium/yaml/colours/use_colours.yml +1 -0
  728. data/lib/studium/yaml/current_exams.yml +30 -0
  729. data/lib/studium/yaml/curricula/README.md +39 -0
  730. data/lib/studium/yaml/curricula/bachelor/bachelor_agrarwissenschaften_033255.yml +147 -0
  731. data/lib/studium/yaml/curricula/bachelor/bachelor_biologie_basisblock_033630.yml +71 -0
  732. data/lib/studium/yaml/curricula/bachelor/bachelor_biologie_botanik_033630.yml +100 -0
  733. data/lib/studium/yaml/curricula/bachelor/bachelor_biologie_ecology_033630.yml +74 -0
  734. data/lib/studium/yaml/curricula/bachelor/bachelor_biologie_mikrobiologie_und_genetik_033630.yml +122 -0
  735. data/lib/studium/yaml/curricula/bachelor/bachelor_biologie_molekulare_biologie_033630.yml +106 -0
  736. data/lib/studium/yaml/curricula/bachelor/bachelor_biologie_zoologie_033630.yml +87 -0
  737. data/lib/studium/yaml/curricula/bachelor/bachelor_chemie_033662.yml +165 -0
  738. data/lib/studium/yaml/curricula/bachelor/bachelor_dummy_curriculum.yml +182 -0
  739. data/lib/studium/yaml/curricula/bachelor/bachelor_elektrotechnik_und_informationstechnik_033235.yml +13 -0
  740. data/lib/studium/yaml/curricula/bachelor/bachelor_forstwirtschaft_033225.yml +115 -0
  741. data/lib/studium/yaml/curricula/bachelor/bachelor_informatik_033521.yml +134 -0
  742. data/lib/studium/yaml/curricula/bachelor/bachelor_ktww_033231.yml +84 -0
  743. data/lib/studium/yaml/curricula/bachelor/bachelor_lmbt_033217.yml +121 -0
  744. data/lib/studium/yaml/curricula/bachelor/bachelor_medizinische_informatik_033533.yml +283 -0
  745. data/lib/studium/yaml/curricula/bachelor/bachelor_molekularbiologie_033665.yml +95 -0
  746. data/lib/studium/yaml/curricula/bachelor/bachelor_nutrition_science_033638.yml +119 -0
  747. data/lib/studium/yaml/curricula/bachelor/bachelor_pharmazie_033305.yml +170 -0
  748. data/lib/studium/yaml/curricula/bachelor/bachelor_technische_chemie_033290.yml +131 -0
  749. data/lib/studium/yaml/curricula/bachelor/bachelor_technische_informatik_033535.yml +23 -0
  750. data/lib/studium/yaml/curricula/bachelor/bachelor_ubrm_033227.yml +142 -0
  751. data/lib/studium/yaml/curricula/bachelor/bachelor_verfahrenstechnik_033273.yml +167 -0
  752. data/lib/studium/yaml/curricula/bachelor/bachelor_wirtschaftsinformatik_033526.yml +29 -0
  753. data/lib/studium/yaml/curricula/experimental/bachelor_informatik_in_den_lebenswissenschaften.yml +137 -0
  754. data/lib/studium/yaml/curricula/individual/bachelor_formale_logik.yml +88 -0
  755. data/lib/studium/yaml/curricula/individual/bachelor_informatik_und_molekulare_biologie.yml +1161 -0
  756. data/lib/studium/yaml/curricula/individual/bachelor_vector_based_strategies_in_life_sciences_molecular_medicine_and_biotechnology.yml +1157 -0
  757. data/lib/studium/yaml/curricula/individual/master_bioinformatics_and_nanobiotechnology_in_molecular_medicine.yml +306 -0
  758. data/lib/studium/yaml/curricula/individual/master_vector_based_strategies_in_life_sciences_molecular_medicine_and_biotechnology.yml +741 -0
  759. data/lib/studium/yaml/curricula/master/master_bioinformatik_066875.yml +75 -0
  760. data/lib/studium/yaml/curricula/master/master_biologie_molekulare_mikrobiologie_mikrobielle_oekologie_und_immunbiologie_066830.yml +78 -0
  761. data/lib/studium/yaml/curricula/master/master_biologische_chemie_066863.yml +66 -0
  762. data/lib/studium/yaml/curricula/master/master_dummy_curriculum.yml +197 -0
  763. data/lib/studium/yaml/curricula/master/master_genetik_und_entwicklungsbiologie_066877.yml +89 -0
  764. data/lib/studium/yaml/curricula/master/master_lmbt_066418.yml +112 -0
  765. data/lib/studium/yaml/curricula/master/master_molecular_biology_066865.yml +72 -0
  766. data/lib/studium/yaml/curricula/master/master_molekulare_biologie_066834.yml +151 -0
  767. data/lib/studium/yaml/curricula/master/master_pharmazie_066605.yml +176 -0
  768. data/lib/studium/yaml/curricula/master/master_technische_chemie_066490.yml +123 -0
  769. data/lib/studium/yaml/curricula/outdated/master_bioinformatics_and_molecular_biotechnology_including_aspects_from_molecular_medicine.yml +438 -0
  770. data/lib/studium/yaml/curricula/outdated/master_food_science_and_plant_biotechnology.yml +31 -0
  771. data/lib/studium/yaml/curricula.yml +562 -0
  772. data/lib/studium/yaml/daily_questions_solved/daily_questions_solved.yml +2019 -0
  773. data/lib/studium/yaml/daily_questions_solved/daily_questions_solved.yml~ +1983 -0
  774. data/lib/studium/yaml/default_delay.yml +4 -0
  775. data/lib/studium/yaml/default_encoding.yml +1 -0
  776. data/lib/studium/yaml/directory_to_the_exam_topics.yml +0 -0
  777. data/lib/studium/yaml/editor.yml +1 -0
  778. data/lib/studium/yaml/exams/next_exams_to_do.md +9 -0
  779. data/lib/studium/yaml/file_for_exam_questions.yml +1 -0
  780. data/lib/studium/yaml/german/README.md +2 -0
  781. data/lib/studium/yaml/german/german_to_english_month_names.yml +16 -0
  782. data/lib/studium/yaml/grouped_themes/grouped_themes.yml +264 -0
  783. data/lib/studium/yaml/holidays/holidays.yml +201 -0
  784. data/lib/studium/yaml/important_exams.yml +286 -0
  785. data/lib/studium/yaml/inscription_dates_of_universities.yml +60 -0
  786. data/lib/studium/yaml/lecture_aliases.yml +138 -0
  787. data/lib/studium/yaml/lecture_information/lecture_information.yml +66145 -0
  788. data/lib/studium/yaml/log_dir.yml +1 -0
  789. data/lib/studium/yaml/main_topic/main_topic.yml +11 -0
  790. data/lib/studium/yaml/max_stats/max_stats.yml +262 -0
  791. data/lib/studium/yaml/max_stats.yml +263 -0
  792. data/lib/studium/yaml/meta_themes +1 -0
  793. data/lib/studium/yaml/mitbelegung/README.md +4 -0
  794. data/lib/studium/yaml/mitbelegung/mitbelegung.yml +21 -0
  795. data/lib/studium/yaml/mitteilungsbl/303/244tter/mitteilungsbl/303/244tter.yml +363 -0
  796. data/lib/studium/yaml/n_total_questions.yml +1 -0
  797. data/lib/studium/yaml/rename_konsole_tab.yml +1 -0
  798. data/lib/studium/yaml/roebe/ad_hoc_exam_topics.md +19 -0
  799. data/lib/studium/yaml/roebe/sommersemester_2024_opportunities.md +441 -0
  800. data/lib/studium/yaml/semester_planner/README.md +4 -0
  801. data/lib/studium/yaml/semester_planner/semester_planner.yml +189 -0
  802. data/lib/studium/yaml/show_topic.yml +1 -0
  803. data/lib/studium/yaml/statistics/lecture_information.yml +1 -0
  804. data/lib/studium/yaml/statistics/max_stats.yml +239 -0
  805. data/lib/studium/yaml/statistics/statistics.yml +77 -0
  806. data/lib/studium/yaml/week/01_monday.yml +25 -0
  807. data/lib/studium/yaml/week/02_tuesday.yml +68 -0
  808. data/lib/studium/yaml/week/03_wednesday.yml +63 -0
  809. data/lib/studium/yaml/week/04_thursday.yml +20 -0
  810. data/lib/studium/yaml/week/05_friday.yml +31 -0
  811. data/lib/studium/yaml/week/06_saturday.yml +16 -0
  812. data/lib/studium/yaml/week/07_sunday.yml +0 -0
  813. data/lib/studium/yaml/week/README.md +10 -0
  814. data/lib/studium.rb +5 -0
  815. data/studium.gemspec +82 -0
  816. data/test/testing_colourized_question_and_answer.rb +18 -0
  817. data/test/testing_studium.rb +244 -0
  818. data/test/testing_studium_base_class.rb +31 -0
  819. data/test/testing_the_file_lecture_information.rb +18 -0
  820. data/test/testing_time_component.rb +29 -0
  821. metadata +1042 -0
@@ -0,0 +1,3266 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # === Studium::GUI::UniversalWidgets::ExamTrainer
6
+ #
7
+ # This widget can be used to ask exam questions.
8
+ #
9
+ # For SQL we could use this:
10
+ #
11
+ # result = `sqlite3 #{SQLITE_DATABASE_FILE} "SELECT * FROM #{current_exam_topic?} ORDER BY RANDOM() LIMIT 1;"`
12
+ # e result
13
+ #
14
+ # Usage example:
15
+ #
16
+ # Studium::GUI::UniversalWidgets::ExamTrainer.new(ARGV)
17
+ #
18
+ # =========================================================================== #
19
+ # require 'studium/gui/universal_widgets/exam_trainer/exam_trainer.rb'
20
+ # =========================================================================== #
21
+ require 'universal_widgets/base/base.rb'
22
+
23
+ module Studium
24
+
25
+ module GUI
26
+
27
+ module UniversalWidgets
28
+
29
+ class ExamTrainer < ::UniversalWidgets::Base # === Studium::GUI::UniversalWidgets::ExamTrainer
30
+
31
+ require 'universal_widgets/base_module/base_module.rb'
32
+ include ::UniversalWidgets::BaseModule
33
+
34
+ require 'studium/exams/question_answer/question_answer.rb'
35
+
36
+ begin
37
+ require 'roebe/toplevel_methods/rinstall2.rb'
38
+ rescue LoadError; end
39
+
40
+ require 'studium/toplevel_methods/toplevel_methods.rb'
41
+ require 'studium/toplevel_methods/find_exam_topic_and_exam_title.rb'
42
+ require 'studium/statistics/report_how_many_exam_questions_were_answered.rb'
43
+ require 'studium/requires/require_class_exams_solved.rb'
44
+ require 'studium/exams/exam_question/exam_question.rb'
45
+ # ========================================================================= #
46
+ # === TITLE
47
+ # ========================================================================= #
48
+ TITLE = 'Simple Exam Trainer'
49
+
50
+ # ========================================================================= #
51
+ # === WIDTH
52
+ # ========================================================================= #
53
+ WIDTH = '95% or minimum 2250px'
54
+
55
+ # ========================================================================= #
56
+ # === Studium::GUI::UniversalWidgets::ExamTrainer::HEIGHT
57
+ #
58
+ # 1080px is the highest for my large monitor, so I set this below.
59
+ # ========================================================================= #
60
+ HEIGHT = '90% or minimum 1060px'
61
+
62
+ # ========================================================================= #
63
+ # === DEFAULT_DELAY
64
+ #
65
+ # This constant specifies how long to wait before the answer is
66
+ # revealed, if the user has set the checkbutton to "automatically
67
+ # answer the question".
68
+ # ========================================================================= #
69
+ DEFAULT_DELAY = '15.0' # This is currently hardcoded.
70
+
71
+ # ========================================================================= #
72
+ # === Studium::GUI::UniversalWidgets::ExamTrainer::N_EXAM_QUESTIONS_IN_TOTAL
73
+ # ========================================================================= #
74
+ N_EXAM_QUESTIONS_IN_TOTAL = 'n exam-questions in total'
75
+
76
+ # ========================================================================= #
77
+ # === Studium::GUI::UniversalWidgets::N_ANSWERED_EXAM_QUESTIONS
78
+ # ========================================================================= #
79
+ N_ANSWERED_EXAM_QUESTIONS = 'n answered exam-questions'
80
+
81
+ # ========================================================================= #
82
+ # === Studium::GUI::UniversalWidgets::N_UNANSWERED_EXAM_QUESTIONS
83
+ # ========================================================================= #
84
+ N_UNANSWERED_EXAM_QUESTIONS = 'n unanswered exam-questions'
85
+
86
+ # ========================================================================= #
87
+ # === Studium::GUI::UniversalWidgets::N_PERCENT_SOLVED
88
+ #
89
+ # An alternative name would be 'percentage solved'.
90
+ # ========================================================================= #
91
+ N_PERCENT_SOLVED = 'n % solved'
92
+
93
+ # ========================================================================= #
94
+ # === Studium::GUI::UniversalWidgets::SLEEP_N_SECONDS
95
+ # ========================================================================= #
96
+ SLEEP_N_SECONDS = 'sleep n seconds'
97
+
98
+ # ========================================================================= #
99
+ # === PANEL_TOOLTIP_TEXT
100
+ # ========================================================================= #
101
+ PANEL_TOOLTIP_TEXT = 'Exam Trainer Widget'
102
+
103
+ # ========================================================================= #
104
+ # === SQLITE_DATABASE_FILE
105
+ #
106
+ # This is experimental - one day we may want to query from a sqlite
107
+ # database rather than flat files. Or, at the least, offer this as
108
+ # a possibility.
109
+ # ========================================================================= #
110
+ SQLITE_DATABASE_FILE = '/Depot/jjjj/exam_questions.db'
111
+
112
+ # ========================================================================= #
113
+ # === USE_THIS_FONT
114
+ #
115
+ # The older font was :dejavu_condensed_20 and the oldest font
116
+ # was :deja_vu_sans_25. Before December 2023 the font was :hack_20,
117
+ # but now it is :hack_22.
118
+ #
119
+ # It is recommended to use the method main_font? rather than this
120
+ # constant directly.
121
+ # ========================================================================= #
122
+ USE_THIS_FONT = :hack_22
123
+
124
+ # ========================================================================= #
125
+ # === LARGER_FONT
126
+ # ========================================================================= #
127
+ LARGER_FONT = :hack_26
128
+
129
+ # ========================================================================= #
130
+ # === SMALLER_FONT
131
+ #
132
+ # This one should be matched onto the larger font defined above.
133
+ # ========================================================================= #
134
+ SMALLER_FONT = :hack_20
135
+
136
+ # ========================================================================= #
137
+ # === SMALLEST_FONT
138
+ # ========================================================================= #
139
+ SMALLEST_FONT = :hack_15
140
+
141
+ # ========================================================================= #
142
+ # === WORD_WRAP_AT_N_CHARACTERS
143
+ #
144
+ # Specify after n characters a given text has to be wrapped via
145
+ # newlines, e. g. "\n".
146
+ # ========================================================================= #
147
+ WORD_WRAP_AT_N_CHARACTERS = 76
148
+
149
+ # ========================================================================= #
150
+ # === DEFAULT_PLACEHOLDER_TEXT
151
+ # ========================================================================= #
152
+ DEFAULT_PLACEHOLDER_TEXT =
153
+ 'You can input your answer to the exam question here.'
154
+
155
+ # ========================================================================= #
156
+ # === USE_THIS_MARGIN
157
+ # ========================================================================= #
158
+ USE_THIS_MARGIN = 12
159
+
160
+ # ========================================================================= #
161
+ # === USE_THIS_AS_THE_DEFAULT_EXAM_TOPIC
162
+ #
163
+ # This constant can be used to specify the default exam topic to be
164
+ # used on startup of this application.
165
+ # ========================================================================= #
166
+ USE_THIS_AS_THE_DEFAULT_EXAM_TOPIC =
167
+ 'toxikologie' # bioinformatics' # 'virus' # stemcells' # chem1' #anatomy'
168
+
169
+ # ========================================================================= #
170
+ # === HASH_DESIGNATED_KEY_COMBINATIONS
171
+ # ========================================================================= #
172
+ HASH_DESIGNATED_KEY_COMBINATIONS = {
173
+ 'strg+s': 'save_the_buffer',
174
+ 'alt+y': 'activate_the_third_textview'
175
+ }
176
+
177
+ # ========================================================================= #
178
+ # === initialize
179
+ # ========================================================================= #
180
+ def initialize(
181
+ commandline_arguments = nil,
182
+ run_already = true
183
+ )
184
+ # ======================================================================= #
185
+ # We first have to determine the GUI that is to be used, even before
186
+ # calling reset(). The reason is that this will also require some
187
+ # files, such as the Gdk namespace, which may be used by the GUI
188
+ # related parts for ruby-gtk3, for instance.
189
+ # ======================================================================= #
190
+ determine_the_GUI_to_be_used(commandline_arguments)
191
+ # super(:vertical) This should be for ruby-gtk3, for a BaseModuleBox.
192
+ reset
193
+ set_commandline_arguments(
194
+ commandline_arguments
195
+ )
196
+ run if run_already
197
+ end
198
+
199
+ # ========================================================================= #
200
+ # === reset (reset tag)
201
+ # ========================================================================= #
202
+ def reset
203
+ super() if respond_to?(:super)
204
+ reset_the_internal_variables
205
+ reset_the_base_module # This must come after reset_the_internal_variables().
206
+ reset_the_shared_module
207
+ infer_the_namespace
208
+ reset_the_shared_variables
209
+ Studium.set_runmode :gui # Make it known that we use the gui-runmode in this case.
210
+ # ======================================================================= #
211
+ # === @configuration
212
+ # ======================================================================= #
213
+ @configuration = [true, __dir__, namespace?]
214
+ # ======================================================================= #
215
+ # === Set the title; this must come after we delegate to the
216
+ # @configuration object
217
+ # ======================================================================= #
218
+ set_title(
219
+ return_the_title_from_the_config_file(true, @configuration)
220
+ )
221
+ # ======================================================================= #
222
+ # === Set the title, width, height and the font in use.
223
+ # ======================================================================= #
224
+ title_width_height_font(title?, WIDTH, HEIGHT, USE_THIS_FONT)
225
+ handle_CSS if use_gtk3?
226
+ enable_all_key_combinations # This should come after CSS was handled.
227
+ infer_the_size_automatically
228
+ # ======================================================================= #
229
+ # === @delay_to_use
230
+ # ======================================================================= #
231
+ set_delay_to_use(DEFAULT_DELAY)
232
+ # ======================================================================= #
233
+ # === @internal_hash[:may_we_reveal_the_answer]
234
+ # ======================================================================= #
235
+ @internal_hash[:may_we_reveal_the_answer] = true
236
+ # ======================================================================= #
237
+ # === :prefer_emoji_or_images
238
+ #
239
+ # This variable can have two different states:
240
+ #
241
+ # :emoji
242
+ # :images
243
+ #
244
+ # If :emoji is active then we will use emojis to enhance the
245
+ # user interface. If :images is active then we will use different
246
+ # images from the main icon theme in use instead.
247
+ #
248
+ # The reason why this was added in May 2021 was because the host
249
+ # system may not support this or that emoji. If the emoji is
250
+ # not supported then the user will see only garbage, which isn't
251
+ # great. Thus, the default is now for :images since as of May
252
+ # 2021, but with the intended goal to retain support for emojis
253
+ # as well, should a user ever want to change this.
254
+ # ======================================================================= #
255
+ @internal_hash[:prefer_emoji_or_images] = :images
256
+ # ======================================================================= #
257
+ # === :use_this_editor
258
+ #
259
+ # The value of this variable may be :bluefish or :internal usually.
260
+ # ======================================================================= #
261
+ @internal_hash[:use_this_editor] = :bluefish # :internal
262
+ # ======================================================================= #
263
+ # === :show_ten_aliases
264
+ #
265
+ # This is only in use if the roebe-gem is available. Many users of this
266
+ # class won't need it though.
267
+ # ======================================================================= #
268
+ @internal_hash[:show_ten_aliases] = nil
269
+ # ======================================================================= #
270
+ # === @internal_hash[:colour_to_use_for_the_notebook_labels]
271
+ # ======================================================================= #
272
+ @internal_hash[:colour_to_use_for_the_notebook_labels] = 'darkblue'
273
+ # ======================================================================= #
274
+ # === @internal_hash[:smaller_font]
275
+ # ======================================================================= #
276
+ @internal_hash[:smaller_font] = SMALLER_FONT
277
+ consider_making_available_the_show_ten_aliases_widget
278
+ upon_delete_event_quit_the_application
279
+ end
280
+
281
+ # ========================================================================= #
282
+ # === reset_the_shared_variables
283
+ # ========================================================================= #
284
+ def reset_the_shared_variables
285
+ # ======================================================================= #
286
+ # === :hash_dataset_of_all_lectures
287
+ #
288
+ # This is the Hash that looks like this:
289
+ #
290
+ # :biopolymers => {:n_total_questions=>4, :n_questions_answered=>0, :percentage_of_questions_answered=>0.0},
291
+ # :biophysik => {:n_total_questions=>28, :n_questions_answered=>0, :percentage_of_questions_answered=>0.0},
292
+ #
293
+ # In other words: it will keep track of how many exam questions and
294
+ # exam answers are in that Hash.
295
+ # ======================================================================= #
296
+ @internal_hash[:hash_dataset_of_all_lectures] =
297
+ Studium::Statistics::ReportHowManyExamQuestionsWereAnswered.new { :be_quiet }.internal_dataset
298
+ end
299
+
300
+ # ========================================================================= #
301
+ # === border_size?
302
+ # ========================================================================= #
303
+ def border_size?
304
+ 0
305
+ end
306
+
307
+ # ========================================================================= #
308
+ # === padding?
309
+ # ========================================================================= #
310
+ def padding?
311
+ 8
312
+ end
313
+
314
+ # ========================================================================= #
315
+ # === update_hash_dataset_of_all_lectures
316
+ # ========================================================================= #
317
+ def update_hash_dataset_of_all_lectures
318
+ @internal_hash[:hash_dataset_of_all_lectures] =
319
+ Studium::Statistics::ReportHowManyExamQuestionsWereAnswered.new { :be_quiet }.internal_dataset
320
+ end
321
+
322
+ # ========================================================================= #
323
+ # === find_completion_for_the_entry_for_the_current_exam_topic
324
+ # ========================================================================= #
325
+ def find_completion_for_the_entry_for_the_current_exam_topic
326
+ _ = entry_for_the_current_exam_topic?
327
+ current_text = _.text?
328
+ new_text = Studium.exam_topic_completion(current_text) { :be_quiet } # Expand it here.
329
+ if new_text
330
+ unless new_text == current_text
331
+ set_exam_topic(new_text)
332
+ end
333
+ one_two_three # The old call was: do_update_the_entry_n_questions
334
+ end
335
+ end
336
+
337
+ # ========================================================================= #
338
+ # === do_update_the_entry_n_questions
339
+ # ========================================================================= #
340
+ def do_update_the_entry_n_questions(
341
+ current_exam_topic =
342
+ current_exam_topic?
343
+ )
344
+ set_n_exam_questions(
345
+ return_n_questions_from_the_currently_selected_topic(current_exam_topic).to_s
346
+ )
347
+ end
348
+
349
+ # ========================================================================= #
350
+ # === let_the_scrolled_window_for_the_answer_parse_URLs
351
+ # ========================================================================= #
352
+ def let_the_scrolled_window_for_the_answer_parse_URLs(
353
+ scrolled_window_for_the_answer = scrolled_window_for_the_answer?
354
+ )
355
+ # ======================================================================= #
356
+ # The scrolled-window for the answer allows the user to click on
357
+ # hyperlinks - or at the least this is the idea. It does not
358
+ # work 100% yet because we need to get the selection first
359
+ # rather than select the whole entry.
360
+ # ======================================================================= #
361
+ scrolled_window_for_the_answer.on_button_release_event {
362
+ parse_for_URL(text_view_for_the_answer?.text?)
363
+ } if scrolled_window_for_the_answer
364
+ end
365
+
366
+ # ========================================================================= #
367
+ # === scrolled_window2?
368
+ # ========================================================================= #
369
+ def scrolled_window2?
370
+ @scrolled_window_containing_the_textarea2
371
+ end; alias return_scrolled_window_containing_the_text_view_for_the_answer scrolled_window2? # === return_scrolled_window_containing_the_text_view_for_the_answer
372
+ alias scrolled_window_for_the_answer? scrolled_window2? # === scrolled_window_for_the_answer?
373
+ alias scrolled_window_containing_the_textarea2? scrolled_window2? # === scrolled_window_containing_the_textarea2?
374
+
375
+ # ========================================================================= #
376
+ # === return_wikipedia_widget (wikipedia tag)
377
+ #
378
+ # This method will return the widget that, upon user-mouse-button-click
379
+ # event, will open the corresponding wikipedia entry. This defaults
380
+ # to the german wikipedia entry right now; if others want to change
381
+ # the default then this could be changed easily.
382
+ # ========================================================================= #
383
+ def return_wikipedia_widget
384
+ begin
385
+ require 'roebe/classes/wikipedia.rb'
386
+ rescue LoadError; end
387
+
388
+ hbox = create_hbox
389
+ wikipedia_entry = entry
390
+ wikipedia_entry.clear_background
391
+ wikipedia_entry.bblack1
392
+ wikipedia_entry.center
393
+ wikipedia_entry.pad3px
394
+ wikipedia_entry.lightgreen_background
395
+ wikipedia_entry.width_height(650, 30)
396
+ wikipedia_entry.hint =
397
+ 'Click the "<b>enter</b>" key to open the assorted keyword in the '\
398
+ 'german-wikipedia. Simply replace <b>de</b> with <b>en</b> in '\
399
+ 'the URL to have the english wikipedia.'
400
+ wikipedia_entry.on_enter {
401
+ if Object.const_defined?(:Roebe) and
402
+ Roebe.const_defined?(:Wikipedia)
403
+ Roebe::Wikipedia.new(wikipedia_entry.text?) # Instantiate a new wrapper.
404
+ else
405
+ e 'You need to install the '+steelblue('roebe')+
406
+ ' gem for this functionality.'
407
+ end
408
+ }
409
+ hbox.minimal(wikipedia_entry, 2)
410
+ return hbox
411
+ end
412
+
413
+ # ========================================================================= #
414
+ # === larger_font?
415
+ # ========================================================================= #
416
+ def larger_font?
417
+ LARGER_FONT
418
+ end
419
+
420
+ # ========================================================================= #
421
+ # === do_jump_into_the_entry_containing_the_current_exam_topic
422
+ # ========================================================================= #
423
+ def do_jump_into_the_entry_containing_the_current_exam_topic
424
+ entry_for_the_current_exam_topic?.do_focus_on_it
425
+ end
426
+
427
+ # ========================================================================= #
428
+ # === debug
429
+ # ========================================================================= #
430
+ def debug
431
+ pp array_all_exam_questions?
432
+ pp array_all_exam_questions?.size
433
+ end
434
+
435
+ # ========================================================================= #
436
+ # === rinstall2
437
+ # ========================================================================= #
438
+ def rinstall2
439
+ Roebe.rinstall2(
440
+ use_this_directory: Studium.ruby_src_dir_at_home?+
441
+ 'studium/'
442
+ )
443
+ end; alias r2 rinstall2 # === r2
444
+
445
+ # ========================================================================= #
446
+ # === main_font?
447
+ # ========================================================================= #
448
+ def main_font?
449
+ USE_THIS_FONT
450
+ end
451
+
452
+ # ========================================================================= #
453
+ # === default_exam_topic?
454
+ # ========================================================================= #
455
+ def default_exam_topic?
456
+ USE_THIS_AS_THE_DEFAULT_EXAM_TOPIC
457
+ end
458
+
459
+ # ========================================================================= #
460
+ # === clear_the_exam_answer (clear tag)
461
+ #
462
+ # This method may only ever call set_exam_answer() - no other method
463
+ # is allowed to be called here.
464
+ # ========================================================================= #
465
+ def clear_the_exam_answer
466
+ set_exam_answer('') # Simply set the answer to an empty String here.
467
+ end; alias clear_reveal_the_answer clear_the_exam_answer # === clear_reveal_the_answer
468
+ alias clear_answers clear_the_exam_answer # === clear_answers
469
+ alias clear_answers_buffer clear_the_exam_answer # === clear_answers_buffer
470
+ alias clear_answer_buffer clear_the_exam_answer # === clear_answer_buffer
471
+ alias clear_the_answer_buffer clear_the_exam_answer # === clear_the_answer_buffer
472
+
473
+ # ========================================================================= #
474
+ # === use_the_internal_editor?
475
+ # ========================================================================= #
476
+ def use_the_internal_editor?
477
+ @internal_hash[:use_this_editor] == :internal
478
+ end
479
+
480
+ # ========================================================================= #
481
+ # === use_this_editor?
482
+ # ========================================================================= #
483
+ def use_this_editor?
484
+ @internal_hash[:use_this_editor]
485
+ end
486
+
487
+ # ========================================================================= #
488
+ # === all_textviews?
489
+ # ========================================================================= #
490
+ def all_textviews?
491
+ [
492
+ textview1?,
493
+ textview2?,
494
+ textview3?
495
+ ]
496
+ end
497
+
498
+ # ========================================================================= #
499
+ # === set_editor_buffer
500
+ # ========================================================================= #
501
+ def set_editor_buffer(i)
502
+ editor?.set_buffer(i.to_s)
503
+ end
504
+
505
+ # ========================================================================= #
506
+ # === handle_CSS (CSS tag)
507
+ # ========================================================================= #
508
+ def handle_CSS
509
+ use_gtk_paradise_project_css_file
510
+ append_project_css_file(
511
+ Studium.project_base_directory?+'css/project.css'
512
+ )
513
+ apply_the_CSS_rules
514
+ end
515
+
516
+ # ========================================================================= #
517
+ # === do_interactively_change_the_font
518
+ #
519
+ # This does not work. :(
520
+ # ========================================================================= #
521
+ def do_interactively_change_the_font
522
+ require 'gtk_paradise/widgets/gtk3/text_entry_widget/text_entry_widget.rb'
523
+ require 'gtk_paradise/examples/gtk3/gtk_dialog_sample.rb'
524
+ _ = ::Gtk::TextEntryWidget.run
525
+ ::Gtk::DialogSample.new(_)
526
+ ::Gtk.main
527
+ e 'The selection was:'
528
+ e
529
+ pp _.selection?
530
+ e
531
+ end
532
+
533
+ # ========================================================================= #
534
+ # === context_menu?
535
+ # ========================================================================= #
536
+ def context_menu?
537
+ @context_menu
538
+ end
539
+
540
+ # ========================================================================= #
541
+ # === button_reveal_the_answer?
542
+ # ========================================================================= #
543
+ def button_reveal_the_answer?
544
+ @internal_hash[:button_reveal_the_answer]
545
+ end
546
+
547
+ # ========================================================================= #
548
+ # === create_text_buffer_for_the_answer
549
+ # ========================================================================= #
550
+ def create_text_buffer_for_the_answer
551
+ # ======================================================================= #
552
+ # === @text_buffer_for_the_answer
553
+ # ======================================================================= #
554
+ @text_buffer_for_the_answer = create_text_buffer
555
+ end
556
+
557
+ # ========================================================================= #
558
+ # === sanitize_the_answer
559
+ #
560
+ # This is called from within set_exam_answer().
561
+ # ========================================================================= #
562
+ def sanitize_the_answer(
563
+ i,
564
+ apply_these_filters = []
565
+ )
566
+ i = i.to_s
567
+ if apply_these_filters.is_a? Symbol
568
+ apply_these_filters = [apply_these_filters]
569
+ end
570
+ if apply_these_filters and !apply_these_filters.empty?
571
+ apply_these_filters.each {|this_filter|
572
+ case this_filter
573
+ # =================================================================== #
574
+ # === :remove_tags
575
+ # =================================================================== #
576
+ when :remove_tags,
577
+ :filter_away_tags
578
+ i = Studium.remove_tags_from_this_input(i)
579
+ end
580
+ }
581
+ end
582
+ if i.include? 'URL: '
583
+ i.gsub!(/URL: /,"\nURL: ")
584
+ end
585
+ if i.include?('(2)')
586
+ i.gsub!(/\(1\)/, "\n (1)")
587
+ i.gsub!(/\(2\)/, "\n (2)")
588
+ i.gsub!(/\(3\)/, "\n (3)")
589
+ i.gsub!(/\(4\)/, "\n (4)")
590
+ i.gsub!(/\(5\)/, "\n (5)")
591
+ i.gsub!(/\(6\)/, "\n (6)")
592
+ i.gsub!(/\(7\)/, "\n (7)")
593
+ i.gsub!(/\(8\)/, "\n (8)")
594
+ end
595
+ i = Studium.remove_html(i)
596
+ i = word_wrap(i, threshold: WORD_WRAP_AT_N_CHARACTERS)
597
+ return i.rstrip
598
+ end; alias sanitize_this_answer sanitize_the_answer # === sanitize_this_answer
599
+
600
+ # ========================================================================= #
601
+ # === consider_running_rinstall2
602
+ # ========================================================================= #
603
+ def consider_running_rinstall2
604
+ if is_on_roebe? and Object.const_defined?(:Roebe)
605
+ rinstall2 # Run rinstall2 here, to update the local copy.
606
+ end
607
+ end
608
+
609
+ # ========================================================================= #
610
+ # === top_textbuffer?
611
+ # ========================================================================= #
612
+ def top_textbuffer?
613
+ text_view_for_the_question?.buffer
614
+ end
615
+
616
+ # ========================================================================= #
617
+ # === smallest_font?
618
+ # ========================================================================= #
619
+ def smallest_font?
620
+ SMALLEST_FONT
621
+ end
622
+
623
+ # ========================================================================= #
624
+ # === original_return_available_exam_topics
625
+ #
626
+ # This variant is probably no longer necessary, but it is retained for now.
627
+ # ========================================================================= #
628
+ def original_return_available_exam_topics
629
+ Studium.return_available_exam_topics
630
+ end
631
+
632
+ # ========================================================================= #
633
+ # === create_the_context_menu
634
+ #
635
+ # This is the context-menu which will appear on a right-mouse
636
+ # click event. It currently only works on ruby-gtk3.
637
+ # ========================================================================= #
638
+ def create_the_context_menu
639
+ # ======================================================================= #
640
+ # === @context_menu
641
+ # ======================================================================= #
642
+ @context_menu = create_context_menu(self) {{
643
+ numbered_actions: {
644
+ 'Ask an exam question': :ask_an_exam_question,
645
+ 'Reveal the answer to the exam question': :reveal_the_answer_to_the_exam_question,
646
+ 'Mark the exam question as solved': :mark_the_exam_question_as_solved,
647
+ 'Pick a new font (show the widget)': :popup_pick_a_new_font,
648
+ 'Debug': :debug
649
+ #'Change the font in use': :do_interactively_change_the_font,
650
+ }
651
+ }}
652
+ @context_menu.make_bold
653
+ @context_menu.set_font(:hack_18)
654
+ end
655
+
656
+ # ========================================================================= #
657
+ # === instantiate_the_control_panel
658
+ #
659
+ # This only works for ruby-gtk3.
660
+ # ========================================================================= #
661
+ def instantiate_the_control_panel
662
+ require 'studium/gui/gtk3/control_panel/control_panel.rb'
663
+ # ======================================================================= #
664
+ # === @control_panel
665
+ # ======================================================================= #
666
+ @control_panel = ::Studium::GUI::Gtk::ControlPanel.new(self)
667
+ @control_panel.use_this_font(main_font?)
668
+ end
669
+
670
+ # ========================================================================= #
671
+ # === use_emoji?
672
+ # ========================================================================= #
673
+ def use_emoji?
674
+ @internal_hash[:prefer_emoji_or_images] == :emoji
675
+ end
676
+
677
+ # ========================================================================= #
678
+ # === set_save_into_this_local_file
679
+ #
680
+ # This method will only be in use if the internal editor is used.
681
+ # ========================================================================= #
682
+ def set_save_into_this_local_file(i)
683
+ editor?.set_save_into_this_local_file(i.to_s)
684
+ end
685
+
686
+ # ========================================================================= #
687
+ # === create_the_button_use_random_entry_from_the_ten_aliases
688
+ # ========================================================================= #
689
+ def create_the_button_use_random_entry_from_the_ten_aliases
690
+ # ======================================================================= #
691
+ # === @internal_hash[:button_use_random_entry_from_the_ten_aliases]
692
+ #
693
+ # This is an eventbox rather than a button, but I think this is still
694
+ # fine. The unicode character "🕵" (U+1F575) is the spy character.
695
+ # ======================================================================= #
696
+ if use_emoji?
697
+ label = create_label('🕵️')
698
+ else
699
+ # label = image_avatar_default # This will be a gtk-image for ruby-gtk3.
700
+ # In December 2023, the above was changed to an image.
701
+ label = create_image(
702
+ Gtk.project_base_directory?+'images/misc/investigate.png'
703
+ )
704
+ end
705
+ # ======================================================================= #
706
+ # === @internal_hash[:button_use_random_entry_from_the_ten_aliases]
707
+ # ======================================================================= #
708
+ _ = create_eventbox(label)
709
+ _.on_clicked {
710
+ if show_ten_aliases?
711
+ set_exam_topic(
712
+ show_ten_aliases?.return_random_entry
713
+ )
714
+ one_two_three
715
+ end
716
+ }
717
+ _.set_size_request(40, 40)
718
+ _.on_hover_lightblue
719
+ # Provide some helpful message to help the user make use of this
720
+ # button.
721
+ _.hint =
722
+ 'Click on this small widget to randomly assign one of '\
723
+ 'the 10 exam-topics currently being studied as the '\
724
+ 'new main exam-topic in use.'
725
+ # This is actually an event box rather than a button.
726
+ @internal_hash[:button_use_random_entry_from_the_ten_aliases] = _ # And assign it here too.
727
+ return _
728
+ end
729
+
730
+ # ========================================================================= #
731
+ # === button_use_random_entry_from_the_ten_aliases?
732
+ # ========================================================================= #
733
+ def button_use_random_entry_from_the_ten_aliases?
734
+ @internal_hash[:button_use_random_entry_from_the_ten_aliases]
735
+ end
736
+
737
+ # ========================================================================= #
738
+ # === do_update_the_entries_n_answered_and_n_unanswered
739
+ # ========================================================================= #
740
+ def do_update_the_entries_n_answered_and_n_unanswered
741
+ do_update_the_entry_n_unanswered_questions
742
+ update_n_unanswered
743
+ end
744
+
745
+ # ========================================================================= #
746
+ # === set_delay_to_use
747
+ # ========================================================================= #
748
+ def set_delay_to_use(
749
+ i = DEFAULT_DELAY
750
+ )
751
+ @internal_hash[:delay_to_use] = i.to_f
752
+ end
753
+
754
+ # ========================================================================= #
755
+ # === reset_the_shared_module
756
+ # ========================================================================= #
757
+ def reset_the_shared_module
758
+ # ======================================================================= #
759
+ # === :array_all_exam_questions
760
+ # ======================================================================= #
761
+ @internal_hash[:array_all_exam_questions] = []
762
+ end
763
+
764
+ # ========================================================================= #
765
+ # === enable_alt_1_key_combination
766
+ # ========================================================================= #
767
+ def enable_alt_1_key_combination
768
+ # ======================================================================= #
769
+ # Add alt+1 key combination:
770
+ # ======================================================================= #
771
+ use_this_key = Gdk::Keyval::KEY_1
772
+ @accel_group.connect(use_this_key, :mod1_mask, :visible) { # alt+1
773
+ entry_ask_questions?.set_focus(true)
774
+ }
775
+ end
776
+
777
+ # ========================================================================= #
778
+ # === enable_alt_y_key_combination
779
+ # ========================================================================= #
780
+ def enable_alt_y_key_combination
781
+ # ======================================================================= #
782
+ # Add alt+y key combination, to assign a new exam topic:
783
+ # ======================================================================= #
784
+ use_this_key = Gdk::Keyval::KEY_Y
785
+ @accel_group.connect(use_this_key, :mod1_mask, :visible) { # alt+y
786
+ do_assign_a_new_exam_topic
787
+ }
788
+ end
789
+
790
+ # ========================================================================= #
791
+ # === popup_pick_a_new_font
792
+ # ========================================================================= #
793
+ def popup_pick_a_new_font
794
+ _ = create_hbox
795
+ _.minimal(text(' → '))
796
+ file_chooser_widget = button('Choose font here')
797
+ file_chooser_widget.set_size_request(800, 660)
798
+ file_chooser_widget.bblack2
799
+ file_chooser_widget.disallow_resizing
800
+ _.minimal(file_chooser_widget) # Add the file-chooser widget here.
801
+ file_chooser_widget.on_click {
802
+ result = gtk_font_chooser_dialog
803
+ set_use_this_font(::Gtk.main_file?)
804
+ result.destroy
805
+ }
806
+ # ======================================================================= #
807
+ # Next create the popup for the font-choosing.
808
+ # ======================================================================= #
809
+ popup_widget = popup_over_this_widget(
810
+ text_view_for_the_question?,
811
+ '',
812
+ _
813
+ )
814
+ # popup_widget.no_arrow # ← This will only work on gtk4, I think.
815
+ popup_widget.popup
816
+ end
817
+
818
+ # ========================================================================= #
819
+ # === textview3?
820
+ # ========================================================================= #
821
+ def textview3?
822
+ @internal_hash[:textview3]
823
+ end; alias text_view_for_the_freeform_input? textview3? # === free_form_textarea?
824
+ alias text_view_for_the_freeform_input textview3? # === text_view_for_the_freeform_input
825
+ alias return_widget_for_the_freeform_textview textview3? # === return_widget_for_the_freeform_textview
826
+ alias free_form_textarea? textview3? # === free_form_textarea?
827
+ alias return_textarea_number_three textview3? # === return_textarea_number_three
828
+
829
+ # ========================================================================= #
830
+ # === create_the_entry_percentage
831
+ # ========================================================================= #
832
+ def create_the_entry_percentage(
833
+ use_this_font = smaller_font?
834
+ )
835
+ # ======================================================================= #
836
+ # === Next create the percentage-entry
837
+ # ======================================================================= #
838
+ _ = entry('', 12)
839
+ @internal_hash[:entry_percentage] = _
840
+ enhance_the_entry_percentage(use_this_font) # This has to happen after the ^^^ above.
841
+ return _
842
+ end
843
+
844
+ # ========================================================================= #
845
+ # === save_the_buffer
846
+ # ========================================================================= #
847
+ def save_the_buffer
848
+ editor?.save_the_buffer
849
+ # ======================================================================= #
850
+ # Check whether we use the internal editor or not.
851
+ # ======================================================================= #
852
+ if use_the_internal_editor? and is_on_roebe?
853
+ # ===================================================================== #
854
+ # In this case jump to the first tab.
855
+ # ===================================================================== #
856
+ @notebook_tab.focus_on_this_tab(0)
857
+ rinstall2
858
+ end
859
+ end
860
+
861
+ # ========================================================================= #
862
+ # === control_panel?
863
+ # ========================================================================= #
864
+ def control_panel?
865
+ @control_panel
866
+ end
867
+
868
+ # ========================================================================= #
869
+ # === create_the_entries (entries tag, entry tag)
870
+ # ========================================================================= #
871
+ def create_the_entries(
872
+ use_this_font = :default_font
873
+ )
874
+ # ======================================================================= #
875
+ # The entry "n percentage" will be created first:
876
+ # ======================================================================= #
877
+ create_the_entry_percentage
878
+ # ======================================================================= #
879
+ # === The entry for n exam questions in total comes next
880
+ # ======================================================================= #
881
+ create_the_entry_containing_n_questions
882
+ create_the_entry_for_the_current_exam_topic
883
+ create_the_entry_n_unanswered_questions
884
+ # ======================================================================= #
885
+ # === :entry_for_sleeping_n_seconds
886
+ # ======================================================================= #
887
+ create_the_entry_for_sleeping_n_seconds
888
+ create_the_entry_n_answered_exam_questions(use_this_font)
889
+ end
890
+
891
+ # ========================================================================= #
892
+ # === textview2?
893
+ # ========================================================================= #
894
+ def textview2?
895
+ @internal_hash[:textview2]
896
+ end; alias return_widget_for_the_answers textview2? # === return_widget_for_the_answers
897
+ alias text_view_for_the_answer textview2? # === text_view_for_the_answer
898
+ alias text_view_for_the_answer? textview2? # === text_view_for_the_answer?
899
+ alias textarea2? textview2? # === textarea2?
900
+ alias answer_buffer? textview2? # === answer_buffer?
901
+ alias answer_buffer textview2? # === answer_buffer
902
+
903
+ # ========================================================================= #
904
+ # === do_clear_the_question_buffer
905
+ #
906
+ # Clear the question-buffer via this method.
907
+ # ========================================================================= #
908
+ def do_clear_the_question_buffer
909
+ text_buffer_for_the_question?.set_text('')
910
+ end; alias clear_question_buffer do_clear_the_question_buffer # === clear_question_buffer
911
+ alias clear_questions_buffer do_clear_the_question_buffer # === clear_questions_buffer
912
+
913
+ # ========================================================================= #
914
+ # === update_n_answered
915
+ # ========================================================================= #
916
+ def update_n_answered(
917
+ i = :infer
918
+ )
919
+ case i
920
+ # ======================================================================= #
921
+ # === :infer
922
+ # ======================================================================= #
923
+ when :infer
924
+ current_exam_topic = current_exam_topic_from_the_entry?
925
+ hash = hash_dataset_of_all_lectures? # Always update it here in this case.
926
+ _ = hash[current_exam_topic.tr(' ','_').to_sym]
927
+ i = _[:n_questions_answered]
928
+ end
929
+ set_n_exam_questions_were_already_answered(i)
930
+ end; alias do_update_the_entry_n_answered update_n_answered # === update_n_answered
931
+
932
+ # ========================================================================= #
933
+ # === return_event_box_with_face_glasses
934
+ #
935
+ # This one belongs close to the top of the widget.
936
+ # ========================================================================= #
937
+ def return_event_box_with_face_glasses
938
+ event_box = create_event_box
939
+ image = create_icon('face-glasses')
940
+ event_box.add(image)
941
+ event_box.on_clicked {
942
+ do_popup_the_array_of_all_exam_questions
943
+ }
944
+ return event_box
945
+ end
946
+
947
+ # ========================================================================= #
948
+ # === do_assign_a_new_exam_topic
949
+ # ========================================================================= #
950
+ def do_assign_a_new_exam_topic
951
+ clear_reveal_the_answer
952
+ this_topic = select_not_yet_completed_exam_topics(
953
+ available_exam_topics?
954
+ ).sample # Obtain a random exam topic here.
955
+ entry_for_the_current_exam_topic?.set_text(this_topic.to_s)
956
+ sync_entry_holding_all_exam_topics_onto_the_combo_box
957
+ do_ask_an_exam_question
958
+ end
959
+
960
+ # ========================================================================= #
961
+ # === sync_entry_holding_all_exam_topics_onto_the_combo_box
962
+ # ========================================================================= #
963
+ def sync_entry_holding_all_exam_topics_onto_the_combo_box(
964
+ value = Studium.find_corresponding_exam_topic(
965
+ entry_for_the_current_exam_topic?.text?
966
+ )
967
+ )
968
+ # ======================================================================= #
969
+ # Next find the correct index:
970
+ # ======================================================================= #
971
+ # index = array.find_index {|entry| entry.delete('_').include?(value) }
972
+ # if index
973
+ # combo_box_available_exam_topics?.set_active(index)
974
+ # else
975
+ # e 'The index was not found. Input was '+steelblue(value)+'.'
976
+ # end
977
+ end; alias sync_entry_holding_all_exam_topics_onto_the_main_combo_box sync_entry_holding_all_exam_topics_onto_the_combo_box # === sync_entry_holding_all_exam_topics_onto_the_main_combo_box
978
+
979
+ # ========================================================================= #
980
+ # === return_event_box_for_asking_a_random_exam_topic
981
+ #
982
+ # This event-box can be used for asking a question from a random exam
983
+ # topic.
984
+ # ========================================================================= #
985
+ def return_event_box_for_asking_a_random_exam_topic
986
+ # ======================================================================= #
987
+ # Next create the actual event box:
988
+ # ======================================================================= #
989
+ event_box_for_image_view_refresh_symbolic_symbolic = create_event_box(
990
+ image_view_refresh_symbolic_symbolic
991
+ )
992
+ # ======================================================================= #
993
+ # Provide useful hints how to use this event-box:
994
+ # ======================================================================= #
995
+ event_box_for_image_view_refresh_symbolic_symbolic.hint =
996
+ 'Click on this icon to <span weight="bold" foreground="lightgreen">set a random exam topic</span>, '\
997
+ "and then ask an exam question from this topic.\n\n"\
998
+ 'Note that since as of <b>August 2022</b> this will ignore '\
999
+ 'exam topics that were already solved.'
1000
+ # ======================================================================= #
1001
+ # Let the event-box respond to an on-click event.
1002
+ # ======================================================================= #
1003
+ event_box_for_image_view_refresh_symbolic_symbolic.on_clicked {
1004
+ do_assign_a_new_exam_topic
1005
+ }
1006
+ return event_box_for_image_view_refresh_symbolic_symbolic
1007
+ end
1008
+
1009
+ # ========================================================================= #
1010
+ # === create_the_thumbs_up_emoji
1011
+ # ========================================================================= #
1012
+ def create_the_thumbs_up_emoji
1013
+ # ======================================================================= #
1014
+ # Add the thumbs-up emoji, but only if we use emojis.
1015
+ # ======================================================================= #
1016
+ if use_emoji?
1017
+ event_box_for_the_thumbs_up_emoji = create_event_box(label(' 👍'))
1018
+ else
1019
+ event_box_for_the_thumbs_up_emoji = create_event_box(image_trophy_gold)
1020
+ end
1021
+ @thumbs_up_emoji = event_box_for_the_thumbs_up_emoji.on_clicked {
1022
+ do_ask_a_new_exam_question
1023
+ }
1024
+ end
1025
+
1026
+ # ========================================================================= #
1027
+ # === parse_for_URL
1028
+ #
1029
+ # This method can be used to return all URLs in a given text.
1030
+ # ========================================================================= #
1031
+ def parse_for_URL(
1032
+ i = text_view_for_the_answer?.buffer.text
1033
+ )
1034
+ array = ::Studium.return_all_URLs_from(i)
1035
+ if array.size > 0
1036
+ first_entry = array.first
1037
+ # ===================================================================== #
1038
+ # We first have to assign it to the GUI part. Note that the "browser"
1039
+ # is part of the control-panel since the rewrite in January 2021.
1040
+ # ===================================================================== #
1041
+ if respond_to?(:control_panel?) and control_panel?.respond_to?(:browser?)
1042
+ control_panel?.browser?.assign_this_text(first_entry)
1043
+ end
1044
+ ::Studium.open_this_remote_url(first_entry)
1045
+ end
1046
+ end
1047
+
1048
+ # ========================================================================= #
1049
+ # === create_the_widget_for_the_freeform_textview
1050
+ # ========================================================================= #
1051
+ def create_the_widget_for_the_freeform_textview
1052
+ # ======================================================================= #
1053
+ # === @internal_hash[:textview3]
1054
+ # ======================================================================= #
1055
+ _ = create_textview
1056
+ _.bblack1
1057
+ _.set_left_right_margin(USE_THIS_MARGIN)
1058
+ # ======================================================================= #
1059
+ # The next code sets up a default placeholder text. Upon a focus-in-event
1060
+ # that default placeholder text is removed.
1061
+ # ======================================================================= #
1062
+ _.buffer.set_placeholder_text(
1063
+ DEFAULT_PLACEHOLDER_TEXT
1064
+ )
1065
+ _.buffer.sync_placeholder_text
1066
+ _.word_wrap
1067
+ _.focus_in_event {
1068
+ if _.buffer.text? == DEFAULT_PLACEHOLDER_TEXT
1069
+ _.buffer.clear # Remove that placeholder text in this case.
1070
+ end
1071
+ }
1072
+ @internal_hash[:textview3] = _
1073
+ return _
1074
+ end
1075
+
1076
+ # ========================================================================= #
1077
+ # === create_scrolled_window3
1078
+ #
1079
+ # This method will return the textarea-widget that can be used for
1080
+ # "free typing" by the user - in other words, where the user can
1081
+ # simply write whatever he/she wants to.
1082
+ # ========================================================================= #
1083
+ def create_scrolled_window3(
1084
+ i = textview3?
1085
+ )
1086
+ # ======================================================================= #
1087
+ # The next scrolled-window is called "textview3", as it is the third
1088
+ # textarea to be seen in the main widget. The rationale for this
1089
+ # method was briefly mentioned above.
1090
+ # ======================================================================= #
1091
+ _ = create_scrolled_window(i) { :only_top_to_bottom }
1092
+ _.set_name('textview3')
1093
+ _.width_height(900, 180)
1094
+ _.pad4px
1095
+ _.do_show_the_scrollbars
1096
+ _.min_content_width = 80
1097
+ _.min_content_height = 120
1098
+ # ======================================================================= #
1099
+ # Next, enable select-all-on-click events:
1100
+ # ======================================================================= #
1101
+ _.signal_connect(:event) {|widget, event|
1102
+ case event.event_type.name.to_s
1103
+ when 'GDK_BUTTON_PRESS'
1104
+ # e 'The left mouse-button was clicked! Selecting everything next.'
1105
+ # @text_view_for_simply_typing_anything.signal_emit(:select_all, event)
1106
+ i.select_everything(event)
1107
+ end
1108
+ }
1109
+ @scrolled_window3 = _
1110
+ return _ # And return it here as well, just in case.
1111
+ end
1112
+
1113
+ # ========================================================================= #
1114
+ # === scrolled_window3?
1115
+ # ========================================================================= #
1116
+ def scrolled_window3?
1117
+ @scrolled_window3
1118
+ end; alias scrolled_window_containing_the_textarea3 scrolled_window3? # === scrolled_window_containing_the_textarea3
1119
+ alias return_scrolled_window3 scrolled_window3? # === scrolled_window_containing_the_textarea3
1120
+ alias return_scrolled_window_containing_the_textarea3 scrolled_window3? # === return_scrolled_window_containing_the_textarea3
1121
+ alias return_widget_for_the_freeform_textview scrolled_window3? # === return_widget_for_the_freeform_textview
1122
+
1123
+ # ========================================================================= #
1124
+ # === button_clear_was_clicked
1125
+ # ========================================================================= #
1126
+ def button_clear_was_clicked
1127
+ all_textviews?.each {|entry|
1128
+ entry.clear
1129
+ }
1130
+ @internal_hash[:may_we_reveal_the_answer_after_a_delay] = false
1131
+ end
1132
+
1133
+ # ========================================================================= #
1134
+ # === notify_the_user_that_all_questions_have_been_answered_in_this_topic
1135
+ # ========================================================================= #
1136
+ def notify_the_user_that_all_questions_have_been_answered_in_this_topic(
1137
+ this_topic = current_exam_topic?,
1138
+ this_widget = button_reveal_the_answer?
1139
+ )
1140
+ bold_popover_message = create_bold_label(
1141
+ 'All questions have been answered for '+this_topic+'. \o/'
1142
+ )
1143
+ popover_message(
1144
+ bold_popover_message,
1145
+ this_widget
1146
+ ).popup
1147
+ end
1148
+
1149
+ # ========================================================================= #
1150
+ # === create_the_entry_n_unanswered_questions
1151
+ # ========================================================================= #
1152
+ def create_the_entry_n_unanswered_questions
1153
+ # ======================================================================= #
1154
+ # === @entry_n_unanswered_questions
1155
+ # ======================================================================= #
1156
+ @entry_n_unanswered_questions = create_entry
1157
+ enhance_entry_containing_n_unanswered_questions(
1158
+ :default_font,
1159
+ @entry_n_unanswered_questions
1160
+ )
1161
+ end; alias create_the_entry_containing_n_unanswered_questions create_the_entry_n_unanswered_questions # === create_the_entry_containing_n_unanswered_questions
1162
+ alias create_the_entry_containing_n_unanswered_exam_questions create_the_entry_n_unanswered_questions # === create_the_entry_containing_n_unanswered_exam_questions
1163
+
1164
+ # ========================================================================= #
1165
+ # === entry_n_answered_exam_questions?
1166
+ # ========================================================================= #
1167
+ def entry_n_answered_exam_questions?
1168
+ @internal_hash[:entry_n_answered_exam_questions]
1169
+ end; alias entry_containing_n_answers? entry_n_answered_exam_questions? # === entry_containing_n_answers?
1170
+
1171
+ # ========================================================================= #
1172
+ # === create_the_entry_for_sleeping_n_seconds
1173
+ # ========================================================================= #
1174
+ def create_the_entry_for_sleeping_n_seconds
1175
+ # ======================================================================= #
1176
+ # === :entry_for_sleeping_n_seconds
1177
+ #
1178
+ # Next create the delay-entry that keeps track how many seconds to wait,
1179
+ # before revealing the answer (IF the user has decided to make use of
1180
+ # that functionality).
1181
+ # ======================================================================= #
1182
+ _ = entry('', 5) # entry('', 5) is primarily for jruby.
1183
+ _ << default_delay?.to_s.dup # Default delay.
1184
+ @internal_hash[:entry_for_sleeping_n_seconds] = _
1185
+ enhance_the_entry_for_sleeping_n_seconds
1186
+ return @internal_hash[:entry_for_sleeping_n_seconds]
1187
+ end
1188
+
1189
+ # ========================================================================= #
1190
+ # === entry_percentage?
1191
+ # ========================================================================= #
1192
+ def entry_percentage?
1193
+ @internal_hash[:entry_percentage]
1194
+ end; alias return_entry_percentage entry_percentage? # === return_entry_percentage
1195
+
1196
+ # ========================================================================= #
1197
+ # === return_hbox_containing_two_icons_and_instructions_what_to_do_with_the_free_form_textarea
1198
+ #
1199
+ # This widget returned by this method here, should come before the
1200
+ # free-form widget is added.
1201
+ # ========================================================================= #
1202
+ def return_hbox_containing_two_icons_and_instructions_what_to_do_with_the_free_form_textarea
1203
+ hbox_with_two_icons = create_hbox
1204
+ first_eventbox = create_event_box(image_accessories_text_editor)
1205
+ first_eventbox.on_clicked {
1206
+ do_clear_the_free_form_textarea
1207
+ }
1208
+ hbox_with_two_icons.minimal(first_eventbox, 2)
1209
+ text = text(
1210
+ 'Below this text you can input your assumed '\
1211
+ 'answer to the exam question at hand.'
1212
+ )
1213
+ text.left_align
1214
+ text.make_selectable
1215
+ text.set_font(:hack_18)
1216
+ hbox_with_two_icons.maximal(text, 4)
1217
+ event_box_for_image_accessories_text_editor = create_event_box(image_accessories_text_editor)
1218
+ event_box_for_image_accessories_text_editor.hint =
1219
+ 'Click here to empty the free-form textarea below this icon.'
1220
+ event_box_for_image_accessories_text_editor.on_clicked {
1221
+ do_clear_the_free_form_textarea
1222
+ }
1223
+ hbox_with_two_icons.minimal(event_box_for_image_accessories_text_editor, 2)
1224
+ return hbox_with_two_icons
1225
+ end
1226
+
1227
+ # ========================================================================= #
1228
+ # === create_entry_n_total_exam_questions
1229
+ # ========================================================================= #
1230
+ def create_entry_n_total_exam_questions
1231
+ # ======================================================================= #
1232
+ # === @entry_n_total_exam_questions
1233
+ # ======================================================================= #
1234
+ @internal_hash[:entry_n_total_exam_questions] = entry('', 12) # The 12 is for jruby specifically.
1235
+ enhance_the_entry_containing_n_questions
1236
+ return @internal_hash[:entry_n_total_exam_questions]
1237
+ end; alias create_the_entry_containing_n_questions create_entry_n_total_exam_questions # === create_the_entry_containing_n_questions
1238
+
1239
+ # ========================================================================= #
1240
+ # === do_style_all_buttons_uniformly (style tag)
1241
+ # ========================================================================= #
1242
+ def do_style_all_buttons_uniformly(
1243
+ i = return_all_buttons
1244
+ )
1245
+ # ======================================================================= #
1246
+ # Style all buttons uniformly next, via CSS.
1247
+ # ======================================================================= #
1248
+ i.each {|this_button|
1249
+ # ===================================================================== #
1250
+ # Use the same CSS rule for each button.
1251
+ # ===================================================================== #
1252
+ this_button.clear_background
1253
+ this_button.bblack2
1254
+ this_button.set_size_request(75, 28)
1255
+ this_button.set_name('button_hover_transition')
1256
+ }
1257
+ end
1258
+
1259
+ # ========================================================================= #
1260
+ # === all_questions_have_been_answered_in_this_topic?
1261
+ #
1262
+ # This method has to determine how many questions have been answered
1263
+ # in the current exam topic.
1264
+ # ========================================================================= #
1265
+ def all_questions_have_been_answered_in_this_topic?(
1266
+ this_topic = current_exam_topic?
1267
+ )
1268
+ (Studium.return_n_percent_solved_from_this_topic(this_topic).to_i == 100)
1269
+ end
1270
+
1271
+ # ========================================================================= #
1272
+ # === textview1?
1273
+ # ========================================================================= #
1274
+ def textview1?
1275
+ @internal_hash[:textview1]
1276
+ end; alias widget_for_the_questions? textview1? # === widget_for_the_questions?
1277
+ alias text_view_for_the_question? textview1? # === text_view_for_the_question?
1278
+ alias return_widget_for_the_questions textview1? # === return_widget_for_the_questions
1279
+ alias return_text_view_for_the_question textview1? # === return_text_view_for_the_question
1280
+ alias return_scrolled_window_for_the_text_view_for_the_question textview1? # === return_scrolled_window_for_the_text_view_for_the_question
1281
+ alias text_view_containing_the_current_question? textview1? # === text_view_containing_the_current_question?
1282
+ alias text_buffer_for_the_question? textview1? # === text_buffer_for_the_question?
1283
+ alias textarea1? textview1? # === textare1?
1284
+ alias question_buffer textview1? # === question_buffer
1285
+ alias question_buffer? textview1? # === question_buffer?
1286
+
1287
+ # ========================================================================= #
1288
+ # === create_the_textview_that_will_contain_the_exam_question
1289
+ # ========================================================================= #
1290
+ def create_the_textview_that_will_contain_the_exam_question(
1291
+ text_buffer_for_the_question = :default_buffer
1292
+ )
1293
+ # ======================================================================= #
1294
+ # === @internal_hash[:textview1]
1295
+ # ======================================================================= #
1296
+ _ = create_textview(text_buffer_for_the_question)
1297
+ _.set_left_right_margin(USE_THIS_MARGIN)
1298
+ _.word_wrap
1299
+ scrolled_window_containing_the_textarea1 = create_scrolled_window(
1300
+ _
1301
+ ) { :only_up_and_bottom }
1302
+ scrolled_window_containing_the_textarea1.set_name('textview1_for_the_studium_gem') # Contains the question.
1303
+ scrolled_window_containing_the_textarea1.set_size_request(920, 180)
1304
+ @internal_hash[:textview1] = _
1305
+ @internal_hash[:scrolled_window_containing_the_textarea1] = scrolled_window_containing_the_textarea1
1306
+ end
1307
+
1308
+ # ========================================================================= #
1309
+ # === hash_dataset_of_all_lectures?
1310
+ # ========================================================================= #
1311
+ def hash_dataset_of_all_lectures?
1312
+ @internal_hash[:hash_dataset_of_all_lectures]
1313
+ end
1314
+
1315
+ # ======================================================================= #
1316
+ # === do_assign_the_default_exam_topic_to_the_correct_entry
1317
+ # ======================================================================= #
1318
+ def do_assign_the_default_exam_topic_to_the_correct_entry
1319
+ set_exam_topic(USE_THIS_AS_THE_DEFAULT_EXAM_TOPIC)
1320
+ end
1321
+
1322
+ # ========================================================================= #
1323
+ # === deselect_the_entry_containing_the_exam_topic
1324
+ # ========================================================================= #
1325
+ def deselect_the_entry_containing_the_exam_topic(
1326
+ i = entry_for_the_current_exam_topic?
1327
+ )
1328
+ i.deselect
1329
+ text_view_containing_the_current_question?.set_focus(true)
1330
+ end
1331
+
1332
+ # ========================================================================= #
1333
+ # === scrolled_window1?
1334
+ # ========================================================================= #
1335
+ def scrolled_window1?
1336
+ @internal_hash[:scrolled_window_containing_the_textarea1]
1337
+ end
1338
+
1339
+ # ========================================================================= #
1340
+ # === create_the_textviews
1341
+ # ========================================================================= #
1342
+ def create_the_textviews
1343
+ create_the_textview_that_will_contain_the_exam_question
1344
+ # ======================================================================= #
1345
+ # === @internal_hash[:textview2]
1346
+ # ======================================================================= #
1347
+ create_the_widget_for_the_exam_answer
1348
+ # ======================================================================= #
1349
+ # === @internal_hash[:textview3]
1350
+ # ======================================================================= #
1351
+ create_the_widget_for_the_freeform_textview
1352
+ create_scrolled_window3 # And create the scrolled-window3 here as well.
1353
+ end
1354
+
1355
+ # ========================================================================= #
1356
+ # === create_the_widget_for_the_exam_answer (answer tag, answers tags)
1357
+ # ========================================================================= #
1358
+ def create_the_widget_for_the_exam_answer(
1359
+ use_this_text_buffer = @text_buffer_for_the_answer
1360
+ )
1361
+ _ = create_textview(use_this_text_buffer)
1362
+ _.set_left_right_margin(USE_THIS_MARGIN)
1363
+ _.word_wrap
1364
+ @internal_hash[:textview2] = _
1365
+ scrolled_window = create_scrolled_window(
1366
+ _
1367
+ ) { :only_up_and_bottom }
1368
+ scrolled_window.set_name('textview2_for_the_studium_gem') # Contains the answer.
1369
+ scrolled_window.set_size_request(1000, 150)
1370
+ scrolled_window.min_content_width = 100
1371
+ scrolled_window.min_content_height = 200
1372
+ scrolled_window.do_show_the_scrollbars
1373
+ @scrolled_window_containing_the_textarea2 = scrolled_window
1374
+ return _ # And return it too, just in case.
1375
+ end; alias create_text_view_for_the_answer create_the_widget_for_the_exam_answer # === create_text_view_for_the_answer
1376
+
1377
+ # ========================================================================= #
1378
+ # === create_the_button_solve_the_question
1379
+ # ========================================================================= #
1380
+ def create_the_button_solve_the_question
1381
+ # ======================================================================= #
1382
+ # === @button_solve_the_question
1383
+ # ======================================================================= #
1384
+ @button_solve_the_exam_question = return_button_solve_the_question
1385
+ end
1386
+
1387
+ # ========================================================================= #
1388
+ # === button_ask_the_exam_question?
1389
+ # ========================================================================= #
1390
+ def button_ask_the_exam_question?
1391
+ @internal_hash[:button_ask_the_exam_question]
1392
+ end; alias question_button? button_ask_the_exam_question? # === question_button?
1393
+ alias button_ask_the_question? button_ask_the_exam_question? # === button_ask_the_question?
1394
+
1395
+ # ========================================================================= #
1396
+ # === create_the_button_ask_the_exam_question
1397
+ # ========================================================================= #
1398
+ def create_the_button_ask_the_exam_question
1399
+ # ======================================================================= #
1400
+ # === @internal_hash[:button_ask_the_exam_question]
1401
+ # ======================================================================= #
1402
+ @internal_hash[:button_ask_the_exam_question] = return_button_ask_the_exam_question(use_emoji?)
1403
+ end; alias create_the_ask_the_exam_question_button create_the_button_ask_the_exam_question # === create_the_ask_the_exam_question_button
1404
+
1405
+ # ========================================================================= #
1406
+ # === set_exam_question
1407
+ #
1408
+ # The second argument can be a filter. For instance, if the Symbol
1409
+ # :remove_tags is passed, then all HTML tags will be removed from
1410
+ # the given input at hand. This is actually the default behaviour.
1411
+ # ========================================================================= #
1412
+ def set_exam_question(
1413
+ i = exam_question_object?.question?,
1414
+ apply_these_filters = [:remove_tags]
1415
+ )
1416
+ i = i.to_s.dup
1417
+ i[0,2] = '' if i.start_with?('- ') # We don't ever want leading '-' here.
1418
+ if apply_these_filters.is_a? Symbol
1419
+ apply_these_filters = [apply_these_filters]
1420
+ end
1421
+ # ======================================================================= #
1422
+ # Replace all URL entries with <a href> entries next:
1423
+ # ======================================================================= #
1424
+ if i
1425
+ i = ::Gtk.replace_all_URL_entries_in_this_string(i)
1426
+ end
1427
+ # ======================================================================= #
1428
+ # The following line may have to be re-evaluated again in the future -
1429
+ # in the past, in 2021, this had a bug and things crashed, but this
1430
+ # may no longer be the case - let's see, eventually.
1431
+ #
1432
+ # editor?.update_the_main_buffer(dataset)
1433
+ #
1434
+ # ======================================================================= #
1435
+ if apply_these_filters and !apply_these_filters.empty?
1436
+ apply_these_filters.each {|this_filter|
1437
+ case this_filter
1438
+ # =================================================================== #
1439
+ # === :remove_tags
1440
+ # =================================================================== #
1441
+ when :remove_tags,
1442
+ :no_tags,
1443
+ :default
1444
+ i = Studium.remove_tags_from_this_input(i)
1445
+ end
1446
+ }
1447
+ end
1448
+ @internal_hash[:exam_question] = i
1449
+ textview1?.set_text(i) # This is the widget for the exam-questions.
1450
+ end; alias set_question set_exam_question # === set_question
1451
+
1452
+ # ========================================================================= #
1453
+ # === create_the_emoji_toggle_widget
1454
+ #
1455
+ # Note that in order to use EmojiToggleWidget, we have to pull in the
1456
+ # right file, either ruby-gtk3 or ruby-gtk2.
1457
+ # ========================================================================= #
1458
+ def create_the_emoji_toggle_widget
1459
+ require 'gtk_paradise/widgets/gtk3/emoji_toggle_widget/emoji_toggle_widget.rb'
1460
+ @a_thinking_smiley_emoji = ::Gtk::EmojiToggleWidget.new(
1461
+ :use_two_smileys
1462
+ )
1463
+ @a_thinking_smiley_emoji.make_selectable
1464
+ end
1465
+
1466
+ # ========================================================================= #
1467
+ # === return_n_questions_from_the_currently_selected_topic
1468
+ #
1469
+ # This method will return how many exam questions exist in the
1470
+ # selected exam topic.
1471
+ #
1472
+ # This method is no longer that important as of December 2023.
1473
+ # ========================================================================= #
1474
+ def return_n_questions_from_the_currently_selected_topic(
1475
+ i = current_exam_topic?
1476
+ )
1477
+ ::Studium.n_questions_available_in_this_topic(i)
1478
+ end
1479
+
1480
+ # ========================================================================= #
1481
+ # === do_clear_the_free_form_textarea
1482
+ # ========================================================================= #
1483
+ def do_clear_the_free_form_textarea
1484
+ free_form_textarea?.set_text('')
1485
+ end
1486
+
1487
+ # ========================================================================= #
1488
+ # === create_the_buttons (buttons tag, button tag)
1489
+ # ========================================================================= #
1490
+ def create_the_buttons
1491
+ create_the_button_ask_the_exam_question
1492
+ # ======================================================================= #
1493
+ # === @button_solve_the_exam_question
1494
+ # ======================================================================= #
1495
+ create_the_button_solve_the_question
1496
+ # ======================================================================= #
1497
+ # === @button_clear
1498
+ # ======================================================================= #
1499
+ @button_clear = bold_button('_Clear all entries', self, :use_mnemonic) {
1500
+ :button_clear_was_clicked
1501
+ }
1502
+ create_the_button_update_n_questions_were_answered
1503
+ create_the_reveal_the_answer_button
1504
+ # ======================================================================= #
1505
+ # Next style these four buttons uniformly
1506
+ # ======================================================================= #
1507
+ [
1508
+ button_ask_the_exam_question?,
1509
+ button_reveal_the_answer?,
1510
+ button_solve_the_exam_question?,
1511
+ @button_clear,
1512
+ button_update_n_questions_were_answered?
1513
+ ].each {|this_button|
1514
+ this_button.clear_background
1515
+ this_button.bblack2
1516
+ this_button.on_hover(:lightgreen)
1517
+ }
1518
+ create_the_button_use_random_entry_from_the_ten_aliases # This one should come last here.
1519
+ end
1520
+
1521
+ # ========================================================================= #
1522
+ # === create_the_editor (editor tag)
1523
+ #
1524
+ # This method only makes sense for ruby-gtk3.
1525
+ # ========================================================================= #
1526
+ def create_the_editor
1527
+ if shall_we_create_the_gtk_editor?
1528
+ require 'gtk_paradise/widgets/gtk3/editor/editor.rb'
1529
+ # ===================================================================== #
1530
+ # === @editor
1531
+ # ===================================================================== #
1532
+ @editor = ::Gtk::Editor.new { :do_not_use_the_colour_box_widget }
1533
+ else
1534
+ @editor = nil
1535
+ end
1536
+ end
1537
+
1538
+ # ========================================================================= #
1539
+ # === add_the_status_icon
1540
+ # ========================================================================= #
1541
+ def add_the_status_icon
1542
+ if use_gtk3?
1543
+ status_icon = return_status_icon
1544
+ status_icon.favicon = Studium.project_base_directory?+
1545
+ 'images/studies_favicon.png'
1546
+ status_icon.hint = 'Exam-question widget: train your brain!'
1547
+ begin # Need to fix this later.
1548
+ menu = create_menu
1549
+ button_hello_world = create_image_menu_item(stock: ::Gtk::Stock::FIND)
1550
+ button_hello_world.signal_connect(:activate) {
1551
+ e 'A click-event has been detected.'
1552
+ }
1553
+ menu << button_hello_world
1554
+ quit_button = create_image_menu_item(stock: ::Gtk::Stock::QUIT)
1555
+ quit_button.signal_connect(:activate) { ::Gtk.main_quit }
1556
+ menu.append(quit_button)
1557
+ menu.show_all
1558
+ status_icon.signal_connect(:popup_menu) { |icon, button, time|
1559
+ menu.popup(nil, nil, button, time)
1560
+ }
1561
+ rescue Exception => error
1562
+ pp error
1563
+ end
1564
+ end
1565
+ end
1566
+
1567
+ # ========================================================================= #
1568
+ # === allow_external_applications?
1569
+ #
1570
+ # This is mostly useful when the main application allows add-ons, such
1571
+ # as the TenAliases widget. It is not so important for standalone
1572
+ # widgets.
1573
+ # ========================================================================= #
1574
+ def allow_external_applications?
1575
+ true
1576
+ end
1577
+
1578
+ # ========================================================================= #
1579
+ # === available_exam_topics_in_short_form?
1580
+ # ========================================================================= #
1581
+ def available_exam_topics_in_short_form?
1582
+ array = Studium.available_exam_topics_in_short_form?
1583
+ array = array.sort_by {|entry| entry.downcase }
1584
+ return array
1585
+ end; alias return_available_exam_topics available_exam_topics_in_short_form? # === return_available_exam_topics
1586
+ alias available_exam_topics? available_exam_topics_in_short_form? # === available_exam_topics?
1587
+ alias exam_topics_short_form? available_exam_topics_in_short_form? # === exam_topics_short_form?
1588
+
1589
+ # ========================================================================= #
1590
+ # === enable_all_key_combinations
1591
+ # ========================================================================= #
1592
+ def enable_all_key_combinations
1593
+ # ======================================================================= #
1594
+ # === @accel_group
1595
+ # ======================================================================= #
1596
+ @accel_group = create_and_add_gtk_accel_group
1597
+ enable_alt_w_key_combination
1598
+ enable_alt_y_key_combination
1599
+ enable_alt_1_key_combination
1600
+ end
1601
+
1602
+ # ========================================================================= #
1603
+ # === return_frame_containing_the_label_exam_topic
1604
+ # ========================================================================= #
1605
+ def return_frame_containing_the_label_exam_topic
1606
+ # ======================================================================= #
1607
+ # Create the exam-topic label next, showing a watermelon emoji on the
1608
+ # left-hand side. The watermelon emoji used to be 🍉️; but it was
1609
+ # replaced with the electric light bulb emoji in January 2021, which
1610
+ # is 💡️. Unfortunately this does not work on every system, so it
1611
+ # was decided to replace this with an image that is determined by
1612
+ # the icon theme at hand.
1613
+ # ======================================================================= #
1614
+ label_exam_topic = bold_text(' Exam topic ')
1615
+ label_emoji = right_arrow_emoji
1616
+ label_emoji.set_size_request(22, 22)
1617
+ label_emoji.align_right
1618
+ event_box_for_the_label_emoji = create_event_box(label_emoji)
1619
+ event_box_for_the_label_emoji.on_clicked {
1620
+ do_jump_into_the_entry_containing_the_current_exam_topic
1621
+ }
1622
+ tiny_hbox = create_hbox
1623
+ tiny_hbox.minimal(label_exam_topic)
1624
+ tiny_hbox.maximal(event_box_for_the_label_emoji)
1625
+ tiny_hbox.minimal(text(' ')) # Just a "spacer".
1626
+ frame_containing_the_label_exam_topic = create_frame(tiny_hbox)
1627
+ frame_containing_the_label_exam_topic.modify_background(:normal, :oldlace)
1628
+ frame_containing_the_label_exam_topic.bblack1
1629
+ # frame_containing_the_label_exam_topic.set_font(smaller_font?)
1630
+ label_exam_topic.hint = 'Denote <b>the current exam </b> topic '\
1631
+ 'to the <b>right</b> of this text.'
1632
+ return frame_containing_the_label_exam_topic
1633
+ end
1634
+
1635
+ # ========================================================================= #
1636
+ # === entry_n_total_exam_questions?
1637
+ # ========================================================================= #
1638
+ def entry_n_total_exam_questions?
1639
+ @internal_hash[:entry_n_total_exam_questions]
1640
+ end; alias entry_containing_n_questions? entry_n_total_exam_questions? # === entry_containing_n_questions?
1641
+
1642
+ # ========================================================================= #
1643
+ # === Studium::GUI::UniversalWidgets::ExamTrainer.gtk_accel_group
1644
+ # ========================================================================= #
1645
+ def self.gtk_accel_group
1646
+ ::Gtk::AccelGroup.new
1647
+ end
1648
+
1649
+ # ========================================================================= #
1650
+ # === button_clear?
1651
+ # ========================================================================= #
1652
+ def button_clear?
1653
+ @button_clear
1654
+ end
1655
+
1656
+ # ========================================================================= #
1657
+ # === parse_the_commandline_arguments
1658
+ # ========================================================================= #
1659
+ def parse_the_commandline_arguments
1660
+ _ = commandline_arguments?
1661
+ unless _.empty?
1662
+ new_topic = _.first
1663
+ # ===================================================================== #
1664
+ # === Handle numbers given as input here:
1665
+ #
1666
+ # Example:
1667
+ #
1668
+ # ruby misc.rb 5
1669
+ #
1670
+ # ===================================================================== #
1671
+ if new_topic =~ /^\d+$/ # A number - and only a number - was given to this class here.
1672
+ new_topic = new_topic.to_i
1673
+ new_topic = Studium.exam_topic_number?(new_topic).to_s
1674
+ end
1675
+ new_topic = Studium.find_corresponding_exam_topic(new_topic)
1676
+ entry_for_the_current_exam_topic?.set_text(new_topic)
1677
+ # ===================================================================== #
1678
+ # Next, we must also update the combo-box.
1679
+ # This is currently not enabled:
1680
+ # _.find_and_try_to_select_this_entry(new_topic)
1681
+ # simply_assign_this_as_the_new_exam_topic_onto_the_primary_combobox(new_topic)
1682
+ # ===================================================================== #
1683
+ one_two_three
1684
+ end
1685
+ end
1686
+
1687
+ # ========================================================================= #
1688
+ # === entry_n_unanswered_questions?
1689
+ # ========================================================================= #
1690
+ def entry_n_unanswered_questions?
1691
+ @entry_n_unanswered_questions
1692
+ end; alias entry_containing_n_unanswered_questions? entry_n_unanswered_questions? # === entry_containing_n_unanswered_questions?
1693
+ alias entry_containing_n_unanswered_questions entry_n_unanswered_questions? # === entry_containing_n_unanswered_questions
1694
+
1695
+ # ========================================================================= #
1696
+ # === button_solve_the_exam_question?
1697
+ # ========================================================================= #
1698
+ def button_solve_the_exam_question?
1699
+ @button_solve_the_exam_question
1700
+ end
1701
+
1702
+ # ========================================================================= #
1703
+ # === button_solve_the_exam_question_was_clicked (solved tag, solve tag)
1704
+ # ========================================================================= #
1705
+ def button_solve_the_exam_question_was_clicked
1706
+ # the_current_exam_question_is_now_solved
1707
+ # update_three_important_widgets
1708
+ _ = Studium::Exams::Solved.new(ARGV) { :do_not_run_yet }
1709
+ _.set_commandline
1710
+ _.run
1711
+ consider_running_rinstall2
1712
+ # ======================================================================= #
1713
+ # Also update the appropriate label next, whenever the solve-exam
1714
+ # question was clicked.
1715
+ # ======================================================================= #
1716
+ update_the_label_n_questions_were_answered
1717
+ end; alias mark_the_exam_question_as_solved button_solve_the_exam_question_was_clicked # === mark_the_exam_question_as_solved
1718
+ alias do_solve_the_exam_question button_solve_the_exam_question_was_clicked # === do_solve_the_exam_question
1719
+ alias the_current_exam_question_is_now_solved button_solve_the_exam_question_was_clicked # === the_current_exam_question_is_now_solved
1720
+
1721
+ # ========================================================================= #
1722
+ # === activate_the_third_textview
1723
+ # ========================================================================= #
1724
+ def activate_the_third_textview
1725
+ free_form_textarea?.do_focus_on_it
1726
+ end
1727
+
1728
+ # ========================================================================= #
1729
+ # === change_to_a_happy_smiley_before_reverting_to_the_prior_default_again
1730
+ #
1731
+ # This method is used to turn the thinking-smiley to a happy-smiley,
1732
+ # before reverting again to the prior default.
1733
+ # ========================================================================= #
1734
+ def change_to_a_happy_smiley_before_reverting_to_the_prior_default_again(
1735
+ delay_to_use = 5_000 # This refers to 5 seconds.
1736
+ )
1737
+ @a_thinking_smiley_emoji.toggle
1738
+ GLib::Timeout.add(delay_to_use) {
1739
+ @a_thinking_smiley_emoji.revert_to_the_initial_state # This reverts to the initial state again.
1740
+ false # Must end it.
1741
+ }
1742
+ end
1743
+
1744
+ # ======================================================================= #
1745
+ # === create_the_combobox
1746
+ #
1747
+ # This method will create the combo-box that contains all exam-topics.
1748
+ # It will be a bit truncated, largely for display-reasons rather
1749
+ # than any other reason.
1750
+ # ======================================================================= #
1751
+ def create_the_combobox(
1752
+ use_these_exam_topics = :default_exam_topics
1753
+ )
1754
+ case use_these_exam_topics
1755
+ # ===================================================================== #
1756
+ # === :default_exam_topics
1757
+ # ===================================================================== #
1758
+ when :default_exam_topics
1759
+ use_these_exam_topics = available_exam_topics_in_short_form?.
1760
+ map(&:downcase).sort
1761
+ end
1762
+ # ===================================================================== #
1763
+ # Next truncate these exam-topics a bit:
1764
+ # ===================================================================== #
1765
+ use_this_sorted_array = use_these_exam_topics.uniq.map {|entry|
1766
+ if entry.size > 25 # Truncate it a bit in this case here.
1767
+ entry = entry[0 .. 25]
1768
+ end
1769
+ entry
1770
+ }.sort
1771
+ _ = create_combobox_text # Create the combo-box here.
1772
+ # use_this_sorted_array.each {|entry|
1773
+ # entry = entry.to_s
1774
+ # _.append_text(entry) if entry and !entry.empty?
1775
+ # }
1776
+ _.fill_up(use_this_sorted_array)
1777
+ _.first_entry_is_active
1778
+ _.bblack1
1779
+ _.set_size_request(100, 28)
1780
+ # ======================================================================= #
1781
+ # Wrap-width determines how many entries per row are shown when the
1782
+ # combo-box is expanded. We stick to the default of 1 here.
1783
+ # ======================================================================= #
1784
+ _.set_wrap_width(1)
1785
+ # ======================================================================= #
1786
+ # The event where the combo-box is changed is handled next.
1787
+ # ======================================================================= #
1788
+ _.on_changed {
1789
+ handle_the_combo_box_available_exam_topics_on_changed_event
1790
+ }
1791
+ @internal_hash[:combobox_available_exam_topics] = _ # And assign it here.
1792
+ return _
1793
+ end
1794
+
1795
+ # ======================================================================= #
1796
+ # === set_exam_topic
1797
+ #
1798
+ # This will set towards the entry that holds the current exam topic.
1799
+ # ======================================================================= #
1800
+ def set_exam_topic(
1801
+ i = :default
1802
+ )
1803
+ case i
1804
+ # ===================================================================== #
1805
+ # === :default
1806
+ # ===================================================================== #
1807
+ when :default
1808
+ i = default_exam_topic?.to_s
1809
+ end
1810
+ i = i.to_s # .downcase # Studium.expand_exam_topic(use_this_topic.to_s)
1811
+ if i and !i.empty?
1812
+ entry_for_the_current_exam_topic?.set_text(i)
1813
+ end
1814
+ end; alias set_current_exam_topic set_exam_topic # === set_current_exam_topic
1815
+
1816
+ # ========================================================================= #
1817
+ # === create_the_entry_for_the_current_exam_topic
1818
+ # ========================================================================= #
1819
+ def create_the_entry_for_the_current_exam_topic
1820
+ # ======================================================================= #
1821
+ # === @internal_hash[:entry_exam_topic_in_use]
1822
+ #
1823
+ # This is the entry that contains the current exam topics. The user can
1824
+ # modify the content of this entry at his or her own discretion. It
1825
+ # is the most important entry for this widget, among all entries
1826
+ # used in this GUI application.
1827
+ #
1828
+ # This entry is positioned rather close to the top of the main widget,
1829
+ # on the left hand side. The user can thus simply manipulate it by
1830
+ # clicking on it; most users will look at the top left (or middle)
1831
+ # first.
1832
+ #
1833
+ # Another entry of this widget may depend on this entry here, so it
1834
+ # should come early in the create-entries method - aka on top of
1835
+ # this method.
1836
+ #
1837
+ # We use a completionable-entry here, but only for ruby-gtk3.
1838
+ # ======================================================================= #
1839
+ _ = entry_with_this_completion(
1840
+ available_exam_topics_in_short_form?
1841
+ )
1842
+ _.clear_background
1843
+ _.bblack1
1844
+ _.very_light_yellow_background
1845
+ _.width_height(400, 20)
1846
+ _.set_font(smaller_font?)
1847
+ _.hint = 'This is the entry that keeps '\
1848
+ 'track of the current exam topic.'
1849
+ # ======================================================================= #
1850
+ # We need this entry to be fairly wide, hence the following method call.
1851
+ # ======================================================================= #
1852
+ _.set_size_request(500, 40)
1853
+ _.set_hexpand(false)
1854
+ _.set_vexpand(false)
1855
+ # ======================================================================= #
1856
+ # Allow for scroll-events.
1857
+ # ======================================================================= #
1858
+ _.enable_scroll_events
1859
+ _.on_enter {
1860
+ find_completion_for_the_entry_for_the_current_exam_topic
1861
+ the_button_ask_the_exam_question_was_clicked
1862
+ }
1863
+ _.on_scroll_event {|widget, event|
1864
+ # ===================================================================== #
1865
+ # For now this simply sets a new, random topic.
1866
+ # ===================================================================== #
1867
+ if scroll_up?(event)
1868
+ set_exam_topic(
1869
+ available_exam_topics?.sample.downcase
1870
+ )
1871
+ sync_entry_holding_all_exam_topics_onto_the_combo_box # Sync towards the combo-box.
1872
+ elsif scroll_down?(event)
1873
+ set_exam_topic(
1874
+ available_exam_topics?.sample.downcase
1875
+ )
1876
+ sync_entry_holding_all_exam_topics_onto_the_combo_box # Sync towards the combo-box.
1877
+ end
1878
+ }
1879
+ # ======================================================================= #
1880
+ # Respond to the enter-key pressed next.
1881
+ # ======================================================================= #
1882
+ # _.on_enter_key_pressed { |widget, event|
1883
+ # sync_entry_holding_all_exam_topics_onto_the_main_combo_box
1884
+ # }
1885
+ # ======================================================================= #
1886
+ # Assign the entry-widget finally:
1887
+ # ======================================================================= #
1888
+ @internal_hash[:entry_exam_topic_in_use] = _ # And assign it here as well.
1889
+ end
1890
+
1891
+ # ========================================================================= #
1892
+ # === do_update_the_entry_n_answered
1893
+ # ========================================================================= #
1894
+ def do_update_the_entry_n_answered(
1895
+ current_exam_topic = combo_box_available_exam_topics?.active_text.to_s.strip.dup,
1896
+ entry = entry_containing_n_answers? # The entry that is to be updated.
1897
+ )
1898
+ current_exam_topic.strip! if current_exam_topic.end_with? '_'
1899
+ entry.set_text(
1900
+ return_n_answers_from_the_currently_selected_topic(current_exam_topic).to_s
1901
+ )
1902
+ end
1903
+
1904
+ # ========================================================================= #
1905
+ # === set_n_exam_questions_are_unanswered
1906
+ # ========================================================================= #
1907
+ def set_n_exam_questions_are_unanswered(i)
1908
+ entry_containing_n_unanswered_questions?.set_text(i.to_s)
1909
+ end; alias set_n_unanswered_questions set_n_exam_questions_are_unanswered # === set_n_unanswered_questions
1910
+
1911
+ # ========================================================================= #
1912
+ # === select_not_yet_completed_exam_topics
1913
+ # ========================================================================= #
1914
+ def select_not_yet_completed_exam_topics(i)
1915
+ if i and i.is_a?(Array)
1916
+ return ::Studium.reject_already_completed_exam_topics(i, hash_dataset_of_all_lectures?)
1917
+ end
1918
+ return i # else return the original input unmodified.
1919
+ end
1920
+
1921
+ # ========================================================================= #
1922
+ # === return_string_how_many_exam_questions_are_already_answered
1923
+ # ========================================================================= #
1924
+ def return_string_how_many_exam_questions_are_already_answered
1925
+ ::Studium.return_string_how_many_exam_questions_are_already_answered
1926
+ end
1927
+
1928
+ # ========================================================================= #
1929
+ # === question_is?
1930
+ # ========================================================================= #
1931
+ def question_is?
1932
+ @internal_hash[:exam_question_object].question?
1933
+ end
1934
+
1935
+ # ========================================================================= #
1936
+ # === answer_is?
1937
+ # ========================================================================= #
1938
+ def answer_is?
1939
+ @internal_hash[:exam_question_object].answer?
1940
+ end
1941
+
1942
+ # ========================================================================= #
1943
+ # === default_delay?
1944
+ # ========================================================================= #
1945
+ def delay_to_use?
1946
+ @internal_hash[:delay_to_use]
1947
+ end; alias default_delay? delay_to_use? # === default_delay?
1948
+
1949
+ # ========================================================================= #
1950
+ # === create_the_button_update_n_questions_were_answered (update tag)
1951
+ # ========================================================================= #
1952
+ def create_the_button_update_n_questions_were_answered
1953
+ # ======================================================================= #
1954
+ # === The update-button is created next. It had the cat emoji in the
1955
+ # past, aka 🐈️, but not every computer system has access to such
1956
+ # an emoji, so this was replaced via an image.
1957
+ #
1958
+ # The old text was: '🐈️ Update ➡️ '
1959
+ #
1960
+ # ======================================================================= #
1961
+ _ = bold_button('Update ➡️ ')
1962
+ _.on_hover(:lightblue)
1963
+ _.hint =
1964
+ 'Click this button to update the entry to the right side.'
1965
+ _.on_clicked {
1966
+ update_the_label_n_questions_were_answered
1967
+ }
1968
+ # ======================================================================= #
1969
+ # Last but not least, assign it:
1970
+ # ======================================================================= #
1971
+ @internal_hash[:button_update_n_questions_were_answered] = _
1972
+ end
1973
+
1974
+ # ========================================================================= #
1975
+ # === return_eventbox_with_an_image_to_exit_the_application
1976
+ #
1977
+ # This method bundles together a quit-the-application functionality.
1978
+ # ========================================================================= #
1979
+ def return_eventbox_with_an_image_to_exit_the_application
1980
+ application_exit_image = return_this_image_based_on_the_default_icon_theme(
1981
+ 'system-log-out-symbolic.symbolic'
1982
+ ) # Or: :application_exit
1983
+ _ = create_eventbox(application_exit_image)
1984
+ _.hint = 'Click on this image to exit the program.'
1985
+ _.on_clicked {
1986
+ exit_application
1987
+ }
1988
+ return _
1989
+ end
1990
+
1991
+ # ========================================================================= #
1992
+ # === enable_the_main_key_combinations
1993
+ # ========================================================================= #
1994
+ def enable_the_main_key_combinations(
1995
+ use_this_hash = HASH_DESIGNATED_KEY_COMBINATIONS
1996
+ )
1997
+ enable_these_key_combinations(
1998
+ use_this_hash
1999
+ )
2000
+ end
2001
+
2002
+ # ========================================================================= #
2003
+ # === populate_the_main_grid (grid tag, populate tag)
2004
+ #
2005
+ # In order to populate the grid, all widgets have to be designated.
2006
+ # ========================================================================= #
2007
+ def populate_the_main_grid(
2008
+ grid = main_grid?
2009
+ )
2010
+ reset_the_grid_counter # Just to be safe.
2011
+ ::Gtk::Grid.full_width = 3 # 3 entries per row.
2012
+ grid.left(
2013
+ return_frame_containing_the_label_exam_topic
2014
+ )
2015
+ grid.middle(
2016
+ entry_exam_topic_in_use?
2017
+ )
2018
+ mini_hbox = create_hbox
2019
+ mini_hbox.maximal(combobox_available_exam_topics?, 2)
2020
+ mini_hbox.minimal(return_event_box_with_face_glasses, 2)
2021
+ # ======================================================================= #
2022
+ # The event-box comes next to the box with face-glasses:
2023
+ # ======================================================================= #
2024
+ mini_hbox.minimal(return_eventbox_with_an_image_to_exit_the_application, 2)
2025
+
2026
+ grid.right(mini_hbox) # One row has been completed here.
2027
+
2028
+ grid.full_line(scrolled_window1?)
2029
+ grid.full_line(scrolled_window_containing_the_textarea2?)
2030
+ # ========================================================================= #
2031
+ # Show a little helpful text how to use the textview3:
2032
+ # ========================================================================= #
2033
+ grid.full_line(return_hbox_containing_two_icons_and_instructions_what_to_do_with_the_free_form_textarea)
2034
+ # ======================================================================= #
2035
+ # Next add the free-form widget:
2036
+ # ======================================================================= #
2037
+ grid.full_line(return_scrolled_window3)
2038
+ # ======================================================================= #
2039
+ # Next synchronize the design layout of the three scrolled windows:
2040
+ # ======================================================================= #
2041
+ [
2042
+ scrolled_window1?,
2043
+ scrolled_window2?,
2044
+ scrolled_window3?
2045
+ ].each {|this_widget|
2046
+ this_widget.pad8px
2047
+ }
2048
+
2049
+ # ======================================================================= #
2050
+ # Next comes the middle-part of the GUI (middle tag)
2051
+ # ======================================================================= #
2052
+
2053
+ # ======================================================================= #
2054
+ # === n questions in total
2055
+ #
2056
+ # This will show the "n questions in total" text.
2057
+ # ======================================================================= #
2058
+ text = selectable_text(N_EXAM_QUESTIONS_IN_TOTAL)
2059
+ text.set_font(smaller_font?)
2060
+ text.pad6px
2061
+ mini_hbox = create_hbox(text, entry_n_total_exam_questions?)
2062
+ grid.left(mini_hbox)
2063
+
2064
+ # ======================================================================= #
2065
+ # === n unanswered questions
2066
+ # ======================================================================= #
2067
+ text = selectable_text(N_UNANSWERED_EXAM_QUESTIONS)
2068
+ text.set_font(smaller_font?)
2069
+ text.pad6px
2070
+ mini_hbox = create_hbox(text, entry_n_unanswered_questions?)
2071
+ grid.middle(mini_hbox)
2072
+
2073
+ # ======================================================================= #
2074
+ # === n answered exam questions
2075
+ #
2076
+ # This is the text that goes along the lines of
2077
+ # "n answered exam questions".
2078
+ # ======================================================================= #
2079
+ text = selectable_text(N_ANSWERED_EXAM_QUESTIONS)
2080
+ text.set_font(smaller_font?)
2081
+ text.pad6px
2082
+ text.royalblue
2083
+ text.make_bold
2084
+ mini_hbox = create_hbox(text, entry_n_answered_exam_questions?)
2085
+ grid.right(mini_hbox)
2086
+
2087
+ # ======================================================================= #
2088
+ # === The entry "percentage solved" comes next
2089
+ # ======================================================================= #
2090
+ text = selectable_text(N_PERCENT_SOLVED)
2091
+ text.set_font(smaller_font?)
2092
+ text.pad6px
2093
+ mini_hbox = create_hbox
2094
+ mini_hbox.minimal(text, 1)
2095
+ mini_hbox.maximal(entry_percentage?, 1)
2096
+ grid.left(mini_hbox)
2097
+
2098
+ # ======================================================================= #
2099
+ # === sleep n seconds solved
2100
+ #
2101
+ # Next we add the delay-n-seconds entry.
2102
+ # ======================================================================= #
2103
+ text = selectable_text(SLEEP_N_SECONDS)
2104
+ text.set_font(smaller_font?)
2105
+ text.pad6px
2106
+ mini_hbox = create_hbox
2107
+ mini_hbox.minimal(text, 1)
2108
+ mini_hbox.maximal(entry_for_sleeping_n_seconds?, 1)
2109
+ grid.middle(mini_hbox)
2110
+ grid.right(checkbox?)
2111
+
2112
+ # ======================================================================= #
2113
+ # Add three buttons next:
2114
+ # ======================================================================= #
2115
+ grid.left(button_ask_the_exam_question?)
2116
+ grid.middle(button_reveal_the_answer?)
2117
+ grid.right(button_solve_the_exam_question?)
2118
+
2119
+ # ======================================================================= #
2120
+ # And two more buttons:
2121
+ # ======================================================================= #
2122
+ grid.left(button_clear?)
2123
+ mini_hbox.set_hexpand(true)
2124
+
2125
+ mini_hbox = create_hbox
2126
+ mini_hbox.minimal(return_wikipedia_widget, 2)
2127
+ mini_hbox.minimal(return_event_box_for_asking_a_random_exam_topic, 2)
2128
+ mini_hbox.minimal(button_use_random_entry_from_the_ten_aliases?, 2)
2129
+ mini_hbox.minimal(return_button_open_exam_topic_file, 2)
2130
+ # ======================================================================= #
2131
+ # We could also add smiley-emojis next:
2132
+ #
2133
+ # mini_hbox.minimal(@a_thinking_smiley_emoji, 2)
2134
+ # mini_hbox.minimal(@thumbs_up_emoji, 2)
2135
+ #
2136
+ # ======================================================================= #
2137
+ grid.two_width(mini_hbox)
2138
+ grid.new_line
2139
+ # ======================================================================= #
2140
+ # Next add the label that the ^^^ button can update:
2141
+ # ======================================================================= #
2142
+ grid.left(button_update_n_questions_were_answered?)
2143
+ grid.two_width(label_n_questions_were_answered?)
2144
+ grid.new_line
2145
+ mini_hbox = create_hbox
2146
+ return grid
2147
+ end
2148
+
2149
+ # ========================================================================= #
2150
+ # === enhance_the_entry_for_sleeping_n_seconds
2151
+ # ========================================================================= #
2152
+ def enhance_the_entry_for_sleeping_n_seconds(
2153
+ i = entry_for_sleeping_n_seconds?
2154
+ )
2155
+ i.width_height(45, 20)
2156
+ i.center
2157
+ i.bblack1
2158
+ i.set_name('BG_bisque')
2159
+ i.hint =
2160
+ 'Provide the delay here, as <b>n seconds</b>. This will only work '\
2161
+ 'if the checkbox to the right side <b>active</b>.'
2162
+ end
2163
+
2164
+ # ========================================================================= #
2165
+ # === enhance_the_entry_percentage
2166
+ # ========================================================================= #
2167
+ def enhance_the_entry_percentage(
2168
+ use_this_font = nil
2169
+ )
2170
+ _ = entry_percentage?
2171
+ _.hint =
2172
+ "This field denotes how many questions have already\n"\
2173
+ "been answered successfully, <b>in percent</b>.\n\n"\
2174
+ "Note that this requires a specific exam topic to "\
2175
+ "have been set, so no percentage value may be "\
2176
+ "shown initially.\n\nSimply assign to an exam topic "\
2177
+ "and it should work fine."
2178
+ _.do_center
2179
+ _.disable_user_input # The user can not change this entry.
2180
+ _.set_font(use_this_font) if use_this_font
2181
+ _.set_name('BG_bisque')
2182
+ _.bblack1
2183
+ end
2184
+
2185
+ # ========================================================================= #
2186
+ # === enhance_the_entry_containing_n_questions
2187
+ # ========================================================================= #
2188
+ def enhance_the_entry_containing_n_questions(
2189
+ use_this_font = smaller_font?,
2190
+ entry = @internal_hash[:entry_n_total_exam_questions]
2191
+ )
2192
+ entry.set_font(use_this_font) if use_this_font
2193
+ entry.clear_background
2194
+ entry.width_height(350, 22)
2195
+ entry.bblack1
2196
+ entry.center
2197
+ entry.readonly
2198
+ entry.very_light_yellow_background
2199
+ end
2200
+
2201
+ # ========================================================================= #
2202
+ # === enhance_entry_n_answered_exam_questions
2203
+ #
2204
+ # This method can be used to enhance the entry "n answered exam questions".
2205
+ # ========================================================================= #
2206
+ def enhance_entry_n_answered_exam_questions(
2207
+ use_this_font = :default_font,
2208
+ entry = entry_n_answered_exam_questions?
2209
+ )
2210
+ case use_this_font
2211
+ # ======================================================================= #
2212
+ # === :default_font
2213
+ # ======================================================================= #
2214
+ when :default_font, nil
2215
+ use_this_font = smaller_font?
2216
+ end
2217
+ # ======================================================================= #
2218
+ # === @internal_hash[:entry_n_answered_exam_questions]
2219
+ # ======================================================================= #
2220
+ entry.set_font(use_this_font) if use_this_font
2221
+ entry.width_height(320, 22)
2222
+ entry.bblack1
2223
+ entry.very_light_yellow_background
2224
+ entry.center
2225
+ entry.readonly
2226
+ end
2227
+
2228
+ # ========================================================================= #
2229
+ # === create_the_entry_n_answered_exam_questions
2230
+ # ========================================================================= #
2231
+ def create_the_entry_n_answered_exam_questions(
2232
+ use_this_font = :default_font
2233
+ )
2234
+ # ======================================================================= #
2235
+ # === The entry keeping track as to how many answers have been
2236
+ # given for that particular exam-topic.
2237
+ # ======================================================================= #
2238
+ @internal_hash[:entry_n_answered_exam_questions] = entry('', 12)
2239
+ enhance_entry_n_answered_exam_questions(use_this_font)
2240
+ return entry_n_answered_exam_questions? # And return it here.
2241
+ end; alias create_the_entry_containing_n_answered_exam_questions create_the_entry_n_answered_exam_questions # === create_the_entry_containing_n_answered_exam_questions
2242
+
2243
+ # ========================================================================= #
2244
+ # === enhance_entry_containing_n_unanswered_questions
2245
+ # ========================================================================= #
2246
+ def enhance_entry_containing_n_unanswered_questions(
2247
+ use_this_font = smaller_font?,
2248
+ entry = entry_n_unanswered_questions?
2249
+ )
2250
+ case use_this_font
2251
+ # ======================================================================= #
2252
+ # === :default_font
2253
+ # ======================================================================= #
2254
+ when :default_font, nil
2255
+ use_this_font = smaller_font?
2256
+ end
2257
+ entry.clear_background
2258
+ entry.set_font(use_this_font) if use_this_font
2259
+ entry.width_height(50, 20)
2260
+ entry.bblack1
2261
+ entry.very_light_yellow_background
2262
+ entry.center
2263
+ entry.readonly
2264
+ end; alias enhance_entry_containing_n_unanswered_questions enhance_entry_containing_n_unanswered_questions # === enhance_entry_containing_n_unanswered_questions
2265
+
2266
+ # ========================================================================= #
2267
+ # === set_n_exam_questions_were_already_answered
2268
+ # ========================================================================= #
2269
+ def set_n_exam_questions_were_already_answered(i)
2270
+ entry_n_answered_exam_questions?.set_text(i.to_s)
2271
+ end
2272
+
2273
+ # ========================================================================= #
2274
+ # === enable_alt_w_key_combination
2275
+ #
2276
+ # This method will specifically enable the "alt+w" shortcut.
2277
+ # ========================================================================= #
2278
+ def enable_alt_w_key_combination(
2279
+ i = @accel_group
2280
+ )
2281
+ # ======================================================================= #
2282
+ # Add alt+w key combination, to open the current exam topic file:
2283
+ # ======================================================================= #
2284
+ use_this_key = ::Gdk::Keyval::KEY_W
2285
+ i.connect(use_this_key, :mod1_mask, :visible) { # alt+w
2286
+ do_open_the_current_exam_topic_file
2287
+ }
2288
+ end
2289
+
2290
+ # ========================================================================= #
2291
+ # === current_exam_topic_from_the_entry?
2292
+ # ========================================================================= #
2293
+ def current_exam_topic_from_the_entry?
2294
+ entry_for_the_current_exam_topic?.text?.to_s
2295
+ end; alias current_exam_topic_as_a_string? current_exam_topic_from_the_entry? # === current_exam_topic_as_a_string?
2296
+
2297
+ # ========================================================================= #
2298
+ # === do_open_the_current_exam_topic_file
2299
+ #
2300
+ # This method can either open the exam-file in the bluefish editor,
2301
+ # or in the integrated ruby-gtk editor. Since as of July 2021 we
2302
+ # will try the integrated variant. Unfortunately ruby-gtk is somehow
2303
+ # buggy - reading a large file leads to a BadAlloc error, so this
2304
+ # was changed to open an external editor instead.
2305
+ # ========================================================================= #
2306
+ def do_open_the_current_exam_topic_file(
2307
+ use_this_as_exam_topic = current_exam_topic_from_the_entry?
2308
+ )
2309
+ use_this_as_exam_topic = Studium.find_corresponding_exam_topic(use_this_as_exam_topic)
2310
+ if use_this_as_exam_topic.empty?
2311
+ do_popup_the_you_have_to_provide_an_exam_topic
2312
+ end
2313
+ # ======================================================================= #
2314
+ # We must obtain the correct path next, to then send into the editor:
2315
+ # ======================================================================= #
2316
+ use_this_as_exam_topic = Studium.path_to_exam_topic?+
2317
+ File.basename(use_this_as_exam_topic)
2318
+ if use_the_internal_editor? # This here is when we use the internal editor.
2319
+ set_save_into_this_local_file(use_this_as_exam_topic)
2320
+ set_editor_buffer(File.read(use_this_as_exam_topic))
2321
+ @notebook_tab.focus_on_this_tab(2)
2322
+ else
2323
+ # ======================================================================= #
2324
+ # Or simply use bluefish or whatever else the editor is.
2325
+ # ======================================================================= #
2326
+ _ = "#{use_this_editor?} #{use_this_as_exam_topic}"
2327
+ esystem(_)
2328
+ end
2329
+ end
2330
+
2331
+ # ========================================================================= #
2332
+ # === return_button_open_exam_topic_file
2333
+ #
2334
+ # This button should be next to the event box that will ask a random
2335
+ # exam topic.
2336
+ # ========================================================================= #
2337
+ def return_button_open_exam_topic_file
2338
+ # ======================================================================= #
2339
+ # This button will have the symbol for :open_file, an emoji - if
2340
+ # emojis are used. Otherwise an image will be used instead.
2341
+ # ======================================================================= #
2342
+ if use_emoji?
2343
+ _ = button(return_emoji(:open_box))
2344
+ else
2345
+ _ = button_with_this_image(image_open_file)
2346
+ end
2347
+ _.no_relief
2348
+ _.on_hover_lightblue
2349
+ _.hint = 'Click on this button to <b>open the current exam-topic file</b>.'
2350
+ _.on_clicked {
2351
+ do_open_the_current_exam_topic_file
2352
+ }
2353
+ return _
2354
+ end
2355
+
2356
+ # ========================================================================= #
2357
+ # === return_n_answers_from_the_currently_selected_topic
2358
+ # ========================================================================= #
2359
+ def return_n_answers_from_the_currently_selected_topic(
2360
+ i = current_exam_topic_as_a_string?
2361
+ )
2362
+ ::Studium.n_answers_available_in_this_topic(i)
2363
+ end
2364
+
2365
+ # ========================================================================= #
2366
+ # === shall_we_create_the_gtk_editor?
2367
+ # ========================================================================= #
2368
+ def shall_we_create_the_gtk_editor?
2369
+ @internal_hash[:use_this_editor] == :internal
2370
+ end
2371
+
2372
+ # ========================================================================= #
2373
+ # === create_the_labels
2374
+ # ========================================================================= #
2375
+ def create_the_labels
2376
+ # ======================================================================= #
2377
+ # === @label_n_questions_were_answered
2378
+ # ======================================================================= #
2379
+ @label_n_questions_were_answered = selectable_label
2380
+ update_the_label_n_questions_were_answered(@label_n_questions_were_answered)
2381
+ end
2382
+
2383
+ # ========================================================================= #
2384
+ # === label_n_questions_were_answered?
2385
+ # ========================================================================= #
2386
+ def label_n_questions_were_answered?
2387
+ @label_n_questions_were_answered
2388
+ end
2389
+
2390
+ # ========================================================================= #
2391
+ # === set_n_exam_questions_exist_in_total
2392
+ #
2393
+ # This method exists to set the value of the proper entry, containing
2394
+ # how many exam-questions are still unanswered.
2395
+ # ========================================================================= #
2396
+ def set_n_exam_questions_exist_in_total(i)
2397
+ entry_n_total_exam_questions?.set_text(i.to_s)
2398
+ end
2399
+
2400
+ # ========================================================================= #
2401
+ # === combobox_available_exam_topics?
2402
+ #
2403
+ # This combo box will contain all available (registered) exam topics.
2404
+ # ========================================================================= #
2405
+ def combobox_available_exam_topics?
2406
+ @internal_hash[:combobox_available_exam_topics]
2407
+ end; alias return_the_combobox combobox_available_exam_topics? # === return_the_combobox
2408
+ alias combo_box_available_exam_topics? combobox_available_exam_topics? # === combo_box_available_exam_topics?
2409
+ alias main_combo_box? combobox_available_exam_topics? # === main_combo_box?
2410
+ alias combo_box? combobox_available_exam_topics? # === combo_box?
2411
+ alias return_combo_box_showing_all_exam_questions combobox_available_exam_topics? # === return_combo_box_showing_all_exam_questions
2412
+ alias return_combo_box_available_exam_topics combobox_available_exam_topics? # === return_combo_box_available_exam_topics
2413
+
2414
+ # ========================================================================= #
2415
+ # === button_update_n_questions_were_answered?
2416
+ # ========================================================================= #
2417
+ def button_update_n_questions_were_answered?
2418
+ @internal_hash[:button_update_n_questions_were_answered]
2419
+ end
2420
+
2421
+ # ========================================================================= #
2422
+ # === update_the_label_n_questions_were_answered
2423
+ # ========================================================================= #
2424
+ def update_the_label_n_questions_were_answered(
2425
+ i = @label_n_questions_were_answered
2426
+ )
2427
+ i.set_text(
2428
+ return_string_how_many_exam_questions_are_already_answered
2429
+ )
2430
+ end; alias update_the_label_containing_the_last_exam_question update_the_label_n_questions_were_answered # === update_the_label_containing_the_last_exam_question
2431
+
2432
+ # ========================================================================= #
2433
+ # === return_checkbox_shall_we_reveal_the_answer
2434
+ #
2435
+ # This will only return the checkbox; creation must happen before
2436
+ # this method is called.
2437
+ # ========================================================================= #
2438
+ def return_checkbox_shall_we_reveal_the_answer
2439
+ @internal_hash[:checkbox_shall_we_reveal_the_answer]
2440
+ end; alias checkbox? return_checkbox_shall_we_reveal_the_answer # === checkbox?
2441
+ alias checkbox_shall_we_reveal_the_answer? return_checkbox_shall_we_reveal_the_answer # === checkbox_shall_we_reveal_the_answer?
2442
+
2443
+ # ========================================================================= #
2444
+ # === simply_assign_this_as_the_new_exam_topic_onto_the_primary_combobox
2445
+ #
2446
+ # This method does not work currently.
2447
+ # ========================================================================= #
2448
+ def simply_assign_this_as_the_new_exam_topic_onto_the_primary_combobox(
2449
+ i
2450
+ )
2451
+ combobox_available_exam_topics?.append_text(i.to_s)
2452
+ end
2453
+
2454
+ # ========================================================================= #
2455
+ # === main_grid?
2456
+ # ========================================================================= #
2457
+ def main_grid?
2458
+ @internal_hash[:main_grid]
2459
+ end
2460
+
2461
+ # ======================================================================= #
2462
+ # === entry_exam_topic_in_use?
2463
+ # ======================================================================= #
2464
+ def entry_exam_topic_in_use?
2465
+ @internal_hash[:entry_exam_topic_in_use]
2466
+ end; alias entry_for_the_current_exam_topic? entry_exam_topic_in_use? # === entry_for_the_current_exam_topic?
2467
+ alias entry_ask_questions_from_this_topic? entry_exam_topic_in_use? # === entry_ask_questions_from_this_topic?
2468
+ alias entry_for_the_exam_topic? entry_exam_topic_in_use? # === entry_for_the_exam_topic?
2469
+ alias entry_holding_all_exam_topics? entry_exam_topic_in_use? # === entry_ask_questions_from_this_topic?
2470
+ alias entry_current_exam_topic? entry_exam_topic_in_use? # === entry_current_exam_topic?
2471
+
2472
+ # ========================================================================= #
2473
+ # === create_then_return_the_default_grid
2474
+ # ========================================================================= #
2475
+ def create_then_return_the_default_grid
2476
+ grid = default_grid # main_grid?
2477
+ grid.pad2px
2478
+ grid.default_spacing(8)
2479
+ grid.width_height(width?, height?)
2480
+ grid.set_size_request(width?, height?)
2481
+ @internal_hash[:main_grid] = grid
2482
+ return grid
2483
+ end; alias create_the_main_grid create_then_return_the_default_grid # === create_the_main_grid
2484
+
2485
+ # ========================================================================= #
2486
+ # === create_the_skeleton (create tag, skeleton tag)
2487
+ # ========================================================================= #
2488
+ def create_the_skeleton
2489
+ create_the_entries # Should come fairly early - definitely before the grid is created.
2490
+ create_the_checkbox_shall_we_reveal_the_answer # ← Must come after the entries were created.
2491
+ create_text_buffer_for_the_answer # Must come before create_the_textviews().
2492
+ create_the_textviews
2493
+ create_the_combobox
2494
+ create_the_buttons
2495
+ create_the_editor
2496
+ create_the_labels # Should come after the editor was created.
2497
+ # create_the_emoji_toggle_widget # This currently does not work.
2498
+ create_the_thumbs_up_emoji
2499
+ create_the_context_menu # The context-menu can come last.
2500
+ # instantiate_the_control_panel # This one must come before the notebook tab is populated.
2501
+ create_the_main_grid
2502
+ create_the_notebook_tab # This must come late.
2503
+ end; alias create_skeleton create_the_skeleton # === create_skeleton
2504
+
2505
+ # ========================================================================= #
2506
+ # === connect_the_notebook_tab
2507
+ #
2508
+ # This method will connect the notebook with the main Gtk::Window in use.
2509
+ # ========================================================================= #
2510
+ def connect_the_notebook_tab(
2511
+ window = main_window?,
2512
+ padding_to_use = 2
2513
+ )
2514
+ # @notebook_tab.halign = 0.5
2515
+ scrolled_window = create_scrolled_window(@notebook_tab)
2516
+ scrolled_window.show_all
2517
+ window.add(scrolled_window) # , padding_to_use)
2518
+ window.show_all
2519
+ end
2520
+
2521
+ # ========================================================================= #
2522
+ # === create_the_notebook_tab (notebook tag)
2523
+ # ========================================================================= #
2524
+ def create_the_notebook_tab
2525
+ # ======================================================================= #
2526
+ # === @notebook_tab
2527
+ # ======================================================================= #
2528
+ @notebook_tab = create_notebook { :make_it_scrollable }
2529
+ @notebook_tab.css_class('notebook_for_the_exam_trainer')
2530
+ @notebook_tab.the_tabs_appear_on_top
2531
+ @notebook_tab.can_be_rearranged
2532
+ @notebook_tab.do_show_the_tabs
2533
+ @notebook_tab.do_show_the_border
2534
+ end
2535
+
2536
+ # ========================================================================= #
2537
+ # === the_first_notebook_tab_is_active
2538
+ # ========================================================================= #
2539
+ def the_first_notebook_tab_is_active
2540
+ @notebook_tab.the_first_notebook_tab_is_active
2541
+ end
2542
+
2543
+ # ========================================================================= #
2544
+ # === populate_the_notebook_tab
2545
+ # ========================================================================= #
2546
+ def populate_the_notebook_tab
2547
+ # ======================================================================= #
2548
+ # We could display a Curriculum in a notebook-tab. Unfortunately, in
2549
+ # 2021, this is a bit wide, and makes the whole notebook appear too
2550
+ # large, so it was disabled again, until we improve on it. We probably
2551
+ # have to decrease its size from the get go, and manage it at all
2552
+ # times via scrolled-widgets.
2553
+ #
2554
+ # The old code is shown next:
2555
+ #
2556
+ # label4 = modify_bold_label('Curriculum Viewer', @internal_hash[:colour_to_use_for_the_notebook_labels])
2557
+ # @notebook_tab.add_tab(::Studium::GUI::Gtk::CurriculumViewer.new, label4)
2558
+ #
2559
+ # ======================================================================= #
2560
+ show_ten_aliases = show_ten_aliases?
2561
+ # ======================================================================= #
2562
+ # === Add the first tab, containing the "Exam Trainer" widget next
2563
+ #
2564
+ # This will be contained in @first_vbox, which in turn contains
2565
+ # the @horizontal_pane variable.
2566
+ # ======================================================================= #
2567
+ @notebook_tab.append_page(
2568
+ main_grid?,
2569
+ modify_bold_label('Exam trainer', @internal_hash[:colour_to_use_for_the_notebook_labels])
2570
+ )
2571
+ if use_the_internal_editor?
2572
+ # ===================================================================== #
2573
+ # Append the editor in this event:
2574
+ # ===================================================================== #
2575
+ @notebook_tab.append_page(@editor, bold_text('editor'))
2576
+ end
2577
+ if Object.const_defined?(:Roebe) and show_ten_aliases
2578
+ # ===================================================================== #
2579
+ # Designate the parent widget next:
2580
+ # ===================================================================== #
2581
+ show_ten_aliases.set_parent_widget(self)
2582
+ # ===================================================================== #
2583
+ # And append the show-ten-aliases widget next:
2584
+ # ===================================================================== #
2585
+ @notebook_tab.append_page(
2586
+ show_ten_aliases,
2587
+ modify_bold_label(
2588
+ 'Current top-ten exams', @internal_hash[:colour_to_use_for_the_notebook_labels]
2589
+ )
2590
+ )
2591
+ end
2592
+ @notebook_tab.the_first_tab_is_active
2593
+ # ======================================================================= #
2594
+ # === Add the tab that includes the Control Panel
2595
+ # ======================================================================= #
2596
+ # label2 = modify_bold_label('Control Panel', @internal_hash[:colour_to_use_for_the_notebook_labels])
2597
+ # @notebook_tab.append_page(
2598
+ # @control_panel,
2599
+ # label2
2600
+ # )
2601
+ end
2602
+
2603
+ # ========================================================================= #
2604
+ # === Studium::GUI::UniversalWidgets::ExamTrainer.run
2605
+ # ========================================================================= #
2606
+ def self.run(
2607
+ i = ARGV
2608
+ )
2609
+ require 'gtk_paradise/run'
2610
+ _ = ::Studium::GUI::UniversalWidgets::ExamTrainer.new(i)
2611
+ r = ::Gtk.run
2612
+ r << _
2613
+ _.set_parent_widget(r) # Designate it as the parent widget.
2614
+ _.enable_the_main_key_combinations
2615
+ r.add_context_menu_with_the_default_accel_group
2616
+ r.on_button_press_event { |widget, event|
2617
+ if ::Gtk.right_mouse_click?(event) # right mouse click event.
2618
+ _.context_menu?.popup_based_on_this_event(event)
2619
+ end
2620
+ }
2621
+ r.automatic_size_then_automatic_title
2622
+ r.enable_quick_exit
2623
+ r.move_to(x: 15, y: 0)
2624
+ r.run
2625
+ end
2626
+
2627
+ # ========================================================================= #
2628
+ # === resize_the_notebook_tab_towards_the_primary_width_and_height
2629
+ # ========================================================================= #
2630
+ def resize_the_notebook_tab_towards_the_primary_width_and_height
2631
+ _ = @notebook_tab
2632
+ _.set_size_request(width?, height?)
2633
+ end
2634
+
2635
+ # ========================================================================= #
2636
+ # === return_button_solve_the_question
2637
+ #
2638
+ # The old String was:
2639
+ #
2640
+ # '_Solve the exam question'
2641
+ #
2642
+ # ========================================================================= #
2643
+ def return_button_solve_the_question
2644
+ _ = bold_button('😁️ Mark the question as _solved ✓', self, :use_a_mnemonic) {
2645
+ :button_solve_the_exam_question_was_clicked
2646
+ }
2647
+ # ======================================================================= #
2648
+ # .set_size_request() is not necessary as we use a separate method
2649
+ # that controls the size of the widget at hand.
2650
+ # ======================================================================= #
2651
+ _.hint =
2652
+ 'Use this button to <span weight="bold" foreground="lightgreen">mark '\
2653
+ 'the question as solved</span> - that is, it is now '\
2654
+ '<b>correctly answered</b>).'
2655
+ # button_solve_the_question.set_size_request(78, 30)
2656
+ return _
2657
+ end
2658
+
2659
+ # ========================================================================= #
2660
+ # === array_all_exam_questions?
2661
+ #
2662
+ # Query-method to keep track of all exam-questions that were asked in
2663
+ # the current run.
2664
+ # ========================================================================= #
2665
+ def array_all_exam_questions?
2666
+ @internal_hash[:array_all_exam_questions]
2667
+ end; alias all_exam_questions array_all_exam_questions? # === all_exam_questions
2668
+
2669
+ # ========================================================================= #
2670
+ # === update_array_all_exam_questions
2671
+ # ========================================================================= #
2672
+ def update_array_all_exam_questions
2673
+ @internal_hash[:array_all_exam_questions] = []
2674
+ end
2675
+
2676
+ # ========================================================================= #
2677
+ # === do_popup_the_array_of_all_exam_questions
2678
+ #
2679
+ # This method will be called then whe icon-with-glasses is clicked.
2680
+ # ========================================================================= #
2681
+ def do_popup_the_array_of_all_exam_questions(
2682
+ array = :infer
2683
+ )
2684
+ case array
2685
+ # ======================================================================= #
2686
+ # === :infer
2687
+ # ======================================================================= #
2688
+ when :infer
2689
+ array = Studium.return_all_exam_questions_from_this_topic(
2690
+ entry_exam_topic_as_string?
2691
+ )
2692
+ end
2693
+ content = array.map.with_index {|line, index| index += 1
2694
+ line = line.dup
2695
+ line.prepend(
2696
+ "(#{index}) "
2697
+ )
2698
+ line
2699
+ }.join("\n")
2700
+ text_buffer = create_text_buffer(content)
2701
+ text_view = create_text_view(text_buffer)
2702
+ scrolled_window = create_scrolled_window(text_view)
2703
+ scrolled_window.width_height(1200, 700)
2704
+ scrolled_window.pad8px
2705
+ # scrolled_window.add(text_view)
2706
+ scrolled_window.show_all
2707
+ popup_over_this_widget(
2708
+ scrolled_window,
2709
+ text_view,
2710
+ entry_for_the_exam_topic?
2711
+ ).popup
2712
+ end
2713
+
2714
+ # ========================================================================= #
2715
+ # === do_popup_the_you_have_to_provide_an_exam_topic
2716
+ # ========================================================================= #
2717
+ def do_popup_the_you_have_to_provide_an_exam_topic
2718
+ bold_popover_message = bold_label(
2719
+ "You have to provide an exam-topic, in the exam-topic entry.\n\n"\
2720
+ "The arrow should indicate the proper entry."
2721
+ )
2722
+ popover_message( # Nudge the user here.
2723
+ bold_popover_message,
2724
+ entry_for_the_exam_topic?
2725
+ ).popup
2726
+ end
2727
+
2728
+ # ========================================================================= #
2729
+ # === exam_topic_from_the_correct_entry?
2730
+ #
2731
+ # This method must always return a string, hence the .to_s call.
2732
+ # ========================================================================= #
2733
+ def exam_topic_from_the_correct_entry?
2734
+ entry_exam_topic_in_use?.text?.to_s.strip # This must always be a String.
2735
+ end; alias current_exam_topic? exam_topic_from_the_correct_entry? # === current_exam_topic?
2736
+ alias main_exam_topic? exam_topic_from_the_correct_entry? # === main_exam_topic?
2737
+ alias exam_topic? exam_topic_from_the_correct_entry? # === exam_topic?
2738
+ alias current_topic? exam_topic_from_the_correct_entry? # === current_topic?
2739
+ alias entry_exam_topic? exam_topic_from_the_correct_entry? # === exam_topic?
2740
+ alias entry_ask_questions? exam_topic_from_the_correct_entry? # === entry_ask_questions?
2741
+ alias entry_ask_questions_from_this_topic? exam_topic_from_the_correct_entry? # === entry_ask_questions_from_this_topic?
2742
+ alias entry_exam_topic_as_string? exam_topic_from_the_correct_entry? # === entry_exam_topic_as_string?
2743
+
2744
+ # ======================================================================= #
2745
+ # === sync_combo_box_entry_onto_the_current_exam_entry
2746
+ # ======================================================================= #
2747
+ def sync_combo_box_entry_onto_the_current_exam_entry(
2748
+ i = combo_box?.entry?
2749
+ )
2750
+ _ = ::Studium.find_corresponding_exam_title(i)
2751
+ set_current_exam_topic(_)
2752
+ end
2753
+
2754
+ # ========================================================================= #
2755
+ # === do_update_the_entry_n_unanswered_questions
2756
+ #
2757
+ # This method depends on two entries being set correctly.
2758
+ # ========================================================================= #
2759
+ def do_update_the_entry_n_unanswered_questions
2760
+ _ = entry_containing_n_questions?.text?.to_i -
2761
+ entry_containing_n_answers?.text?.to_i
2762
+ entry_containing_n_unanswered_questions?.set_text(_.to_s)
2763
+ end; alias update_the_entry_n_unanswered_questions do_update_the_entry_n_unanswered_questions # === update_the_entry_n_unanswered_questions
2764
+ alias update_n_unanswered do_update_the_entry_n_unanswered_questions # === update_n_unanswered
2765
+
2766
+ # ========================================================================= #
2767
+ # === set_n_percentage_of_questions_answered
2768
+ #
2769
+ # An alternative would be:
2770
+ #
2771
+ # percentage_value = Studium.n_percent_questions_answered_of_this_topic?(
2772
+ # use_this_exam_topic.downcase
2773
+ # )
2774
+ #
2775
+ # ========================================================================= #
2776
+ def set_n_percentage_of_questions_answered(i)
2777
+ percentage_value = -1 if percentage_value == false # Weak "safeguard".
2778
+ i = i.to_f.round(1)
2779
+ entry_percentage?.set_text("#{i}%") # Sync it onto the proper entry.
2780
+ end; alias set_n_percentage set_n_percentage_of_questions_answered # === set_n_percentage
2781
+ alias update_the_percentage_entry set_n_percentage_of_questions_answered # === update_the_percentage_entry
2782
+ alias do_update_this_entry_with_that_exam_topic_for_its_percentage_value set_n_percentage_of_questions_answered # === do_update_this_entry_with_that_exam_topic_for_its_percentage_value
2783
+
2784
+ # ======================================================================= #
2785
+ # === handle_the_combo_box_available_exam_topics_on_changed_event
2786
+ # ======================================================================= #
2787
+ def handle_the_combo_box_available_exam_topics_on_changed_event
2788
+ clear_question_buffer
2789
+ # ===================================================================== #
2790
+ # Now we need to sync from the combo-box towards the current
2791
+ # exam-entry.
2792
+ # ===================================================================== #
2793
+ sync_combo_box_entry_onto_the_current_exam_entry
2794
+ one_two_three
2795
+ end; alias do_handle_the_combobox_available_exam_topics_on_changed_event handle_the_combo_box_available_exam_topics_on_changed_event # === do_handle_the_combobox_available_exam_topics_on_changed_event
2796
+ alias sync_the_current_exam_topic_onto_the_exam_topic_entry handle_the_combo_box_available_exam_topics_on_changed_event # === sync_the_current_exam_topic_onto_the_exam_topic_entry
2797
+
2798
+ # ========================================================================= #
2799
+ # === create_the_checkbox_shall_we_reveal_the_answer
2800
+ # ========================================================================= #
2801
+ def create_the_checkbox_shall_we_reveal_the_answer(
2802
+ entry_delay_to_use = entry_delay_to_use?
2803
+ )
2804
+ _ = create_checkbox(
2805
+ " Automatically reveal the \n answer after a delay"
2806
+ )
2807
+ _.set_font(smallest_font?)
2808
+ # ======================================================================= #
2809
+ # Next determine whether the checkbox is active, on startup, or whether
2810
+ # it is not active when the GUI starts up.
2811
+ # ======================================================================= #
2812
+ _.mark_as_checked # Should be checked as-is.
2813
+ _.hint =
2814
+ 'Deselect this if you do not want to automatically reveal the answer. '\
2815
+ 'In that case you have to manually click on the Answer button.'
2816
+ _.on_toggled { |widget|
2817
+ if _.active?
2818
+ entry_delay_to_use.grey_in
2819
+ elsif not _.active?
2820
+ entry_delay_to_use.grey_out
2821
+ end
2822
+ }
2823
+ if _.is_it_active?
2824
+ entry_delay_to_use.grey_in
2825
+ else
2826
+ entry_delay_to_use.grey_out
2827
+ end
2828
+ # ======================================================================= #
2829
+ # === @internal_hash[:checkbox_shall_we_reveal_the_answer]
2830
+ # ======================================================================= #
2831
+ @internal_hash[:checkbox_shall_we_reveal_the_answer] = _
2832
+ end
2833
+
2834
+ # ========================================================================= #
2835
+ # === button_ask_the_exam_question_was_clicked (clicked tag)
2836
+ #
2837
+ # This is the most important button of this GUI.
2838
+ # ========================================================================= #
2839
+ def button_ask_the_exam_question_was_clicked(
2840
+ use_this_topic =
2841
+ :obtain_the_exam_topic_from_the_relevant_entry
2842
+ )
2843
+ case use_this_topic
2844
+ # ======================================================================= #
2845
+ # === :obtain_the_exam_topic_from_the_relevant_entry
2846
+ # ======================================================================= #
2847
+ when :obtain_the_exam_topic_from_the_relevant_entry
2848
+ use_this_topic = entry_exam_topic_in_use?.text?.to_s
2849
+ end
2850
+ we_may_reveal_the_exam_answer
2851
+ one_two_three(use_this_topic)
2852
+ end; alias do_handle_the_click_event_for_the_ask_question_button button_ask_the_exam_question_was_clicked # === do_handle_the_click_event_for_the_ask_question_button
2853
+ alias ask_an_exam_question button_ask_the_exam_question_was_clicked # === ask_an_exam_question
2854
+ alias do_ask_the_exam_question button_ask_the_exam_question_was_clicked # === do_ask_the_exam_question
2855
+ alias do_ask_a_new_question button_ask_the_exam_question_was_clicked # === do_ask_a_new_question
2856
+ alias trigger_the_event_when_the_ask_exam_question_button_was_clicked button_ask_the_exam_question_was_clicked # === trigger_the_event_when_the_ask_exam_question_button_was_clicked
2857
+ alias ask_an_exam_question button_ask_the_exam_question_was_clicked # === ask_an_exam_question
2858
+ alias do_ask_an_exam_question button_ask_the_exam_question_was_clicked # === do_ask_an_exam_question
2859
+ alias do_ask_a_new_exam_question button_ask_the_exam_question_was_clicked # === do_ask_a_new_exam_question
2860
+ alias the_button_ask_the_question_was_clicked button_ask_the_exam_question_was_clicked # === the_button_ask_the_question_was_clicked
2861
+ alias the_button_ask_the_exam_question_was_clicked button_ask_the_exam_question_was_clicked # === the_button_ask_the_exam_question_was_clicked
2862
+
2863
+ # ========================================================================= #
2864
+ # === entry_for_sleeping_n_seconds?
2865
+ # ========================================================================= #
2866
+ def entry_for_sleeping_n_seconds?
2867
+ @internal_hash[:entry_for_sleeping_n_seconds]
2868
+ end; alias entry_delay_to_use? entry_for_sleeping_n_seconds? # === entry_delay_to_use
2869
+ alias entry_sleep_n_seconds? entry_for_sleeping_n_seconds? # === entry_sleep_n_seconds?
2870
+ alias entry_delay? entry_for_sleeping_n_seconds? # === entry_delay?
2871
+ alias return_entry_for_sleeping_n_seconds entry_for_sleeping_n_seconds? # === return_entry_for_sleeping_n_seconds
2872
+ alias return_the_entry_sleep_n_seconds entry_for_sleeping_n_seconds? # === return_the_entry_sleep_n_seconds
2873
+
2874
+ # ========================================================================= #
2875
+ # === entry_delay_value?
2876
+ # ========================================================================= #
2877
+ def entry_delay_value?
2878
+ entry_for_sleeping_n_seconds?.text?.to_f
2879
+ end
2880
+
2881
+ # ========================================================================= #
2882
+ # === exam_question_object?
2883
+ # ========================================================================= #
2884
+ def exam_question_object?
2885
+ @internal_hash[:exam_question_object]
2886
+ end
2887
+
2888
+ # ========================================================================= #
2889
+ # === create_the_reveal_the_answer_button
2890
+ #
2891
+ # This is the so-called "reveal button".
2892
+ # ========================================================================= #
2893
+ def create_the_reveal_the_answer_button
2894
+ # ======================================================================= #
2895
+ # === @internal_hash[:button_reveal_the_answer] (answer tag)
2896
+ #
2897
+ # The reveal-button is created next, also known as the "answer button".
2898
+ # The mnemonic-key is set to "A", so that we can toggle between
2899
+ # "Q" and "A" for "Question" and "Answer" respectively.
2900
+ # ======================================================================= #
2901
+ _ = bold_button('Reveal the _Answer', self, true) { # This was the old emoji: ❗
2902
+ :the_button_reveal_the_answer_was_clicked
2903
+ }
2904
+ _.set_size_request(78, 30)
2905
+ #_.on_hover_lightblue
2906
+ _.hint = 'Click on this button in order to '\
2907
+ 'reveal the answer to the current exam question at hand.'
2908
+ @internal_hash[:button_reveal_the_answer] = _
2909
+ end; alias create_the_reveal_button create_the_reveal_the_answer_button # === create_the_reveal_button
2910
+
2911
+ # ========================================================================= #
2912
+ # === set_exam_answer (answer tag)
2913
+ # ========================================================================= #
2914
+ def set_exam_answer(
2915
+ i = answer_is?,
2916
+ apply_these_filters = [:filter_away_tags]
2917
+ )
2918
+ i = sanitize_the_answer(i.to_s, apply_these_filters)
2919
+ i = ::Gtk.replace_all_URL_entries_in_this_string(i)
2920
+ i.lstrip!
2921
+ i.sub!(/A: /,'') if i.start_with? 'A: '
2922
+ # ================================================================= #
2923
+ # Replace all "(2) foo" entries with "(2) foo\n" entries.
2924
+ # ================================================================= #
2925
+ i = ::Studium.add_newlines_to_numbered_exam_question(i)
2926
+ @internal_hash[:exam_answer] = i
2927
+ textview2?.set_text(i)
2928
+ end; alias set_answer set_exam_answer # === set_answer
2929
+
2930
+ # ========================================================================= #
2931
+ # === exam_answer?
2932
+ # ========================================================================= #
2933
+ def exam_answer?
2934
+ @internal_hash[:exam_answer]
2935
+ end
2936
+
2937
+ # ========================================================================= #
2938
+ # === always_reveal_the_exam_answer_via_this_method
2939
+ #
2940
+ # This method will ALWAYS reveal the exam-answer.
2941
+ # ========================================================================= #
2942
+ def always_reveal_the_exam_answer_via_this_method
2943
+ set_exam_answer
2944
+ always_reset_the_delay_before_using_another_delay
2945
+ end
2946
+
2947
+ # ========================================================================= #
2948
+ # === may_we_reveal_the_answer_after_a_delay?
2949
+ # ========================================================================= #
2950
+ def may_we_reveal_the_answer_after_a_delay?
2951
+ @internal_hash[:may_we_reveal_the_answer_after_a_delay]
2952
+ end; alias may_we_reveal_the_answer? may_we_reveal_the_answer_after_a_delay? # === may_we_reveal_the_answer?
2953
+
2954
+ # ========================================================================= #
2955
+ # === do_sleep_now (sleep tag)
2956
+ # ========================================================================= #
2957
+ def do_sleep_now(
2958
+ i = :default,
2959
+ use_this_as_timeout = 0
2960
+ )
2961
+ case i
2962
+ # ======================================================================= #
2963
+ # === :default
2964
+ #
2965
+ # This will always obtain the value from the proper entry.
2966
+ # ======================================================================= #
2967
+ when :default,
2968
+ :use_the_correct_entry_for_the_delay
2969
+ i = entry_sleep_n_seconds?.text?
2970
+ end
2971
+ i = i.to_f # Always use a float here.
2972
+ # ======================================================================= #
2973
+ # An alternative to sleep() would be this:
2974
+ #
2975
+ # GLib::Timeout.add(use_this_as_timeout) {
2976
+ # @text_view_for_the_answer.set_text(answer)
2977
+ # false
2978
+ # }
2979
+ #
2980
+ # ======================================================================= #
2981
+ if use_this_as_timeout >= 0 and
2982
+ checkbox_shall_we_reveal_the_answer?.is_it_active?
2983
+ sleep(i)
2984
+ end
2985
+ end
2986
+
2987
+ # ========================================================================= #
2988
+ # === one_two_three (one_two_three tag)
2989
+ # ========================================================================= #
2990
+ def one_two_three(
2991
+ use_this_topic =
2992
+ exam_topic_from_the_correct_entry?
2993
+ )
2994
+ update_array_all_exam_questions
2995
+ if use_this_topic.empty?
2996
+ # ===================================================================== #
2997
+ # First protect against empty exam topics, with a helpful message to
2998
+ # the user.
2999
+ # ===================================================================== #
3000
+ do_popup_the_you_have_to_provide_an_exam_topic
3001
+ end
3002
+ unless ::Studium.is_this_exam_topic_available?(use_this_topic)
3003
+ # ===================================================================== #
3004
+ # Here we must notify the user that this exam-topic is not registered
3005
+ # aka not available.
3006
+ # ===================================================================== #
3007
+ popover_message( # Nudge the user here.
3008
+ text(
3009
+ ' <b>⚠️</b> No exam-entry called <b>'+use_this_topic.to_s+
3010
+ '</b> is available. <b>⚠️</b>'
3011
+ ),
3012
+ entry_for_the_exam_topic?
3013
+ ).popup
3014
+ return
3015
+ end
3016
+ local_file = Studium.local_exam_file(use_this_topic)
3017
+ if File.exist?(local_file)
3018
+ update_hash_dataset_of_all_lectures
3019
+ # ===================================================================== #
3020
+ # (1) Pass the current exam topic into a method that will return
3021
+ # an Array.
3022
+ # ===================================================================== #
3023
+ # array = Studium.return_an_array_for_this_exam_topic(use_this_topic)
3024
+ dataset = Studium.read_in_unanswered_exam_questions_from_this_file(local_file)
3025
+ sample = dataset.sample
3026
+ n_exam_questions_in_total = Studium.n_exam_questions_in_this_topic?(File.basename(local_file))
3027
+ n_unanswered_exam_questions = dataset.size
3028
+ n_answered_exam_questions = n_exam_questions_in_total - n_unanswered_exam_questions
3029
+ # ===================================================================== #
3030
+ # (3) Next we must update various entries:
3031
+ # ===================================================================== #
3032
+ set_n_exam_questions_exist_in_total(n_exam_questions_in_total)
3033
+ set_n_unanswered_questions(n_unanswered_exam_questions)
3034
+ set_n_exam_questions_were_already_answered(n_answered_exam_questions)
3035
+ set_n_percentage(
3036
+ n_answered_exam_questions.to_f * 100.0 / n_exam_questions_in_total
3037
+ )
3038
+ if entry_percentage?.text?.to_f == 100.0
3039
+ # =================================================================== #
3040
+ # Handle the case where the exam-topic at hand has been answered
3041
+ # completely.
3042
+ # =================================================================== #
3043
+ bold_popover_message = label(
3044
+ "All questions have been answered for the topic <b>"\
3045
+ "#{current_exam_topic?}</b>.\n\n <b>Please choose another exam topic</b>.\n"
3046
+ )
3047
+ popover_message(
3048
+ bold_popover_message,
3049
+ button_ask_the_exam_question?
3050
+ ).popup
3051
+ else
3052
+ # =================================================================== #
3053
+ # Next keep a backup-reference
3054
+ # =================================================================== #
3055
+ ::Studium.set_last_exam_question_line(sample)
3056
+ # =================================================================== #
3057
+ # Keep a reference to the exam-question object:
3058
+ # =================================================================== #
3059
+ @internal_hash[:exam_question_object] = Studium::Exams::ExamQuestion.new(sample)
3060
+ @internal_hash[:may_we_reveal_the_answer_after_a_delay] = true
3061
+ clear_the_exam_answer
3062
+ last_exam_question_asked = current_exam_question?
3063
+ set_exam_question(
3064
+ @internal_hash[:exam_question_object].question?,
3065
+ :remove_tags
3066
+ )
3067
+ Thread.new {
3068
+ if may_we_reveal_the_answer_after_a_delay?
3069
+ do_sleep_now(:use_the_correct_entry_for_the_delay)
3070
+ unless last_exam_question_asked == current_exam_question?
3071
+ reveal_the_exam_answer(:but_only_if_we_may)
3072
+ end
3073
+ end
3074
+ }
3075
+ end
3076
+ else
3077
+ e "No file exists at `#{local_file}`."
3078
+ end
3079
+ end; alias update_n_questions one_two_three # === update_n_questions
3080
+ alias update_three_important_widgets one_two_three # === update_three_important_widgets
3081
+
3082
+ # ========================================================================= #
3083
+ # === reveal_the_exam_answer
3084
+ # ========================================================================= #
3085
+ def reveal_the_exam_answer(
3086
+ may_we_reveal_the_exam_answer = may_we_reveal_the_answer_after_a_delay?
3087
+ )
3088
+ case may_we_reveal_the_exam_answer
3089
+ # ========================================================================= #
3090
+ # === true
3091
+ # ========================================================================= #
3092
+ when true
3093
+ set_exam_answer
3094
+ # ========================================================================= #
3095
+ # === :but_only_if_we_may
3096
+ # ========================================================================= #
3097
+ when :but_only_if_we_may
3098
+ may_we_reveal_the_exam_answer = may_we_reveal_the_answer_after_a_delay?
3099
+ set_exam_answer if may_we_reveal_the_exam_answer
3100
+ end
3101
+ end; alias reveal_the_answer_to_the_exam_question set_exam_answer # === reveal_the_answer_to_the_exam_question
3102
+
3103
+ # ========================================================================= #
3104
+ # === exam_question?
3105
+ # ========================================================================= #
3106
+ def exam_question?
3107
+ @internal_hash[:exam_question]
3108
+ end; alias current_exam_question? exam_question? # === current_exam_question?
3109
+
3110
+ # ========================================================================= #
3111
+ # === button_reveal_the_answer_was_clicked
3112
+ # ========================================================================= #
3113
+ def button_reveal_the_answer_was_clicked
3114
+ if all_questions_have_been_answered_in_this_topic?
3115
+ notify_the_user_that_all_questions_have_been_answered_in_this_topic(
3116
+ current_topic?,
3117
+ _
3118
+ )
3119
+ else
3120
+ always_reveal_the_exam_answer_via_this_method
3121
+ we_may_not_reveal_the_exam_answer_anymore
3122
+ end
3123
+ end; alias the_button_reveal_the_answer_was_clicked button_reveal_the_answer_was_clicked # === the_button_reveal_the_answer_was_clicked
3124
+
3125
+ # ========================================================================= #
3126
+ # === return_button_ask_the_exam_question (ask tag)
3127
+ # ========================================================================= #
3128
+ def return_button_ask_the_exam_question(
3129
+ use_emoji = false
3130
+ )
3131
+ # ======================================================================= #
3132
+ # Add the ask-exam-question button next. Note that its click-event
3133
+ # is handled separately via a method call.
3134
+ #
3135
+ # The question mark emoji is Unicode Character "❓" (U+2753).
3136
+ # ======================================================================= #
3137
+ if use_emoji?
3138
+ _ = bold_button(mnemonic: 'Ask an exam _Question ❓')
3139
+ else
3140
+ _ = bold_button(mnemonic: 'Ask an exam _Question')
3141
+ end
3142
+ _.clear_background
3143
+ _.width_height(780, 38)
3144
+ _.pad2px
3145
+ _.hint =
3146
+ 'Click on this button to ask an exam-question. '\
3147
+ '(Or, use alt+q as shortcut)'
3148
+ _.on_clicked {
3149
+ # ===================================================================== #
3150
+ # Determine what happens next when the ask-question button is clicked.
3151
+ # ===================================================================== #
3152
+ trigger_the_event_when_the_ask_exam_question_button_was_clicked
3153
+ }
3154
+ return _
3155
+ end; alias return_button_ask_an_exam_question return_button_ask_the_exam_question # === return_button_ask_an_exam_question
3156
+
3157
+ # ========================================================================= #
3158
+ # === we_may_reveal_the_exam_answer
3159
+ # ========================================================================= #
3160
+ def we_may_reveal_the_exam_answer
3161
+ @internal_hash[:may_we_reveal_the_answer_after_a_delay] = true
3162
+ end
3163
+
3164
+ # ========================================================================= #
3165
+ # === always_reset_the_delay_before_using_another_delay
3166
+ # ========================================================================= #
3167
+ def always_reset_the_delay_before_using_another_delay
3168
+ we_may_not_reveal_the_exam_answer_anymore
3169
+ end
3170
+
3171
+ # ========================================================================= #
3172
+ # === we_may_not_reveal_the_exam_answer_anymore
3173
+ # ========================================================================= #
3174
+ def we_may_not_reveal_the_exam_answer_anymore
3175
+ # ======================================================================= #
3176
+ # === @internal_hash[:may_we_reveal_the_answer_after_a_delay]
3177
+ # ======================================================================= #
3178
+ @internal_hash[:may_we_reveal_the_answer_after_a_delay] = false
3179
+ end
3180
+
3181
+ # ========================================================================= #
3182
+ # === consider_making_available_the_show_ten_aliases_widget
3183
+ # ========================================================================= #
3184
+ def consider_making_available_the_show_ten_aliases_widget
3185
+ # ======================================================================= #
3186
+ # The next if-clause must come after @internal_hash has been
3187
+ # defined.
3188
+ # ======================================================================= #
3189
+ if Object.const_defined?(:Roebe)
3190
+ begin
3191
+ require 'roebe/gui/gtk3/show_ten_aliases/show_ten_aliases.rb'
3192
+ @internal_hash[:show_ten_aliases] = ::Roebe::GUI::Gtk::ShowTenAliases.new
3193
+ rescue LoadError; end
3194
+ end
3195
+ end
3196
+
3197
+ # ========================================================================= #
3198
+ # === show_ten_aliases?
3199
+ # ========================================================================= #
3200
+ def show_ten_aliases?
3201
+ @internal_hash[:show_ten_aliases]
3202
+ end
3203
+
3204
+ # ========================================================================= #
3205
+ # === connect_the_skeleton (connect tag)
3206
+ # ========================================================================= #
3207
+ def connect_the_skeleton
3208
+ abort_on_exception
3209
+ add_the_status_icon
3210
+ r = create_window_or_runner(nil, width?, height?, title?)
3211
+ properly_prepare_this_window(
3212
+ r,
3213
+ return_the_default_hash_for_properly_preparing_this_window
3214
+ )
3215
+ do_style_all_buttons_uniformly
3216
+ do_assign_the_default_exam_topic_to_the_correct_entry
3217
+ let_the_scrolled_window_for_the_answer_parse_URLs
3218
+ deselect_the_entry_containing_the_exam_topic
3219
+ do_jump_into_the_entry_containing_the_current_exam_topic
3220
+ parse_the_commandline_arguments
3221
+ populate_the_main_grid(main_grid?) # Populate the main grid here next.
3222
+ populate_the_notebook_tab
3223
+ connect_the_notebook_tab(r)
3224
+ r.top_left
3225
+ set_parent_widget(r) # Designate it as the parent widget.
3226
+ enable_the_main_key_combinations
3227
+ r.add_context_menu_with_the_default_accel_group
3228
+ r.on_button_press_event { |widget, event|
3229
+ if ::Gtk.right_mouse_click?(event) # right mouse click event.
3230
+ _.context_menu?.popup_based_on_this_event(event)
3231
+ end
3232
+ }
3233
+ # r.automatic_size_then_automatic_title
3234
+ r.show_all
3235
+ the_first_notebook_tab_is_active
3236
+ r.enable_quick_exit
3237
+ r.set_default_size(width?, height?)
3238
+ # resize_the_notebook_tab_towards_the_primary_width_and_height
3239
+ run_main
3240
+ end
3241
+
3242
+ # ========================================================================= #
3243
+ # === run (run tag)
3244
+ # ========================================================================= #
3245
+ def run
3246
+ run_super
3247
+ end
3248
+
3249
+ # ========================================================================= #
3250
+ # === Studium::GUI::UniversalWidgets::ExamTrainer[]
3251
+ # ========================================================================= #
3252
+ def self.[](i = ARGV)
3253
+ new(i)
3254
+ end
3255
+
3256
+ # ========================================================================= #
3257
+ # Last but not least, add two "compatibility constants":
3258
+ # ========================================================================= #
3259
+ AskExamQuestion = ExamTrainer
3260
+ SimpleExamTrainer = ExamTrainer # And add a helper "alias" here.
3261
+
3262
+ end; end; end; end
3263
+
3264
+ if __FILE__ == $PROGRAM_NAME
3265
+ Studium::GUI::UniversalWidgets::ExamTrainer.new(ARGV)
3266
+ end # gtkexamtrainer 2