pgadmin3/utils/log/StorageModel.cpp
lsv 5aeb93b625 Optimization for linux.
Исправлено форматирование и учтены особенности GTK для корректного
отображения Log View.
2025-03-27 22:08:54 +05:00

546 lines
18 KiB
C++

#include "pgAdmin3.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/dataview.h"
#include "log/Storage.h"
#include "log/StorageModel.h"
#include "utils/utffile.h"
#include <wx/filename.h>
#include <wx/stdpaths.h>
// ----------------------------------------------------------------------------
// resources
// ----------------------------------------------------------------------------
#include "log/null.xpm"
#include "log/log_xpm.xpm"
#include "log/war_xpm.xpm"
#include "log/errorl_xpm.xpm"
#include "log/fatal_xpm.xpm"
#include "log/panic_xpm.xpm"
#include "log/user_xpm.xpm"
#include "log/wx_small.xpm"
// ----------------------------------------------------------------------------
// MyCustomRendererText
// ----------------------------------------------------------------------------
class MyCustomRendererText : public wxDataViewCustomRenderer
{
public:
StorageModel::cols col;
Storage* st;
int row;
int countRows = 0;
wxColour quoteselcolor;
// 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 MyCustomRendererText(wxDataViewCellMode mode, StorageModel::cols column)
: wxDataViewCustomRenderer("string", mode, wxALIGN_LEFT)
{
EnableEllipsize(wxELLIPSIZE_END);
col = column;
st = NULL;
wxColour textColour;
#ifdef __WXGTK__
textColour = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
#else
textColour = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT);
#endif // __WXGTK__
if (ContrastColorBlackOrWhite(textColour) == "#000000") {
quoteselcolor = wxColour(wxString("#7f7f7f"));
}
else quoteselcolor = *wxYELLOW;
}
virtual bool Render(wxRect rect, wxDC* dc, int state) wxOVERRIDE
{
//dc->SetBrush( *wxLIGHT_GREY_BRUSH );
if (state & wxDATAVIEW_CELL_SELECTED)
dc->SetBrush(quoteselcolor);
else
dc->SetBrush(*wxYELLOW_BRUSH);
dc->SetPen(*wxTRANSPARENT_PEN);
rect.Deflate(2);
wxRect orig = rect;
//dc->DrawRoundedRectangle( rect, 3 );
wxString s = m_value, t;
wxString rest;
wxString* pointer = &rest;
int x = 0, y = 0;
//dc->GetMultiLineTextExtent(m_value);
wxArrayInt arr;
wxSize h = dc->GetTextExtent("H");
dc->GetPartialTextExtents(m_value, arr);
bool ex = false;
int i = 0;
int startX = 0;
wxRect rectCol;
while (i < s.Len()) {
t = "";
x = 0;
bool inquote = false;
rectCol.x = rect.x;
rectCol.y = rect.y;
rectCol.height = h.GetHeight();
rectCol.width = 0;
while (i < s.Len())
{
if (s[i] == '\n') {
startX = arr[i];
i++;
break;
}
if (s[i] == '"') {
if (inquote) {
// закрытие кавычек
rectCol.width = arr[i] - rectCol.x;
rectCol.x = rectCol.x - startX + rect.x;
dc->DrawRoundedRectangle(rectCol, 3);
rectCol.x = arr[i];
rectCol.width = 0;
}
else
rectCol.x = arr[i];
inquote = !inquote;
}
t += s[i];
i++;
}
RenderText(t, x, rect, dc, state);
rect.y = rect.y + h.GetHeight() + 0;
rect.height = rect.height - (h.GetHeight() + 0);
ex = true;
}
if (!ex) RenderText(t, x, rect, dc, state);
if (countRows > 0 && col == StorageModel::cols::Col_Host) {
dc->SetBrush(*wxGREEN_BRUSH);
wxString str = wxString::Format("%d", countRows);
wxSize sz = dc->GetTextExtent(str);
sz.SetWidth(sz.GetX() + 3);
orig.SetLeft(orig.GetLeft() + (orig.GetWidth() - sz.GetWidth()));
orig.SetHeight(sz.GetHeight());
orig.SetWidth(sz.GetWidth());
dc->DrawRoundedRectangle(orig, 2);
RenderText(str,
1, // no offset
//wxRect(dc->GetTextExtent(m_value)).CentreIn(rect),
orig,
dc,
state);
}
return true;
RenderText(m_value,
0, // no offset
//wxRect(dc->GetTextExtent(m_value)).CentreIn(rect),
rect,
dc,
state);
return true;
}
virtual bool ActivateCell(const wxRect& WXUNUSED(cell),
wxDataViewModel* WXUNUSED(model),
const wxDataViewItem& WXUNUSED(item),
unsigned int WXUNUSED(col),
const wxMouseEvent* mouseEvent) wxOVERRIDE
{
wxString position;
if (mouseEvent)
position = wxString::Format("via mouse at %d, %d", mouseEvent->m_x, mouseEvent->m_y);
else
position = "from keyboard";
wxLogMessage("MyCustomRendererText ActivateCell() %s", position);
return false;
}
virtual wxSize GetSize() const wxOVERRIDE
{
wxSize txtSize = GetTextExtent(m_value);
//wxSize txtSize = GetDC()->GetMultiLineTextExtent(GetMultiLineTextExtent);
//wxSize txtSize = wxDataViewRenderer::GetDC()->GetMultiLineTextExtent(m_value);
int lines = m_value.Freq('\n') + 1;
if (lines > 1) {
wxString position;
position = wxString::Format("lines %d,hieght 1 row %d full h=%d", lines, txtSize.GetHeight(), txtSize.GetHeight() * lines + 1 * lines);
#ifdef __WXGTK__
wxSize charSize = GetTextExtent("H");
txtSize.SetHeight(txtSize.GetHeight() + charSize.GetHeight()/2);
#else
txtSize.SetHeight(txtSize.GetHeight() * lines + 1 * lines);
#endif
}
else
txtSize.SetHeight(-1);
txtSize.SetWidth(-1);
return txtSize;
//return GetView()->FromDIP(wxSize(60, 20));
}
virtual bool SetValue(const wxVariant& value) wxOVERRIDE
{
m_value = value.GetString();
if (!st) {
StorageModel* m = dynamic_cast<StorageModel*>(GetView()->GetModel());
st = m->getStorage();
}
if (st->IsGroupFilter()) {
row = st->getLastRowIndex();
countRows = st->getCountGroup(row);
}
else countRows = -1;
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 true; }
virtual wxWindow*
CreateEditorCtrl(wxWindow* parent,
wxRect labelRect,
const wxVariant& value) wxOVERRIDE
{
wxTextCtrl* text = new wxTextCtrl(parent, wxID_ANY, value,
labelRect.GetPosition(),
labelRect.GetSize(),
wxTE_PROCESS_ENTER);
text->SetInsertionPointEnd();
return text;
}
virtual bool
GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) wxOVERRIDE
{
wxTextCtrl* text = wxDynamicCast(ctrl, wxTextCtrl);
if (!text)
return false;
wxString sel = text->GetStringSelection();
if (sel.IsEmpty()) return false;
value = sel;
return true;
}
private:
wxString m_value;
};
// ----------------------------------------------------------------------------
// StorageModel
// ----------------------------------------------------------------------------
static int my_sort_reverse(int* v1, int* v2)
{
return *v2 - *v1;
}
static int my_sort(int* v1, int* v2)
{
return *v1 - *v2;
}
#define INITIAL_NUMBER_OF_ITEMS 0
void StorageModel::BuildColumns(MyDataViewCtrl* ctrl) {
wxDataViewColumn* const colIconText = new wxDataViewColumn
(
"Severity",
new wxDataViewIconTextRenderer(),
StorageModel::Col_ToggleIconText,
wxCOL_WIDTH_AUTOSIZE, wxALIGN_CENTER_VERTICAL
);
colmap[StorageModel::Col_ToggleIconText] = MyConst::colField::logSqlstate;
ctrl->AppendColumn(colIconText);
ctrl->AppendColumn(
new wxDataViewColumn("logTime",
new MyCustomRendererText(wxDATAVIEW_CELL_EDITABLE, StorageModel::Col_LogTime),
StorageModel::Col_LogTime,
wxCOL_WIDTH_AUTOSIZE,
wxALIGN_NOT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE
));
colmap[StorageModel::Col_LogTime] = MyConst::colField::logtime;
ctrl->AppendColumn(
new wxDataViewColumn("UserName",
new MyCustomRendererText(wxDATAVIEW_CELL_EDITABLE, StorageModel::Col_User),
StorageModel::Col_User,
wxCOL_WIDTH_AUTOSIZE,
wxALIGN_NOT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE
));
colmap[StorageModel::Col_User] = MyConst::colField::loguser;
ctrl->AppendColumn(
new wxDataViewColumn("DbName",
new MyCustomRendererText(wxDATAVIEW_CELL_EDITABLE, StorageModel::Col_Db),
StorageModel::Col_Db,
30,
wxALIGN_NOT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE
));
colmap[StorageModel::Col_Db] = MyConst::colField::logdb;
ctrl->AppendColumn(
new wxDataViewColumn("Pid",
new MyCustomRendererText(wxDATAVIEW_CELL_EDITABLE, StorageModel::Col_PID),
StorageModel::Col_PID,
60,
wxALIGN_NOT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE
));
colmap[StorageModel::Col_PID] = MyConst::colField::logpid;
ctrl->AppendColumn(
new wxDataViewColumn("Host",
new MyCustomRendererText(wxDATAVIEW_CELL_EDITABLE, StorageModel::Col_Host),
StorageModel::Col_Host,
90,
wxALIGN_NOT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE
));
colmap[StorageModel::Col_Host] = MyConst::colField::loghost;
ctrl->AppendColumn(
new wxDataViewColumn("AppName",
new MyCustomRendererText(wxDATAVIEW_CELL_EDITABLE, StorageModel::Col_App),
StorageModel::Col_App,
100,
wxALIGN_NOT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE
));
colmap[StorageModel::Col_App] = MyConst::colField::logappname;
ctrl->AppendColumn(
new wxDataViewColumn("Hint",
new MyCustomRendererText(wxDATAVIEW_CELL_EDITABLE, StorageModel::Col_Hint),
StorageModel::Col_Hint,
90,
wxALIGN_NOT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE
));
colmap[StorageModel::Col_Hint] = MyConst::colField::logHint;
ctrl->AppendColumn(
new wxDataViewColumn("Detail",
new MyCustomRendererText(wxDATAVIEW_CELL_EDITABLE, StorageModel::Col_Detail),
StorageModel::Col_Detail,
60,
wxALIGN_NOT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE
));
colmap[StorageModel::Col_Detail] = MyConst::colField::logDetail;
ctrl->AppendColumn(
new wxDataViewColumn("Message",
new MyCustomRendererText(wxDATAVIEW_CELL_EDITABLE, StorageModel::Col_Message),
StorageModel::Col_Message,
wxCOL_WIDTH_AUTOSIZE,
wxALIGN_NOT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE
));
colmap[StorageModel::Col_Message] = MyConst::colField::logMessage;
ctrl->AppendColumn(
new wxDataViewColumn("Server",
new MyCustomRendererText(wxDATAVIEW_CELL_EDITABLE, StorageModel::Col_Server),
StorageModel::Col_Server,
wxCOL_WIDTH_AUTOSIZE,
wxALIGN_NOT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE
));
colmap[StorageModel::Col_Server] = MyConst::colField::logSERVER;
}
#include <wx/textfile.h>
#include "log/filter_xpm.xpm"
StorageModel::~StorageModel() {
delete store;
}
StorageModel::StorageModel(MyDataViewCtrl* view) :
wxDataViewVirtualListModel(INITIAL_NUMBER_OF_ITEMS)
{
m_view = view;
//m_icon[0] = wxIcon(null_xpm);
m_icon[MyConst::iconIndex::log] = wxIcon(log_xpm);
m_icon[MyConst::iconIndex::war] = wxIcon(war_xpm);
m_icon[MyConst::iconIndex::user] = wxIcon(user_xpm);
m_icon[MyConst::iconIndex::error] = wxIcon(errorl_xpm);
m_icon[MyConst::iconIndex::fatal] = wxIcon(fatal_xpm);
m_icon[MyConst::iconIndex::panic] = wxIcon(panic_xpm);
bitmapflt = wxBitmap((wxIcon(filter_xpm)));
store = new Storage();
}
bool StorageModel::setFilter(int col, wxString val, int flags, MyDataViewCtrl* view) {
bool r = store->SetFilter(colmap[col], val, flags);
m_view->UnselectAll();
Reset(store->getCountFilter());
if (col != -1) {
wxDataViewColumn* vc = view->GetColumn(col);
vc->SetBitmap(bitmapflt);
}
return r;
}
bool StorageModel::setFilterArray(std::deque<LineFilter> arr,MyDataViewCtrl* view) {
bool r=store->SetFilterArray(arr);
view->UnselectAll();
Reset(store->getCountFilter());
setIconFilter(view);
return r;
}
void StorageModel::setIconFilter(MyDataViewCtrl* view) {
bool yesfilter = false;
for (int j = 0; j < view->GetColumnCount(); j++) {
int colt = 0;
yesfilter = false;
wxDataViewColumn* vc = view->GetColumn(j);
while (colt != -1) {
colt = testFilter(j, colt);
if (colt >= 0) {
//m->DropColFilter(colt);
vc->SetBitmap(bitmapflt);
yesfilter = true;
colt++;
break;
}
}
if (!yesfilter) vc->SetBitmap(wxNullBitmap);
}
}
int StorageModel::testFilter(int col, int position = 0) {
int idx = 0;
idx = store->testFilter(colmap[col], position);
return idx;
}
void StorageModel::ApplyFilter() {
store->ApplyFilter();
m_view->UnselectAll();
Reset(store->getCountFilter());
}
void StorageModel::DropColFilter(int index) {
if (index >= 0) store->DropColFilter(index);
}
bool StorageModel::Prepend(const wxString& text)
{
//m_toggleColValues.insert(m_toggleColValues.begin(), 0);
//m_textColValues.Insert(text, 0);
bool add=store->AddLineTextCSV(text);
if (!add) return false;
int row = store->getCountStore() - 1;
wxString val = store->GetFieldStorage(row, MyConst::colField::loguser, false);
IncCountFreq(StorageModel::Col_User, val);
IncCountFreq(StorageModel::Col_Db, store->GetFieldStorage(row, MyConst::colField::logdb, false));
IncCountFreq(StorageModel::Col_Host, store->GetFieldStorage(row, MyConst::colField::loghost, false));
val = store->GetFieldStorage(row, MyConst::colField::logappname, false);
//if (val.IsEmpty()) val = store->GetFieldStorage((int)row, MyConst::colField::logbtype,false);
IncCountFreq(StorageModel::Col_App, val);
IncCountFreq(StorageModel::Col_PID, store->GetFieldStorage(row, MyConst::colField::logpid, false));
IncCountFreq(StorageModel::Col_Hint, store->GetFieldStorage(row, MyConst::colField::logHint, false));
val = store->GetFieldStorage(row, MyConst::colField::logSqlstate, false);
IncCountFreq(StorageModel::Col_ToggleIconText, val);
val = store->GetFieldStorage(row, MyConst::colField::logSERVER, false);
IncCountFreq(StorageModel::Col_Server, val);
if (store->ApplyFilter(row)) {
RowAppended();
//RowPrepended();
return true;
}
if (store->IsGroupFilter()) {
}
return false;
}
void StorageModel::DeleteItem(const wxDataViewItem& item)
{
unsigned int row = GetRow(item);
RowDeleted(row);
}
void StorageModel::DeleteItems(const wxDataViewItemArray& items)
{
unsigned i;
wxArrayInt rows;
}
void StorageModel::AddMany()
{
Reset(GetCount() + 1000);
}
void StorageModel::GetValueByRow(wxVariant& variant,
unsigned int row, unsigned int col) const
{
MyConst::colField fldcsv = colmap[col];
wxString val;
val = store->GetField((int)row, fldcsv);
if (col == StorageModel::Col_ToggleIconText) {
int i = store->GetSeverityIndex((int)row);
variant << wxDataViewIconText(val, m_icon[i]);
return;
}
else if (col == StorageModel::Col_App) {
//if (val.IsEmpty()) val = store->GetField((int)row, MyConst::colField::logbtype);
}
else if (col == StorageModel::Col_User) {
};
variant = val;
}
bool StorageModel::GetAttrByRow(unsigned int row, unsigned int col,
wxDataViewItemAttr& attr) const
{
//attr.SetBackgroundColour(*wxLIGHT_GREY);
wxColor c = store->GetBgColorLine((int)row);
if (c.IsOk()) {
attr.SetBackgroundColour(c);
return true;
}
return false;
}
bool StorageModel::SetValueByRow(const wxVariant& variant,
unsigned int row, unsigned int col)
{
wxString flt = variant.GetString();
int flags = FL_CONTAINS;
if (flt[0] == '!') {
flags = flags | FL_REVERSE;
flt = flt.substr(1);
}
setFilter(col, flt, flags, m_view);
return false;
}