#pragma once #include #include "utils/WaitSample.h" #include "wx/popupwin.h" #include "wx/dataview.h" #include "wx/headerctrl.h" #include #include //#include "utils/misc.h" // ---------------------------------------------------------------------------- // MyCustomRendererText // ---------------------------------------------------------------------------- extern std::vector sort_vec_map(const std::vector& src, int& sum); #define sepListWait ";" extern int s_pid_HIGHLIGH; class MyCustomRendererGraph : public wxDataViewCustomRenderer { public: // This renderer can be either activatable or editable, for demonstration // purposes. In real programs, you should select whether the user should be // able to activate or edit the cell and it doesn't make sense to switch // between the two -- but this is just an example, so it doesn't stop us. explicit MyCustomRendererGraph(wxDataViewCellMode mode, int column) : wxDataViewCustomRenderer("string", mode, wxALIGN_LEFT) { EnableEllipsize(wxELLIPSIZE_END); col = column; } virtual bool Render(wxRect rect, wxDC* dc, int state) wxOVERRIDE { wxString l; wxRect orig = rect; if (col < 2) { l = m_value; if (m_value == "ffffffffffffffff" || m_value == "-1") { l = "SUM"; RenderText(l, 0, rect, dc, state); return true; } } if (col == 0) { if (m_value[0] == '*') { l = m_value.AfterFirst('*'); // wxFont fn = dc->GetFont().Italic(); // wxDCFontChanger nfont(*dc, fn); dc->SetBrush(*wxLIGHT_GREY_BRUSH); dc->SetPen(*wxTRANSPARENT_PEN); rect.Deflate(1); dc->DrawRoundedRectangle(rect, 3); RenderText(l, 0, rect, dc, state); } else { l = m_value; RenderText(l, 0, rect, dc, state); } return true; } if (col == 1) { RenderText(l, 0, rect, dc, state); return true; } //dc->SetBrush( *wxLIGHT_GREY_BRUSH ); dc->SetBrush(*wxYELLOW_BRUSH); //dc->SetPen(*wxTRANSPARENT_PEN); dc->SetPen(*wxBLACK_PEN); rect.Deflate(1); //WaitSample*ws= static_cast(GetView())->GetSample(); //dc->DrawRoundedRectangle( rect, 3 ); wxFont fn = dc->GetFont(); fn.SetPointSize(fn.GetPointSize() - 1); wxDCFontChanger nfont(*dc, fn); wxString s = m_value, t; wxStringTokenizer tk(s, sepListWait, wxTOKEN_DEFAULT); bool isDis = true; bool isGrp = true; int f = 0; float itog = 0; int widt = orig.width - 20; wxPoint p(orig.x, orig.y); while (tk.HasMoreTokens()) { l = tk.GetNextToken(); if (f == 0) { float tmp; l = l.AfterLast(' '); wxSscanf(l, "%f", &tmp); itog = tmp; float sek = itog / 1000; wxString tt = wxString::Format("%.1f", sek); // time sec wxSize sz = GetTextExtent(tt); wxRect drw(orig.x + orig.width - sz.x - 2, orig.y, sz.x + 2, orig.GetHeight()); wxRect npos(0, 0, sz.x, sz.y); npos = npos.CentreIn(drw); dc->DrawText(tt, npos.x, npos.y); widt = orig.width - sz.x - 2; } if (f > 0) { float tmp; wxString w; long cl; l = l.AfterFirst(' '); wxSscanf(l, "%ld %f", &cl, &tmp); wxColour c(cl); //c.Set(cl); dc->SetBrush(c); int ww = widt * tmp; wxRect drw(p.x, p.y, ww, rect.GetHeight()); float sek = itog * tmp / 1000; wxString tt = wxString::Format("%.1f", sek); // time sec wxSize sz = GetTextExtent(tt); wxRect npos(0, 0, sz.x, sz.y); npos = npos.CentreIn(drw); dc->DrawRectangle(drw); { wxColour fg(ContrastColorBlackOrWhite(c)); wxDCTextColourChanger setfg(*dc, fg); if (sz.GetWidth() < drw.GetWidth()) dc->DrawText(tt, npos.x, npos.y); } p.x = p.x + ww; } f++; } return true; } virtual bool ActivateCell(const wxRect& WXUNUSED(cell), wxDataViewModel* WXUNUSED(model), const wxDataViewItem& WXUNUSED(item), unsigned int WXUNUSED(col), const wxMouseEvent* mouseEvent) wxOVERRIDE { return false; } virtual wxSize GetSize() const wxOVERRIDE { wxSize txtSize = GetTextExtent(m_value); int lines = m_value.Freq('\n') + 1; if (lines > 1) { // wxLogMessage("MyCustomRendererText GetSize() %s", position); txtSize.SetHeight(txtSize.GetHeight() * lines + 1 * lines); } else { #ifdef __WXGTK__ txtSize.SetHeight(txtSize.GetHeight() + 3); #else txtSize.SetHeight(-1); #endif } if (col == 2) txtSize.SetWidth(-1); else { //maxw = txtSize.GetWidth(); //maxw=wxMax(txtSize.GetWidth(), maxw); txtSize.SetWidth(txtSize.GetWidth() + 1); } return txtSize; //return GetView()->FromDIP(wxSize(60, 20)); } virtual bool SetValue(const wxVariant& value) wxOVERRIDE { m_value = value.GetString(); return true; } virtual bool GetValue(wxVariant& WXUNUSED(value)) const wxOVERRIDE { return true; } #if wxUSE_ACCESSIBILITY virtual wxString GetAccessibleDescription() const wxOVERRIDE { return m_value; } #endif // wxUSE_ACCESSIBILITY virtual bool HasEditorCtrl() const wxOVERRIDE { return false; } private: wxString m_value; int col; int maxw = -1; }; class MyIndexListModel : public wxDataViewIndexListModel { public: MyIndexListModel(WaitSample* w) { ws = w; } void SetAllRows(const std::vector& keys, const std::map& wait, bool isfp) { k = keys; w = wait; //IsFirstPid = isfp; Reset(keys.size()); } key3 GetRowValue(long row) { key3 r{}; if (row >= 0 && row < k.size()) { r = k[row]; } return r; } // Implement base class pure virtual methods. unsigned GetCount() const wxOVERRIDE { return k.size(); } void GetValueByRow(wxVariant& val, unsigned row, unsigned col) const wxOVERRIDE { //val=wxString::Format("r:%d,c:%d",row,col); //val = m_strings[row]; //if (row + 1 < m_strings.Count() && col == 1 ) val = m_strings[row + 1]; bool ishint = false; int r = row; if (!val.IsNull()) { //r = r * -1; ishint = true; } if (k.size() > 0) { key3 kk = k.at(r); if (col == 0) { long ttmp = kk.pid; if (kk.sum > 0) val = wxString::Format("*%ld", ttmp); // backend else val = wxString::Format("%ld", ttmp); } else val = wxString::Format("%llx", kk.qid); if (col == 2) { vec_int v = w.at(kk); int sz = v.size(); val = wxString::Format("count w=%d", sz); int itog = 0; std::vector map_sum_all = sort_vec_map(v, itog); int period = ws->getPeriod(); int total = itog; wxString h; if (total != 0) { wxString x = wxString::Format("all %ld", (long)itog * period); for (int i = 0; i < map_sum_all.size(); i++) { int wait_index = map_sum_all[i]; if (v[wait_index] == 0) continue; float w_sum = (v[wait_index] / (float)total); float sek = ((period * v[wait_index]) / 1000.0); wxString w_name = ws->GetName(wait_index, WAIT_NAME); wxString w_grp = ws->GetName(wait_index, WAIT_GRP); wxString full = ws->GetName(wait_index, WAIT_FULL); long clr = ws->GetColorByWaitName(full); wxString pr = wxString::Format("%s %ld %.3f", w_name, clr, w_sum); if (ishint) { if (!h.IsEmpty()) h += "\n"; h.Append(wxString::Format("%-8.1f%-15s", sek, w_name)); } else { if (!x.IsEmpty()) x += sepListWait; x += pr; } } if (ishint) val = h; else val = x; } } } } bool SetValueByRow(const wxVariant&, unsigned, unsigned) wxOVERRIDE { return false; } unsigned int GetRow(const wxDataViewItem& item) const wxOVERRIDE { unsigned int i; // wxUIntToPtr() i=wxPtrToUInt(item.GetID()); i=i-1; return i; } // 0 row = header unsigned int GetColumnCount() const wxOVERRIDE { return 0; } wxString GetColumnType(unsigned int) const wxOVERRIDE { return ""; } private: bool IsFirstPid = true; std::vector k; std::map w; WaitSample* ws = NULL; wxDECLARE_NO_COPY_CLASS(MyIndexListModel); }; //---------------------------------------------------------------------------- // SimpleTransientPopup //---------------------------------------------------------------------------- class wxTopActivity; class topDataViewCtrl; class SimpleTransientPopup : public wxFrame { public: friend class wxTopActivity; friend class topDataViewCtrl; SimpleTransientPopup(wxWindow* parent, bool scrolled, wxTopActivity* small_ctl, wxPoint p, wxString title); virtual ~SimpleTransientPopup(); // wxPopupTransientWindow virtual methods are all overridden to log them private: //wxScrolledWindow* m_panel; wxPanel* m_panel; wxTopActivity* top; topDataViewCtrl* dvc; wxObjectDataPtr m_index_list_model; wxPoint mouseDownPos_; bool dragg = false; wxTimer m_taskTimer; private: void OnMouse(wxMouseEvent& event); void OnSize(wxSizeEvent& event); void OnSetFocus(wxFocusEvent& event); void OnKillFocus(wxFocusEvent& event); void OnTimerEvent(wxTimerEvent& pEvent); void OnClose(wxCommandEvent& event); private: wxDECLARE_ABSTRACT_CLASS(SimpleTransientPopup); wxDECLARE_EVENT_TABLE(); }; struct title_info { bool iner = false; bool remove; bool down_line; int total; wxString title; }; /// /// Графический элемент отображающий данные WaitSample /// Может использоваться в двух режимах. /// class wxTopActivity : public wxControl { WaitSample* ws; wxString m_title; wxSize setsize; wxArrayString seriosName; std::vector xAxis; std::vector yAxis; std::vector val; std::vector colors; std::vector m_title_i; std::map m_collapse; std::map m_sumtotal; wxPoint mouse, mouseS; wxRect m_area; int m_click = 0; int m_fix_detail_idx = -1; // fix sel Range wxDateTime fix_pos_L; wxDateTime fix_pos_R; wxPoint m_fix_pos; // context win wxString m_filter_detail; long long m_qid_filter = -1; bool m_regroup = false; int m_lastInterval = 0; int m_RightTime = -1; wxString m_filter; int m_agg_int = 5000; int m_count_wait; int m_inter[9] = { 5000 ,// 5 sek 10000 ,//10 sek 30000 ,//30 s 60000 ,//1 min 5 * 60000 ,//5 min 10 * 60000,//10 min 15 * 60000,//15 min 30 * 60000,//30 min 60 * 60000 //60 min }; SimpleTransientPopup* m_simplePopup; void paintSelRange(wxDC& dc, int width_sample); public: wxTopActivity(wxWindow* parent, WaitSample* WS, wxSize sz); wxSize DoGetBestClientSize(); int getAggregateInterval() { return m_agg_int; }; void setViewRange(int m_aggregate_interval, int RightTime); WaitSample* getViewRange(int& m_aggregate_interval, int& RightTime); void paintEvent(wxPaintEvent& evt); void OnEraseBackground(wxEraseEvent& event); void paintNow(); void SetFilter(long long qid); /// /// Возвращает время указаной границы /// /// true для левой границы, инаце правая /// int getTimeSelRange(bool isLeftRange); void render(wxDC& dc); // some useful events void mouseMoved(wxMouseEvent& event); void mouseDown(wxMouseEvent& event); void mouseWheelMoved(wxMouseEvent& event); void mouseReleased(wxMouseEvent& event); void rightClick(wxMouseEvent& event); void mouseLeftWindow(wxMouseEvent& event); void keyPressed(wxKeyEvent& event); void keyReleased(wxKeyEvent& event); void resize(wxSizeEvent& event); DECLARE_EVENT_TABLE() }; class topDataViewCtrl : public wxDataViewCtrl { public: topDataViewCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, wxTopActivity* topactive = NULL, const wxValidator& validator = wxDefaultValidator, const wxString& name = wxASCII_STR(wxDataViewCtrlNameStr) ) : wxDataViewCtrl(parent, id, pos, size, style, validator, name) { //SetMinSize(wxSize(300,200)); top = topactive; w = NULL; m_win_s = NULL; w = top->getViewRange(agg, right_g); Bind(wxEVT_DATAVIEW_COLUMN_HEADER_CLICK, [&](wxDataViewEvent& event) { int col = event.GetColumn(); if (GetColumn(col)->GetTitle() == "PID") { ignoreBG = !ignoreBG; CalcRowsDataView(true, ispidfirst); Refresh(); } }); Bind(wxEVT_DATAVIEW_ITEM_ACTIVATED, [&](wxDataViewEvent& event) { int col = event.GetColumn(); wxDataViewItem item(event.GetItem()); long row = wxPtrToUInt(item.GetID()); row--; if (col == 1) //qid { MyIndexListModel* m = static_cast(GetModel()); key3 k = m->GetRowValue(row); if (k.qid != -1) top->SetFilter(k.qid); } if (col == 0) { //pid MyIndexListModel* m = static_cast(GetModel()); key3 k = m->GetRowValue(row); if (k.pid > 0) s_pid_HIGHLIGH = k.pid; // else // s_pid_HIGHLIGH = -1; } }); Bind(wxEVT_DATAVIEW_COLUMN_REORDERED, [&](wxDataViewEvent& event) { wxDataViewColumn* const col = event.GetDataViewColumn(); if (!col) { return; } ispidfirst = col->GetTitle() == "PID" && event.GetColumn() == 0; if (!ispidfirst) ispidfirst = col->GetTitle() == "QID" && event.GetColumn() == 1; CalcRowsDataView(true, ispidfirst); Refresh(); if (m_win_s != NULL) m_win_s->Refresh(); }); Bind(wxEVT_CHAR, [&](wxKeyEvent& event) { bool fnd = false; wxChar charcode = event.GetUnicodeKey(); int l = m_find.length(); if (event.GetKeyCode() == WXK_ESCAPE) { //GetParent()->Close(true); m_find = ""; if (m_win_s != NULL) { m_win_s->Destroy(); m_win_s = NULL; } } else if (event.GetKeyCode() == WXK_F3) { //GetParent()->Close(true); fnd = true; } else if (event.GetKeyCode() == WXK_BACK) { if (l > 0) m_find.RemoveLast(); //m_win_s->SetValue(m_find); fnd = true; } else if (wxIsprint(charcode)) { //txt->EmulateKeyPress(event); m_find += charcode; fnd = true; } //else // event.Skip(); if (fnd) { if (m_win_s == NULL && m_find.length() > 0) { wxRect r; r.width = GetColumn(0)->GetWidth(); #ifdef __WXGTK__ r.height = GTKGetUniformRowHeight(); #endif wxWindow* t = this; #ifdef WIN32 //wxWindow* t = this->GenericGetHeader(); r.height = this->GenericGetHeader()->GetSize().GetHeight(); #else #endif m_win_s = new wxTextCtrl(t, wxID_ANY, "", r.GetPosition(), r.GetSize(), wxTE_PROCESS_ENTER | wxTE_READONLY ); m_win_s->SetInsertionPointEnd(); } if (m_win_s != NULL) { m_win_s->SetValue(m_find); m_win_s->Refresh(); } if (m_find.length() > 0) { MyIndexListModel* m = static_cast(GetModel()); wxDataViewItem item(GetCurrentItem()); long row = wxPtrToUInt(item.GetID()); if (!(row < m->GetCount())) row = 0; while (row != -1 && row < m->GetCount()) { key3 k = m->GetRowValue(row); wxString v = wxString::Format("%d,%llx", k.pid, k.qid); // m->GetValueByRow(v, row, 0); bool isfind = v.Contains(m_find); if (isfind) { wxDataViewItem it = wxDataViewItem(wxUIntToPtr(row + 1)); SetCurrentItem(it); EnsureVisible(it); return; } row++; } } return; } // end function event.Skip(); }); GetMainWindow()->Bind(wxEVT_MOTION, [&](wxMouseEvent& event) { if (event.Dragging()) return; wxClientDC dc(GetMainWindow()); PrepareDC(dc); //wxPoint logPos(event.GetLogicalPosition(dc)); //wxPoint mc= GetMainWindow()->ScreenToClient(event.GetPosition()); wxPoint mc = event.GetPosition(); wxString position; //position = wxString::Format("x=%d y=%d", logPos.x, logPos.y); //wxLogMessage("Mouse pos %s", position); int dy = 0; wxSize sz; #ifdef WIN32 wxHeaderCtrl* const header = GenericGetHeader(); if (header) { sz = header->GetSize(); //header->Refresh(); dy = sz.GetHeight(); } mc.y += dy; #else mc.y += 18; // only linux compile #endif wxDataViewItem item; wxDataViewColumn* column; HitTest(mc, item, column); if (item != NULL && column != NULL) { int row = wxPtrToUInt(item.GetID()) - 1; int ncol = column->GetModelColumn(); if (row >= 0) { if (column && column->GetModelColumn() == 2) { wxVariant vr; vr = "gethint"; if ((lastcol != ncol) || (lastrow != row)) { MyIndexListModel* m = static_cast(GetModel()); m->GetValueByRow(vr, row, ncol); GetMainWindow()->SetToolTip(vr.GetString()); lastrow = row; lastcol = ncol; } } else if (column && column->GetModelColumn() == 0) { // PID MyIndexListModel* m = static_cast(GetModel()); key3 k = m->GetRowValue(row); if (k.sum > 0) { if (((lastcol != ncol) || (lastrow != row))) { wxString s = w->GetBackendTypeName(k.sum); GetMainWindow()->SetToolTip(s); lastrow = row; lastcol = ncol; } } else { GetMainWindow()->UnsetToolTip(); lastcol = -1; } } else if (column && column->GetModelColumn() == 1) { //qid MyIndexListModel* m = static_cast(GetModel()); key3 k = m->GetRowValue(row); if (k.qid != 0) { if (((lastcol != ncol) || (lastrow != row))) { wxString s = w->GetQueryByQid(k.qid); if (s.IsEmpty()) s = "not found sql text"; GetMainWindow()->SetToolTip(s); lastrow = row; lastcol = ncol; } } else { GetMainWindow()->UnsetToolTip(); lastcol = -1; lastrow = -1; } } else { GetMainWindow()->UnsetToolTip(); lastcol = -1; } } } else { GetMainWindow()->UnsetToolTip(); lastcol = -1; ; lastrow = -1; } }); } WaitSample* GetSample() { return w; } void BuildColumn(int mode); bool CalcRowsDataView(bool force, bool IsPidFirst); //void AddRow(wxString csvtext); //void OnMouseMove(wxMouseEvent& event); //void OnMouseDown(wxMouseEvent& event); //void OnKEY_DOWN(wxKeyEvent& event); //void OnKEY_UP(wxKeyEvent& event); //void OnEVT_DATAVIEW_COLUMN_HEADER_CLICK(wxDataViewEvent& event); //void OnEVT_DATAVIEW_CONTEXT_MENU(wxCommandEvent& event); //void OnEVT_DATAVIEW_SELECTION_CHANGED(wxDataViewEvent& event); //void OnContextMenu(wxDataViewEvent& event); DECLARE_EVENT_TABLE() private: int lastrow = -1, lastcol = 1; int agg, right_g, left_g; bool ignoreBG = false; bool ispidfirst = true; wxString m_find; wxTextCtrl* m_win_s; wxTopActivity* top; WaitSample* w; }; #undef sepListWait