#include "ide.h" struct EventsDlg : WithEventsLayout { struct CbInfo { String scope; String type; String name; }; String cls; Index existing_methods; // to avoid duplicite names Array cb; void GatherEvents(const String& var, Index& done, const String& cls); void CbEdit(One& ctrl); void Generate(String& ins, String& clip, const String& scope, bool in_line); typedef EventsDlg CLASSNAME; EventsDlg(const String& cls); }; int FilterId(int c) { return iscid(c) ? c : 0; } void EventsDlg::CbEdit(One& ctrl) { ctrl.Create().SetFilter(FilterId); } EventsDlg::EventsDlg(const String& cls) : cls(cls) { CtrlLayoutOKCancel(*this, "Events"); list.AddColumn("Defined"); list.AddColumn("Type"); list.AddColumn("Event"); list.AddColumn("New Method Name").Ctrls(THISBACK(CbEdit)); list.ColumnWidths("121 178 254 124"); list.SetLineCy(EditField::GetStdHeight()); list.EvenRowColor(); list.SetEditLineCy(); list.MultiSelect(); Sizeable().Zoomable(); for(const auto& f : ~CodeIndex()) for(const AnnotationItem& m : f.value.items) if(m.nest == cls) existing_methods.FindAdd(m.name); Index visited; GatherEvents("", visited, cls); Breaker(yes, IDYES); } void EventsDlg::GatherEvents(const String& var, Index& visited, const String& cls) { String h = cls + " " + var; if(IsNull(cls) || visited.Find(h) >= 0 || h.GetCount() > 200 || list.GetCount() > 500 || visited.GetCount() > 2000) return; visited.Add(h); for(const auto& f : ~CodeIndex()) for(const AnnotationItem& m : f.value.items) if(m.nest == cls && IsVariable(m.kind) && (m.pretty.StartsWith("Event<") || m.pretty.StartsWith("Gate<"))) { String n = m.name; String event = Merge(".", var, n); if(n == "WhenAction") n = "Action"; else { Vector ss = Split(event, '.'); for(int i = 0; i < ss.GetCount(); i++) { String& s = ss[i]; if(s == "WhenAction") s.Clear(); else { s.TrimStart("When"); if(s.GetCount()) s.Set(0, ToUpper(s[0])); } } n = Join(ss, ""); while(existing_methods.Find(n) >= 0) n = "On" + n; } list.Add(cls, m.type, event, n); } for(const auto& f : ~CodeIndex()) for(const AnnotationItem& m : f.value.items) if(m.id == cls && IsStruct(m.kind)) { // we cheat with With.. by splitting it to With... and TopWindow for(String s : Split(m.bases, [](int c) { return iscid(c) || c == ':' ? 0 : 1; })) GatherEvents(var, visited, s); } for(const auto& f : ~CodeIndex()) for(const AnnotationItem& m : f.value.items) { if(m.nest == cls && IsVariable(m.kind) && !IsSourceFile(f.key) && m.type.Find('&') < 0 && m.type.Find('*') < 0 && !m.name.StartsWith("dv___") && m.pretty.Find("static") < 0) { GatherEvents(Merge(".", var, m.name), visited, m.type); } } } void EventsDlg::Generate(String& ins, String& clip, const String& scope, bool in_line) { String n; Vector nn = Split(cls, ':'); if(nn.GetCount()) n = nn.Top(); String ac; for(int i = 0; i < list.GetCount(); i++) { if(list.IsSel(i)) { String type = list.Get(i, 1); String var = list.Get(i, 2); String method = list.Get(i, 3); String param; int q = type.Find('<'); if(q >= 0) { int qq = type.ReverseFind('>'); if(q < qq) { param = String(~type + q + 1, ~type + qq); } } q = var.ReverseFind('.'); ins << '\t'; if(q >= 0 && var.Mid(q + 1) == "WhenAction") ins << var.Mid(0, q) << " <<="; else ins << var << " ="; if(in_line) ins << " [=](" << param << ") {\n\t}\n\t\n"; else { ins << " THISFN(" << method << ");\n"; String t = type.StartsWith("Gate") ? "bool " : "void "; clip << t << n << "::" << method << "(" << param << ")\n{\n}\n\n"; ac << '\t' << t << method << "(" << param << ");\n"; } } } clip << ac; } INITBLOCK { RegisterGlobalConfig("EventsDlg"); } void AssistEditor::Events() { SortByKey(CodeIndex()); AnnotationItem cm = FindCurrentNest(); if(IsNull(cm.nest)) return; EventsDlg dlg(cm.nest); LoadFromGlobal(dlg, "EventsDlg"); int c = dlg.Run(); StoreToGlobal(dlg, "EventsDlg"); if(c != IDOK) return; String a, b; dlg.Generate(a, b, cm.nest, c == IDYES); Paste(a.ToWString()); if(c != IDYES) WriteClipboardText(b); }