mono_bottom_panel.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. /*************************************************************************/
  2. /* mono_bottom_panel.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "mono_bottom_panel.h"
  31. #include "../csharp_script.h"
  32. #include "godotsharp_editor.h"
  33. MonoBottomPanel *MonoBottomPanel::singleton = NULL;
  34. void MonoBottomPanel::_update_build_tabs_list() {
  35. build_tabs_list->clear();
  36. int current_tab = build_tabs->get_current_tab();
  37. bool no_current_tab = current_tab < 0 || current_tab >= build_tabs->get_tab_count();
  38. for (int i = 0; i < build_tabs->get_child_count(); i++) {
  39. MonoBuildTab *tab = Object::cast_to<MonoBuildTab>(build_tabs->get_child(i));
  40. if (tab) {
  41. String item_name = tab->build_info.solution.get_file().get_basename();
  42. item_name += " [" + tab->build_info.configuration + "]";
  43. build_tabs_list->add_item(item_name, tab->get_icon_texture());
  44. String item_tooltip = String("Solution: ") + tab->build_info.solution;
  45. item_tooltip += String("\nConfiguration: ") + tab->build_info.configuration;
  46. item_tooltip += String("\nStatus: ");
  47. if (tab->build_exited) {
  48. item_tooltip += tab->build_result == MonoBuildTab::RESULT_SUCCESS ? "Succeeded" : "Errored";
  49. } else {
  50. item_tooltip += "Running";
  51. }
  52. if (!tab->build_exited || !tab->build_result == MonoBuildTab::RESULT_SUCCESS) {
  53. item_tooltip += "\nErrors: " + itos(tab->error_count);
  54. }
  55. item_tooltip += "\nWarnings: " + itos(tab->warning_count);
  56. build_tabs_list->set_item_tooltip(i, item_tooltip);
  57. if (no_current_tab || current_tab == i) {
  58. build_tabs_list->select(i);
  59. _build_tab_item_selected(i);
  60. }
  61. }
  62. }
  63. }
  64. void MonoBottomPanel::add_build_tab(MonoBuildTab *p_build_tab) {
  65. build_tabs->add_child(p_build_tab);
  66. raise_build_tab(p_build_tab);
  67. }
  68. void MonoBottomPanel::raise_build_tab(MonoBuildTab *p_build_tab) {
  69. ERR_FAIL_COND(p_build_tab->get_parent() != build_tabs);
  70. build_tabs->move_child(p_build_tab, 0);
  71. _update_build_tabs_list();
  72. }
  73. void MonoBottomPanel::show_build_tab() {
  74. for (int i = 0; i < panel_tabs->get_tab_count(); i++) {
  75. if (panel_tabs->get_tab_control(i) == panel_builds_tab) {
  76. panel_tabs->set_current_tab(i);
  77. editor->make_bottom_panel_item_visible(this);
  78. return;
  79. }
  80. }
  81. ERR_PRINT("Builds tab not found");
  82. }
  83. void MonoBottomPanel::_build_tab_item_selected(int p_idx) {
  84. ERR_FAIL_INDEX(p_idx, build_tabs->get_tab_count());
  85. build_tabs->set_current_tab(p_idx);
  86. }
  87. void MonoBottomPanel::_build_tab_changed(int p_idx) {
  88. if (p_idx < 0 || p_idx >= build_tabs->get_tab_count()) {
  89. warnings_btn->set_visible(false);
  90. errors_btn->set_visible(false);
  91. } else {
  92. warnings_btn->set_visible(true);
  93. errors_btn->set_visible(true);
  94. }
  95. }
  96. void MonoBottomPanel::_warnings_toggled(bool p_pressed) {
  97. int current_tab = build_tabs->get_current_tab();
  98. ERR_FAIL_INDEX(current_tab, build_tabs->get_tab_count());
  99. MonoBuildTab *build_tab = Object::cast_to<MonoBuildTab>(build_tabs->get_child(current_tab));
  100. build_tab->warnings_visible = p_pressed;
  101. build_tab->_update_issues_list();
  102. }
  103. void MonoBottomPanel::_errors_toggled(bool p_pressed) {
  104. int current_tab = build_tabs->get_current_tab();
  105. ERR_FAIL_INDEX(current_tab, build_tabs->get_tab_count());
  106. MonoBuildTab *build_tab = Object::cast_to<MonoBuildTab>(build_tabs->get_child(current_tab));
  107. build_tab->errors_visible = p_pressed;
  108. build_tab->_update_issues_list();
  109. }
  110. void MonoBottomPanel::_notification(int p_what) {
  111. switch (p_what) {
  112. case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
  113. panel_tabs->add_style_override("panel", editor->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles"));
  114. panel_tabs->add_style_override("tab_fg", editor->get_gui_base()->get_stylebox("DebuggerTabFG", "EditorStyles"));
  115. panel_tabs->add_style_override("tab_bg", editor->get_gui_base()->get_stylebox("DebuggerTabBG", "EditorStyles"));
  116. } break;
  117. }
  118. }
  119. void MonoBottomPanel::_bind_methods() {
  120. ClassDB::bind_method(D_METHOD("_warnings_toggled", "pressed"), &MonoBottomPanel::_warnings_toggled);
  121. ClassDB::bind_method(D_METHOD("_errors_toggled", "pressed"), &MonoBottomPanel::_errors_toggled);
  122. ClassDB::bind_method(D_METHOD("_build_tab_item_selected", "idx"), &MonoBottomPanel::_build_tab_item_selected);
  123. ClassDB::bind_method(D_METHOD("_build_tab_changed", "idx"), &MonoBottomPanel::_build_tab_changed);
  124. }
  125. MonoBottomPanel::MonoBottomPanel(EditorNode *p_editor) {
  126. singleton = this;
  127. editor = p_editor;
  128. set_v_size_flags(SIZE_EXPAND_FILL);
  129. set_anchors_and_margins_preset(Control::PRESET_WIDE);
  130. panel_tabs = memnew(TabContainer);
  131. panel_tabs->set_tab_align(TabContainer::ALIGN_LEFT);
  132. panel_tabs->add_style_override("panel", editor->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles"));
  133. panel_tabs->add_style_override("tab_fg", editor->get_gui_base()->get_stylebox("DebuggerTabFG", "EditorStyles"));
  134. panel_tabs->add_style_override("tab_bg", editor->get_gui_base()->get_stylebox("DebuggerTabBG", "EditorStyles"));
  135. panel_tabs->set_custom_minimum_size(Size2(0, 228) * EDSCALE);
  136. panel_tabs->set_v_size_flags(SIZE_EXPAND_FILL);
  137. add_child(panel_tabs);
  138. { // Builds
  139. panel_builds_tab = memnew(VBoxContainer);
  140. panel_builds_tab->set_name(TTR("Builds"));
  141. panel_builds_tab->set_h_size_flags(SIZE_EXPAND_FILL);
  142. panel_tabs->add_child(panel_builds_tab);
  143. HBoxContainer *toolbar_hbc = memnew(HBoxContainer);
  144. toolbar_hbc->set_h_size_flags(SIZE_EXPAND_FILL);
  145. panel_builds_tab->add_child(toolbar_hbc);
  146. toolbar_hbc->add_spacer();
  147. warnings_btn = memnew(ToolButton);
  148. warnings_btn->set_text("Warnings");
  149. warnings_btn->set_toggle_mode(true);
  150. warnings_btn->set_pressed(true);
  151. warnings_btn->set_visible(false);
  152. warnings_btn->set_focus_mode(FOCUS_NONE);
  153. warnings_btn->connect("toggled", this, "_warnings_toggled");
  154. toolbar_hbc->add_child(warnings_btn);
  155. errors_btn = memnew(ToolButton);
  156. errors_btn->set_text("Errors");
  157. errors_btn->set_toggle_mode(true);
  158. errors_btn->set_pressed(true);
  159. errors_btn->set_visible(false);
  160. errors_btn->set_focus_mode(FOCUS_NONE);
  161. errors_btn->connect("toggled", this, "_errors_toggled");
  162. toolbar_hbc->add_child(errors_btn);
  163. HSplitContainer *hsc = memnew(HSplitContainer);
  164. hsc->set_h_size_flags(SIZE_EXPAND_FILL);
  165. hsc->set_v_size_flags(SIZE_EXPAND_FILL);
  166. panel_builds_tab->add_child(hsc);
  167. build_tabs_list = memnew(ItemList);
  168. build_tabs_list->set_h_size_flags(SIZE_EXPAND_FILL);
  169. build_tabs_list->connect("item_selected", this, "_build_tab_item_selected");
  170. hsc->add_child(build_tabs_list);
  171. build_tabs = memnew(TabContainer);
  172. build_tabs->set_tab_align(TabContainer::ALIGN_LEFT);
  173. build_tabs->set_h_size_flags(SIZE_EXPAND_FILL);
  174. build_tabs->set_tabs_visible(false);
  175. build_tabs->connect("tab_changed", this, "_build_tab_changed");
  176. hsc->add_child(build_tabs);
  177. }
  178. }
  179. MonoBottomPanel::~MonoBottomPanel() {
  180. singleton = NULL;
  181. }
  182. void MonoBuildTab::_load_issues_from_file(const String &p_csv_file) {
  183. FileAccessRef f = FileAccess::open(p_csv_file, FileAccess::READ);
  184. if (!f)
  185. return;
  186. while (!f->eof_reached()) {
  187. Vector<String> csv_line = f->get_csv_line();
  188. if (csv_line.size() == 1 && csv_line[0].empty())
  189. return;
  190. ERR_CONTINUE(csv_line.size() != 7);
  191. BuildIssue issue;
  192. issue.warning = csv_line[0] == "warning";
  193. issue.file = csv_line[1];
  194. issue.line = csv_line[2].to_int();
  195. issue.column = csv_line[3].to_int();
  196. issue.code = csv_line[4];
  197. issue.message = csv_line[5];
  198. issue.project_file = csv_line[6];
  199. if (issue.warning)
  200. warning_count += 1;
  201. else
  202. error_count += 1;
  203. issues.push_back(issue);
  204. }
  205. }
  206. void MonoBuildTab::_update_issues_list() {
  207. issues_list->clear();
  208. Ref<Texture> warning_icon = get_icon("Warning", "EditorIcons");
  209. Ref<Texture> error_icon = get_icon("Error", "EditorIcons");
  210. for (int i = 0; i < issues.size(); i++) {
  211. const BuildIssue &issue = issues[i];
  212. if (!(issue.warning ? warnings_visible : errors_visible))
  213. continue;
  214. String tooltip;
  215. tooltip += String("Message: ") + issue.message;
  216. if (issue.code.length()) {
  217. tooltip += String("\nCode: ") + issue.code;
  218. }
  219. tooltip += String("\nType: ") + (issue.warning ? "warning" : "error");
  220. String text;
  221. if (issue.file.length()) {
  222. String sline = String::num_int64(issue.line);
  223. String scolumn = String::num_int64(issue.column);
  224. text += issue.file + "(";
  225. text += sline + ",";
  226. text += scolumn + "): ";
  227. tooltip += "\nFile: " + issue.file;
  228. tooltip += "\nLine: " + sline;
  229. tooltip += "\nColumn: " + scolumn;
  230. }
  231. if (issue.project_file.length()) {
  232. tooltip += "\nProject: " + issue.project_file;
  233. }
  234. text += issue.message;
  235. int line_break_idx = text.find("\n");
  236. issues_list->add_item(line_break_idx == -1 ? text : text.substr(0, line_break_idx),
  237. issue.warning ? warning_icon : error_icon);
  238. int index = issues_list->get_item_count() - 1;
  239. issues_list->set_item_tooltip(index, tooltip);
  240. issues_list->set_item_metadata(index, i);
  241. }
  242. }
  243. Ref<Texture> MonoBuildTab::get_icon_texture() const {
  244. // FIXME these icons were removed... find something better
  245. if (build_exited) {
  246. if (build_result == RESULT_ERROR) {
  247. return get_icon("DependencyChangedHl", "EditorIcons");
  248. } else {
  249. return get_icon("DependencyOkHl", "EditorIcons");
  250. }
  251. } else {
  252. return get_icon("GraphTime", "EditorIcons");
  253. }
  254. }
  255. MonoBuildInfo MonoBuildTab::get_build_info() {
  256. return build_info;
  257. }
  258. void MonoBuildTab::on_build_start() {
  259. build_exited = false;
  260. issues.clear();
  261. warning_count = 0;
  262. error_count = 0;
  263. _update_issues_list();
  264. MonoBottomPanel::get_singleton()->raise_build_tab(this);
  265. }
  266. void MonoBuildTab::on_build_exit(BuildResult result) {
  267. build_exited = true;
  268. build_result = result;
  269. _load_issues_from_file(logs_dir.plus_file("msbuild_issues.csv"));
  270. _update_issues_list();
  271. MonoBottomPanel::get_singleton()->raise_build_tab(this);
  272. }
  273. void MonoBuildTab::on_build_exec_failed(const String &p_cause) {
  274. build_exited = true;
  275. build_result = RESULT_ERROR;
  276. issues_list->clear();
  277. BuildIssue issue;
  278. issue.message = p_cause;
  279. issue.warning = false;
  280. error_count += 1;
  281. issues.push_back(issue);
  282. _update_issues_list();
  283. MonoBottomPanel::get_singleton()->raise_build_tab(this);
  284. }
  285. void MonoBuildTab::restart_build() {
  286. ERR_FAIL_COND(!build_exited);
  287. GodotSharpBuilds::get_singleton()->restart_build(this);
  288. }
  289. void MonoBuildTab::stop_build() {
  290. ERR_FAIL_COND(build_exited);
  291. GodotSharpBuilds::get_singleton()->stop_build(this);
  292. }
  293. void MonoBuildTab::_issue_activated(int p_idx) {
  294. ERR_FAIL_INDEX(p_idx, issues.size());
  295. const BuildIssue &issue = issues[p_idx];
  296. if (issue.project_file.empty() && issue.file.empty())
  297. return;
  298. String project_dir = issue.project_file.length() ? issue.project_file.get_base_dir() : build_info.solution.get_base_dir();
  299. String file = project_dir.simplify_path().plus_file(issue.file.simplify_path());
  300. if (!FileAccess::exists(file))
  301. return;
  302. file = ProjectSettings::get_singleton()->localize_path(file);
  303. if (file.begins_with("res://")) {
  304. Ref<Script> script = ResourceLoader::load(file, CSharpLanguage::get_singleton()->get_type());
  305. if (script.is_valid() && ScriptEditor::get_singleton()->edit(script, issue.line, issue.column)) {
  306. EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT);
  307. }
  308. }
  309. }
  310. void MonoBuildTab::_bind_methods() {
  311. ClassDB::bind_method("_issue_activated", &MonoBuildTab::_issue_activated);
  312. }
  313. MonoBuildTab::MonoBuildTab(const MonoBuildInfo &p_build_info, const String &p_logs_dir) {
  314. build_info = p_build_info;
  315. logs_dir = p_logs_dir;
  316. build_exited = false;
  317. issues_list = memnew(ItemList);
  318. issues_list->set_v_size_flags(SIZE_EXPAND_FILL);
  319. issues_list->connect("item_activated", this, "_issue_activated");
  320. add_child(issues_list);
  321. error_count = 0;
  322. warning_count = 0;
  323. errors_visible = true;
  324. warnings_visible = true;
  325. }