Extended hints

В результатах запроса, нажатием правой кнопки мыши можно вызвать окно
подсказки, с возможностью выделения содержимого и его копирования (Rbutton).
This commit is contained in:
lsv 2025-07-31 16:14:09 +05:00 committed by lsv
parent c2c44c18f1
commit 077de1ad7c
17 changed files with 4789 additions and 3946 deletions

View file

@ -132,7 +132,14 @@ wxString ctlListView::GetText(long row, long col)
item.SetColumn(col);
item.SetMask(wxLIST_MASK_TEXT);
GetItem(item);
return item.GetText();
wxString v = item.GetText();
if (storelongstring) {
int len = v.Length();
if (len==200 && row >= 0 && col==0 && row < longstring.size()) {
return longstring[row];
}
}
return v;
};
@ -151,7 +158,19 @@ void ctlListView::AddColumn(const wxString& text, int size, int format)
long ctlListView::AppendItem(int icon, const wxString& val, const wxString& val2, const wxString& val3, const wxString& val4)
{
long pos = InsertItem(GetItemCount(), val, icon);
long idx = GetItemCount();
long pos;
if (storelongstring) {
if (val.Length() > 200) {
longstring.push_back(val);
pos = InsertItem(idx, val.Mid(0,200), icon);
}
else {
longstring.push_back(wxEmptyString);
pos = InsertItem(idx, val, icon);
}
} else
pos = InsertItem(idx, val, icon);
if (!val2.IsEmpty())
SetItem(pos, 1, val2);
if (!val3.IsEmpty())

View file

@ -261,6 +261,13 @@ wxMenu* ctlNavigatePanel::GetPopupMenu() {
}
return NULL;
}
void ctlNavigatePanel::SetFindString(const wxString& findstr) {
logFindString = findstr;
items_find.clear();
FindText(logFindString, FOCUSNEXT, false);
Refresh();
}
bool ctlNavigatePanel::RunKeyCommand(wxKeyEvent& event,int numCmd) {
//wxAcceleratorEntry::ParseAccel(const wxString & text, int* flagsOut, int* keyOut);
wxJSONValue cmds = opt["commands"];
@ -693,7 +700,7 @@ void ctlNavigatePanel::OnMouse(wxMouseEvent& evt) {
wxString tt;
if (i >= 0 && i < items_mark.size() && items_mark[i] > pos) i--;
if (i >= 0 && i < items_mark.size() ) {
tt = ctrl->GetItemText(items_mark[i]);
tt = ctrl->GetText(items_mark[i]);
this->SetToolTip(tt);
}
else
@ -983,7 +990,7 @@ int ctlNavigatePanel::FindText(wxString findtext, int position, bool directionUp
// this item is selected - do whatever is needed with it
//wxLogMessage("Item %ld is focused.", item);
//long fpos = logList->FindItem(item, logFindString, true);
wxString s = ctrl->GetItemText(item);
wxString s = ctrl->GetText(item);
item++;
if (!(s.Find(logFindString) > -1)) {
continue;

View file

@ -30,6 +30,7 @@
#include "utils/FormatterSQL.h"
#include "utils/dlgTransformText.h"
#include "utils/TableColsMap.h"
#include "wx/display.h"
wxString ctlSQLBox::sqlKeywords;
static const wxString s_leftBrace(_T("([{"));
@ -591,9 +592,40 @@ void ctlSQLBox::OnFuncHelp(wxCommandEvent& ev) {
for (int i = tmp.Len()-1; i >=0; i--) key+=tmp[i];
}
delete m_PopupHelp;
m_PopupHelp = new popuphelp(this->GetParent(), key.Lower(), fh);
wxSize rr(450, 370);
m_PopupHelp = new popuphelp(this->GetParent(), key.Lower(), fh,p,rr);
if (m_PopupHelp && m_PopupHelp->IsValid() && rr != m_PopupHelp->GetSizePopup()) {
// recreate with new size
rr = m_PopupHelp->GetSizePopup();
delete m_PopupHelp;
m_PopupHelp = new popuphelp(this->GetParent(), key.Lower(), fh, p, rr);
}
if (m_PopupHelp && m_PopupHelp->IsValid()) {
m_PopupHelp->Position(p, wxSize(0, 17));
//m_PopupHelp->UpdateWindowUI(true);
wxSize top_sz=m_PopupHelp->GetSizePopup();
wxPoint posScreen;
wxSize sizeScreen;
const int displayNum = wxDisplay::GetFromPoint(p);
if (displayNum != wxNOT_FOUND)
{
const wxRect rectScreen = wxDisplay(displayNum).GetGeometry();
posScreen = rectScreen.GetPosition();
sizeScreen = rectScreen.GetSize();
}
else // outside of any display?
{
// just use the primary one then
posScreen = wxPoint(0, 0);
sizeScreen = wxGetDisplaySize();
}
wxSize top_new(top_sz);
wxPoint oldp(p);
if (p.x + top_new.x > sizeScreen.x) p.x = sizeScreen.x - top_new.x - 20;
if (p.y + top_new.y > sizeScreen.y) p.y = sizeScreen.y - top_new.y - 20;
if (oldp==p) p.x = p.x + 20;
m_PopupHelp->Move(p);
//m_PopupHelp->Position(p, wxSize(0, 17));
m_PopupHelp->Popup();
}
@ -1659,7 +1691,7 @@ void ctlSQLBox::OnMarginClick(wxStyledTextEvent &event)
event.Skip();
}
wxString ctlSQLBox::TextToHtml(int start, int end) {
wxString ctlSQLBox::TextToHtml(int start, int end,bool isAddNewLine) {
wxColor frColor[40];
wxString str;
wxColour frc = settings->GetSQLBoxColourForeground();
@ -1691,10 +1723,16 @@ wxString ctlSQLBox::TextToHtml(int start, int end) {
wxString sz;
sz.Printf("%d", fntSQLBox.GetPixelSize().GetHeight());
str = wxT("<div style=\"font-family: ") + fontName + wxT("; font-size: " + sz + "px\"><font>");
//str = wxT("<div style=\"font-family: ") + fontName + wxT("; font-size: " + sz + "px\"><font>");
str = wxString::Format("<div style=\"font-family: %s; font-size: %spx\"><font face=\"%s\" >", fontName, sz, fontName);
int k = 0;
int l = 1;
while (startp < endp) {
wxString newline = "<br>";
if (isAddNewLine) newline = L"\u2936<br>";
//if (isAddNewLine) newline = L"&ldca;<br>";
//if (isAddNewLine) newline = L"<br>\x0b78";
int lenstr = selText.Length();
while (k<lenstr) {
int st = GetStyleAt(startp);
if (st < 34) tColor = frColor[st].GetAsString(wxC2S_HTML_SYNTAX);
if (prevColor != tColor) {
@ -1703,15 +1741,16 @@ wxString ctlSQLBox::TextToHtml(int start, int end) {
}
//str.append(str[k].GetValue());
l = 1;
if (!selText[k].IsAscii()) l++;
wxUniChar c = selText[k];
if (!c.IsAscii()) l++;
int s = 0;
wxUniChar c = selText[k].GetValue();
//wxUniChar c = selText[k].GetValue();
if (c == '\r') { startp = startp + l; k++; continue; };
if (c == '\n') { str += wxT("<br>"); startp = startp + l; k++; continue; };
if (c == '\n') { str += newline; startp = startp + l; k++; continue; };
if (c == 9) s = 5;
if (c == 32) s = 1;
if (s > 0) for (int tt = 0; tt < s; tt++) str += wxT("&nbsp;");
else str += selText[k];
else str += c;
startp = startp + l; k++;
}
str = str + wxT("</font></div>");

View file

@ -22,12 +22,17 @@
#include <wx/regex.h>
#include "ctl/ctlSQLResult.h"
#include "utils/misc.h"
#include "utils/FunctionPGHelper.h"
#include "utils/PreviewHtml.h"
#define EXTRAEXTENT_HEIGHT 6
#define EXTRAEXTENT_WIDTH 6
//DEFINE_EVENT_TYPE(myEVT_SHOW_POPUP)
BEGIN_EVENT_TABLE(ctlSQLGrid, wxGrid)
EVT_MOUSEWHEEL(ctlSQLGrid::OnMouseWheel)
//EVT_CUSTOM(wxID_ANY, myEVT_SHOW_POPUP,ctlSQLGrid::OnShowPopup)
EVT_GRID_COL_SIZE(ctlSQLGrid::OnGridColSize)
EVT_GRID_LABEL_LEFT_CLICK(ctlSQLGrid::OnLabelClick)
EVT_GRID_CELL_RIGHT_CLICK(ctlSQLGrid::OnCellRightClick)
@ -66,7 +71,7 @@ ctlSQLGrid::ctlSQLGrid(wxWindow* parent, wxWindowID id, const wxPoint& pos, cons
event.Skip();
});
*/
Bind(wxEVT_THREAD, &ctlSQLGrid::OnShowPopup, this);
setresizedpi();
SetDefaultCellOverflow(false);
//SetDefaultRenderer(new wxGridCellAutoWrapStringRenderer);
@ -859,15 +864,132 @@ void ctlSQLGrid::OnLabelDoubleClick(wxGridEvent& event)
}
}
}
void ctlSQLGrid::OnMouseEvent(wxMouseEvent& event)
{
if (event.RightDown()) {
wxGridEvent ev;
OnCellRightClick(ev);
return;
}
event.Skip();
}
void ctlSQLGrid::OnShowPopup(wxThreadEvent& event) {
// wxMessageBox("omshowpopup "+event.GetString(), "msg");
wxString s = event.GetString();
wxPoint p = rpos;
wxPoint p1(rpos);
wxString bg;
wxColour bgColor = settings->GetSQLBoxColourBackground();
if (settings->GetSQLBoxUseSystemBackground())
{
bgColor = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
}
bg = bgColor.GetAsString(wxC2S_HTML_SYNTAX);
// parse context
wxRegEx r(L"(?im)(select|from|where|set|insert|into|delete)\\b", wxRE_NEWLINE);
int cnt = 0;
if (r.IsValid()) {
size_t start=0;
std::unordered_set<wxString> unic;
while (r.Matches(s.Mid(start))) {
size_t start2 = 0, len2 = 0;
r.GetMatch(&start2, &len2, 1);
unic.insert(s.Mid(start + start2,len2));
r.GetMatch(&start2, &len2, 0);
start = start + start2 + len2;
}
cnt = unic.size();
}
if (cnt >= 2) {
wxString q = s;
wxString html;
ctlSQLBox* box = new ctlSQLBox((wxWindow*) winMain, CTL_SQLQUERY, wxDefaultPosition, wxSize(0, 0), wxTE_MULTILINE | wxTE_RICH2);
box->SetText(q);
int l = q.Length();
box->Colourise(0, box->GetLength());
//bg = box->SetSQLBoxColourBackground(false).GetAsString(wxC2S_CSS_SYNTAX);
html = box->TextToHtml(0, box->GetLength(),false);
delete box;
s = html;
s = "<html><body BGCOLOR=\"" + bg + "\">" + s + "</body></html>";
}
else {
//simple text
PreviewHtml v;
wxString tt=v.Preview(s,fmtpreview::AUTO);
s = tt;
}
delete m_Popup;
wxSize rr(350, 70);
FunctionPGHelper fh(s);
wxString key = "content";
m_Popup = new popuphelp(this, key, &fh, p, rr);
if (m_Popup && m_Popup->IsValid() && rr != m_Popup->GetSizePopup()) {
// recreate with new size
rr = m_Popup->GetSizePopup();
delete m_Popup;
m_Popup = new popuphelp((wxWindow*)winMain, key, &fh, p, rr);
}
if (m_Popup && m_Popup->IsValid()) {
//m_PopupHelp->UpdateWindowUI(true);
wxSize top_sz = m_Popup->GetSizePopup();
wxPoint posScreen;
wxSize sizeScreen;
const int displayNum = wxDisplay::GetFromPoint(p);
if (displayNum != wxNOT_FOUND)
{
const wxRect rectScreen = wxDisplay(displayNum).GetGeometry();
posScreen = rectScreen.GetPosition();
sizeScreen = rectScreen.GetSize();
}
else // outside of any display?
{
// just use the primary one then
posScreen = wxPoint(0, 0);
sizeScreen = wxGetDisplaySize();
}
wxSize top_new(top_sz);
wxPoint oldp(p);
if (p.x + top_new.x > sizeScreen.x) p.x = sizeScreen.x - top_new.x - 20;
if (p.y + top_new.y > sizeScreen.y) p.y = sizeScreen.y - top_new.y - 20;
if (oldp == p) p.x = p.x + 20;
m_Popup->Move(p);
wxRect r = m_Popup->GetScreenRect();
if (r.Contains(p1)) {
//wxMouseEvent mv(wxEVT_MOTION,);
//wxGetMousePosition();
}
//m_PopupHelp->Position(p, wxSize(0, 17));
m_Popup->Popup();
//wxPopupTransientWindow
}
}
void ctlSQLGrid::OnCellRightClick(wxGridEvent& event)
{
int row = event.GetRow();
int col = event.GetCol();
//SetRowLabelValue(row-1,);
//HideRow(row);
event.Skip();
wxPoint p;
if (row != -1 && col != -1) {
rrow = row;
rcol = col;
rpos = ClientToScreen(event.GetPosition());
wxThreadEvent e(wxEVT_THREAD);
//e.SetString(s);
e.SetString(GetCellValue(row, col));
//GetEventHandler()->AddPendingEvent(e);
wxPostEvent(this, e);
//event.Skip();
return;
}
else
{
row = rrow;
col = rcol;
p = rpos;
}
wxString s = GetCellValue(row, col);
}
void ctlSQLGrid::OnLabelClick(wxGridEvent& event)
{

View file

@ -52,17 +52,22 @@
#include "images/up.pngc"
#include "images/server_status.pngc"
#include <algorithm>
#include "utils/FunctionPGHelper.h"
#include "utils/PreviewHtml.h"
#include "db/pgConn.h"
#ifdef __WXMSW__
#include "wx/msw/wrapcctl.h"
#endif
extern int s_pid_HIGHLIGH;
#define CTRLID_DATABASE 4200
//wxDEFINE_EVENT(EVENT_FIND_STR, wxCommandEvent);
BEGIN_EVENT_TABLE(frmStatus, pgFrame)
EVT_MENU(MNU_EXIT, frmStatus::OnExit)
EVT_MENU(MNU_COPY, frmStatus::OnCopy)
EVT_MENU(MNU_COPY_QUERY, frmStatus::OnCopyQuery)
EVT_MENU(MNU_HELP, frmStatus::OnHelp)
@ -91,6 +96,7 @@ EVT_MENU(MNU_TERMINATE, frmStatus::OnTerminateBtn)
EVT_MENU(MNU_COMMIT, frmStatus::OnCommit)
EVT_MENU(MNU_ROLLBACK, frmStatus::OnRollback)
EVT_MENU(MNU_CLEAR_FILTER_SERVER_STATUS, frmStatus::OnClearFilter)
EVT_MENU(CMD_EVENT_FIND_STR, frmStatus::OnCmdFindStrLog)
EVT_COMBOBOX(CTL_LOGCBO, frmStatus::OnLoadLogfile)
EVT_BUTTON(CTL_ROTATEBTN, frmStatus::OnRotateLogfile)
@ -117,15 +123,11 @@ EVT_LIST_ITEM_DESELECTED(CTL_XACTLIST, frmStatus::OnSelXactItem)
EVT_LIST_COL_CLICK(CTL_XACTLIST, frmStatus::OnSortXactGrid)
EVT_LIST_COL_RIGHT_CLICK(CTL_XACTLIST, frmStatus::OnRightClickXactGrid)
EVT_LIST_COL_END_DRAG(CTL_XACTLIST, frmStatus::OnChgColSizeXactGrid)
//EVT_KEY_UP(CTL_LOGLIST, frmStatus::OnLogKeyUp)
EVT_TIMER(TIMER_LOG_ID, frmStatus::OnRefreshLogTimer)
EVT_LIST_ITEM_SELECTED(CTL_LOGLIST, frmStatus::OnSelLogItem)
EVT_LIST_ITEM_DESELECTED(CTL_LOGLIST, frmStatus::OnSelLogItem)
EVT_LIST_ITEM_RIGHT_CLICK(CTL_LOGLIST, frmStatus::OnRightClickLogGrid)
EVT_TIMER(TIMER_LOGHINT_ID, frmStatus::OnTimerHintLog)
EVT_TIMER(TIMER_QUERYSTATE_ID, frmStatus::OnRefreshQuerystateTimer)
EVT_LIST_COL_RIGHT_CLICK(CTL_QUERYSTATELIST, frmStatus::OnRightClickQuerystateGrid)
EVT_LIST_ITEM_SELECTED(CTL_QUERYSTATELIST, frmStatus::OnSelQuerystateItem)
@ -324,6 +326,7 @@ frmStatus::frmStatus(frmMain* form, const wxString& _title, pgConn* conn) : pgFr
// Set different window's attributes
SetTitle(_title);
SetName(dlgName);
SetIcon(*server_status_png_ico);
RestorePosition(-1, -1, 700, 500, 700, 500);
SetMinSize(FromDIP(wxSize(700, 500)));
@ -413,7 +416,6 @@ frmStatus::frmStatus(frmMain* form, const wxString& _title, pgConn* conn) : pgFr
toolBar->AddSeparator();
toolBar->AddTool(MNU_CLEAR_FILTER_SERVER_STATUS, wxEmptyString, GetBundleSVG(sortfilterclear_png_bmp, "sortfilterclear.svg", wxSize(16, 16)), _("Clear filter"), wxITEM_NORMAL);
toolBar->AddSeparator();
cbLogfiles = new wxComboBox(toolBar, CTL_LOGCBO, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL,
wxCB_READONLY | wxCB_DROPDOWN);
toolBar->AddControl(cbLogfiles);
@ -692,8 +694,7 @@ void frmStatus::OnClose(wxCloseEvent& event)
if (logThread && logisread) {
logThread->BreakRead();
event.Veto();
}
else Destroy();
} else Destroy();
//Destroy();
}
@ -1144,23 +1145,36 @@ void frmStatus::AddLogPane()
// Disable sort on Mac.
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), true);
#endif
wxListCtrl* lstLog = new wxListCtrl(pnlLog, CTL_LOGLIST, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxSUNKEN_BORDER);
//wxListCtrl *lstLog = new wxListCtrl(pnlLog, CTL_LOGLIST, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxSUNKEN_BORDER);
logList = new ctlListView(pnlLog, CTL_LOGLIST, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
logList->SetToolTip(NULL);
// hide tooltip for windows
#ifdef __WXMSW__
HWND hwndList = (HWND)logList->GetHandle();
LPARAM style = ::SendMessage(hwndList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
::SendMessage(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, style & ~LVS_EX_LABELTIP);
#endif
// Add the log list
logList = (ctlListView*)lstLog;
//logList = (ctlListView*)lstLog;
logList->SetModeStoreLongString();
nav = new ctlNavigatePanel(pnlLog, logList);
lstLog->Bind(wxEVT_KEY_UP, &frmStatus::OnLogKeyUp, this);
logList->Bind(wxEVT_KEY_UP, &frmStatus::OnLogKeyUp, this);
//lstLog->Bind(wxEVT_MENU, &ctlNavigatePanel::OnContextMenu, this);
Bind(wxEVT_THREAD, &frmStatus::OnAddLabelTextThread, this);
lstLog->Bind(wxEVT_MENU, &frmStatus::OnLogContextMenu, this);
logList->Bind(wxEVT_MENU, &frmStatus::OnLogContextMenu, this);
logList->Bind(wxEVT_MOTION, &frmStatus::OnMoveMouseLog, this);
//Connect(wxID_ANY, wxEVT_THREAD, wxThreadEventHandler(frmLog::OnAddLabelTextThread), NULL, this);
// Now switch back
#ifdef __WXMAC__
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), false);
#endif
delayHitLog = new wxTimer(this, TIMER_LOGHINT_ID);
//Bind(wxEVT_TIMER, &frmStatus::OnTimerHintLog, this);
///delayHitLog->Start(DELAYHITLOGPERIOD);
grdLog->Add(nav, 0, wxSHRINK, 3);
grdLog->Add(lstLog, 0, wxALL | wxEXPAND, 3);
grdLog->Add(logList, 0, wxALL | wxEXPAND, 3);
// Add the panel to the notebook
manager.AddPane(pnlLog,
wxAuiPaneInfo().Center().
@ -1178,7 +1192,7 @@ void frmStatus::AddLogPane()
// if server release is less than 8.0 or if server has no adminpack
if (!is_read_log) {
logList->InsertColumn(logList->GetColumnCount(), _("Message"), wxLIST_FORMAT_LEFT, 700);
logList->InsertItem(logList->GetItemCount(), _("Function pg_read_binary_file(text,bigint,bigint,boolean) permission denied."), -1);
logList->AppendItem(-1, _("Function pg_read_binary_file(text,bigint,bigint,boolean) permission denied."));
logList->Enable(false);
logTimer = NULL;
// We're done
@ -1209,7 +1223,7 @@ void frmStatus::AddLogPane()
if (!connection->HasFeature(FEATURE_FILEREAD, true))
{
logList->InsertColumn(logList->GetColumnCount(), _("Message"), wxLIST_FORMAT_LEFT, wxLIST_AUTOSIZE_USEHEADER);
logList->InsertItem(logList->GetItemCount(), _("Logs are not available for this server."), -1);
logList->AppendItem(-1,_("Logs are not available for this server."));
logList->Enable(false);
logTimer = NULL;
// We're done
@ -1324,8 +1338,7 @@ void frmStatus::OnCopy(wxCommandEvent& ev)
#endif
}
// list->GetText(row,3);
}
else
} else
{
row = list->GetFirstSelected();
@ -1880,9 +1893,9 @@ void frmStatus::OnRefreshStatusTimer(wxTimerEvent& event)
q+="group by pid, event_type, event,queryid \
) l group by pid) hs on p.pid = hs.pid\n";
}
//backend_type
}
else
} else
{
q += wxT("FROM pg_stat_activity p ");
}
@ -1945,8 +1958,7 @@ void frmStatus::OnRefreshStatusTimer(wxTimerEvent& event)
if (connection->BackendMinimumVersion(13, 0)) {
wxString progress_info = dataSet1->GetVal(wxT("progress_info"));
if (!progress_info.IsEmpty()) app_name = progress_info;
}
else
} else
{
wxString heap_blks_total = dataSet1->GetVal(wxT("heap_blks_total"));
if (!heap_blks_total.IsEmpty()) {
@ -2510,13 +2522,11 @@ void frmStatus::OnRefreshQuerystateTimer(wxTimerEvent& event)
querystateList->SetItemBackgroundColour(row, wc);
//querystateList->SetItemBackgroundColour(row, );
}
else
} else
{
if (getlongvalue(p,wxT("actual rows=([0-9]+)"))>1000000) {
querystateList->SetItemBackgroundColour(row, wxColour(255,174,200)); // red
}
else
} else
querystateList->SetItemBackgroundColour(row, wxColour(224,255,224)); // gren
}
@ -2590,8 +2600,7 @@ void frmStatus::OnRefreshLogTimer(wxTimerEvent& event)
wxLogError(wxT("Cant create log thread!"));
delete logThread;
logThread = NULL;
}
else
} else
logThread->Run();
}
else
@ -2846,8 +2855,7 @@ void frmStatus::addLogFile(wxDateTime* dt, bool skipFirst)
wxString sql = "select current_setting('log_directory')||'/'||name filename,modification filetime,size len\n"
" FROM pg_ls_logdir() where name ~ '.csv' and modification >= '" + DateToAnsiStr(*dt) + "'::timestamp order by modification-'" + DateToAnsiStr(*dt) + "'::timestamp limit 1";
set = connection->ExecuteSet(sql);
}
else
} else
set = connection->ExecuteSet(
wxT("SELECT modification filetime, name filename, size AS len ")
wxT(" FROM pg_ls_logdir()")
@ -2973,11 +2981,9 @@ void frmStatus::addLogFile(const wxString& filename, const wxDateTime timestamp,
//read = startChar - &m[0];
// remove bad utf-8 char
*startChar = 0;
}
else
} else
m[pos] = 0;
}
else {
} else {
raw = raw1;
}
read += strlen(raw);
@ -3733,8 +3739,7 @@ void ReadLogThread::readLogFile(wxString logfileName, long& lenfile, long& logfi
*startChar = 0;
pos = startChar- (unsigned char*)&m[0];
// start position bad utf-8 char
}
else
} else
m[pos] = 0;
if (startLine != (unsigned char*)&m[pos]) {
// partial line
@ -4607,9 +4612,120 @@ void frmStatus::OnRightClickQuerystateGrid(wxListEvent& event)
void frmStatus::OnLogContextMenu(wxCommandEvent& event) {
nav->OnContextMenu(event);
}
int count = 0;
void frmStatus::OnTimerHintLog(wxTimerEvent& event)
{
delayHitLog->Stop();
wxPoint pm = logList->GetScreenPosition();
wxRect rc = logList->GetSize();
wxPoint m = wxGetMousePosition();
rc.x = pm.x;
rc.y = pm.y;
count++;
//statusBar->SetStatusText(wxString::Format(" TIMER COUNT %d x:%d,y:%d",count, m.x, m.y));
if (!rc.Contains(m)) {
}
else {
wxPoint curr = logList->ScreenToClient(m);
if (lastmouse == m && lastlogitem != -1 && lastlogitemShow != lastlogitem) {
{
wxString s;
if (m_Popup != NULL) {
delete m_Popup;
m_Popup = NULL;
}
else {
}
s = logList->GetText(lastlogitem);
lastlogitemShow = lastlogitem;
lastlogitem = -1;
wxSize rr(350, 25);
//
wxString key = "content";
int x, y;
wxPoint p = m;
p.x = p.x + 5;
p.y = p.y + 5;
PreviewHtml v;
wxString tt = v.Preview(s, fmtpreview::CSV);
s = tt;
FunctionPGHelper fh(s);
fh.SetTimerClose(1500);
//m_Popup = new popuphelp((wxWindow*)winMain, key, &fh, p, rr);
m_Popup = new popuphelp(this, key, &fh, p, rr);
if (m_Popup && m_Popup->IsValid() && rr != m_Popup->GetSizePopup()) {
// recreate with new size
rr = m_Popup->GetSizePopup();
delete m_Popup;
m_Popup = new popuphelp(this, key, &fh, p, rr);
}
if (m_Popup && m_Popup->IsValid()) {
//m_PopupHelp->UpdateWindowUI(true);
wxSize top_sz = m_Popup->GetSizePopup();
wxPoint posScreen;
wxSize sizeScreen;
const int displayNum = wxDisplay::GetFromPoint(p);
if (displayNum != wxNOT_FOUND)
{
const wxRect rectScreen = wxDisplay(displayNum).GetGeometry();
posScreen = rectScreen.GetPosition();
sizeScreen = rectScreen.GetSize();
}
else // outside of any display?
{
// just use the primary one then
posScreen = wxPoint(0, 0);
sizeScreen = wxGetDisplaySize();
}
wxSize top_new(top_sz);
wxPoint oldp(p);
if (p.x + top_new.x > sizeScreen.x) p.x = sizeScreen.x - top_new.x - 20;
if (p.y + top_new.y > sizeScreen.y) p.y = sizeScreen.y - top_new.y - 20;
if (oldp == p) p.x = p.x + 20;
m_Popup->Move(p);
wxRect r = m_Popup->GetScreenRect();
//m_PopupHelp->Position(p, wxSize(0, 17));
m_Popup->Popup();
//wxPopupTransientWindow
}
}
}
}
}
void frmStatus::OnCmdFindStrLog(wxCommandEvent& event) {
wxString s = event.GetString();
//statusBar->SetStatusText(wxString::Format(" FIND CMD: %s",s));
nav->SetFindString(s);
}
void frmStatus::OnMoveMouseLog(wxMouseEvent& event)
{
// wxMenu* logListPopupMenu;
// logListPopupMenu = nav->GetPopupMenu();
wxPoint mp = event.GetPosition();
lastmouse = wxGetMousePosition();
int flags = wxLIST_HITTEST_ONITEMLABEL;
long item=logList->HitTest(mp,flags);
//logList->PopupMenu(logListPopupMenu, event.GetPoint());
// statusBar->SetStatusText(wxString::Format("x:%d,y:%d",lastmouse.x,lastmouse.y));
wxString s;
if (lastlogitem != -1 || lastlogitem != item) {
#define DELAYHITLOGPERIOD 1000
delayHitLog->Stop();
delayHitLog->StartOnce(DELAYHITLOGPERIOD);
}
else
delayHitLog->Stop();
lastlogitem = item;
event.Skip();
return;
}
void frmStatus::OnRightClickLogGrid(wxListEvent& event)
{
delayHitLog->Stop();
wxMenu* logListPopupMenu;
logListPopupMenu = nav->GetPopupMenu();
logList->PopupMenu(logListPopupMenu, event.GetPoint());

View file

@ -25,11 +25,19 @@ private:
void OnSortGrid(wxListEvent& event);
bool nosort; // если кто то пользуется SetItemData то не будем сортировать такие ctlListView
int order, prev_col;
// будем сохранять длинные строки 0 колонки в этом массиве
bool storelongstring = false;
std::vector<wxString> longstring;
public:
bool SetItemData(long item, long data) {
nosort = true;
return wxListView::SetItemData(item, data);
}
void SetModeStoreLongString() { storelongstring = true; }
bool DeleteAllItems() {
longstring.clear();
return wxListView::DeleteAllItems();
}
ctlListView(wxWindow* p, int id, wxPoint pos, wxSize siz, long attr = 0);
long GetSelection();
wxString GetText(long row, long col = 0);

View file

@ -68,6 +68,7 @@ public:
int GetIndexColor(const wxColour &color) const;
void ClearMark();
void RowVisibleCenter(long row);
void SetFindString(const wxString &findstr);
int GetCountMark();
wxMenu* GetPopupMenu();
bool RunKeyCommand(wxKeyEvent& event,int numCmd=-1);

View file

@ -53,7 +53,7 @@ public:
void Create(wxWindow *parent, wxWindowID id = -1, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = 0);
void HighlightBrace(int lb, int rb);
void SetDatabase(pgConn *db);
wxString TextToHtml(int start, int end);
wxString TextToHtml(int start, int end, bool isAddNewLine=false);
void Copy();
void OnKeyDown(wxKeyEvent &event);
void OnAutoComplete(wxCommandEvent &event);

View file

@ -15,6 +15,8 @@
// wxWindows headers
#include <wx/grid.h>
#include <wx/brush.h>
#include "utils/popuphelp.h"
class GroupRows;
class ctlSQLGrid : public wxGrid
@ -52,6 +54,8 @@ public:
void OnGridSelectCell(wxGridEvent& evt);
void OnLabelClick(wxGridEvent& event);
void OnCellRightClick(wxGridEvent& event);
void OnMouseEvent(wxMouseEvent& event);
void OnShowPopup(wxThreadEvent& event);
bool FullArrayCollapseRowsPlan(bool clear);
void AutoSizeColumn(int col, bool setAsMin = false, bool doLimit = true);
void AutoSizeColumns(bool setAsMin);
@ -83,7 +87,11 @@ private:
// Max size for each column
wxArrayInt colMaxSizes;
bool isSort;
// viewr
popuphelp* m_Popup = NULL;
int rcol, rrow;
wxPoint rpos;
//FunctionPGHelper fh;
};
class GroupRows

View file

@ -63,12 +63,14 @@ enum
MNU_QUERYSTATETRIGGER,
MNU_WAITENABLE,
MNU_WAITSAVE,
CMD_EVENT_FIND_STR,
TIMER_REFRESHUI_ID,
TIMER_STATUS_ID,
TIMER_LOCKS_ID,
TIMER_XACT_ID,
TIMER_LOG_ID,
TIMER_QUERYSTATE_ID
TIMER_QUERYSTATE_ID,
TIMER_LOGHINT_ID
};
@ -80,9 +82,6 @@ enum
PANE_LOG,
PANE_QUERYSTATE
};
//
// This number MUST be incremented if changing any of the default perspectives
//
#define FRMSTATUS_PERSPECTIVE_VER wxT("8275")
@ -241,6 +240,7 @@ private:
wxTimer *refreshUITimer;
wxTimer *statusTimer, *locksTimer, *xactTimer, *logTimer, *querystateTimer;
wxTimer *delayHitLog;
int statusRate, locksRate, xactRate, logRate, querystateRate;
ctlListView *statusList;
@ -261,6 +261,9 @@ private:
wxArrayString filterValue;
int statusColWidth[12], lockColWidth[10], xactColWidth[5], querystateColWidth[5];
popuphelp* m_Popup = NULL;
long lastlogitem = -1, lastlogitemShow=-1;
wxPoint lastmouse;
int cboToRate();
wxString rateToCboString(int rate);
@ -288,6 +291,8 @@ private:
void OnToggleWaitEnable(wxCommandEvent& event);
void OnEmptyAction(wxCommandEvent &event);
void OnLogContextMenu(wxCommandEvent& event);
void OnMoveMouseLog(wxMouseEvent& event);
void OnTimerHintLog(wxTimerEvent& event);
void OnToggleToolBar(wxCommandEvent &event);
void OnDefaultView(wxCommandEvent &event);
@ -348,6 +353,7 @@ private:
void OnLogKeyUp(wxKeyEvent& event);
void OnAddLabelTextThread(wxThreadEvent& event);
void ActivatePane(wxString name);
void OnCmdFindStrLog(wxCommandEvent& event);
void OnChangeDatabase(wxCommandEvent &ev);

View file

@ -155,10 +155,11 @@ public:
int getCountGroup(int row);
int GetTotalCountGroup(int rowfilter);
wxArrayString GetAllFields(int row, bool isfilter);
// use for parse csv log file
static Line getLineParse(const wxString& str, bool csv = false, const wxString& host=wxEmptyString);
static wxString get_field(Line& l, MyConst::colField col);
private:
bool checkFilter(Line& l);
Line getLineParse(const wxString& str, bool csv = false);
wxString get_field(Line& l, MyConst::colField col);
LineFilter getLineFilter(wxString strflt,wxString fn);
void getLineToCache(int row, bool filter = true);
bool CompareFilterLine(int row, bool filter);

View file

@ -15,6 +15,21 @@ class FunctionPGHelper
{
public:
FunctionPGHelper() {};
/// <summary>
/// Создать только переданный в конструкторе html текст с именем "content"
/// </summary>
/// <param name="content"></param>
FunctionPGHelper(const wxString& content) {
body.clear();
Add("content", content);
isload = true;
};
int Size() {
return body.size();
}
void SetTimerClose(int ms) { m_interval = ms; }
int GetTimerClose() { return m_interval; }
void Add(const wxString& key, const wxString& v) { body.emplace(key, v); }
wxString getHelpString(wxString fnd, bool isPart = true) {
if (!isValid()) return wxEmptyString;
auto search = body.find(fnd);
@ -100,6 +115,7 @@ public:
}
private:
bool isload = false;
int m_interval = -1;
wxString path;
std::map<wxString, wxString> body;
void loadfile() {

149
include/utils/PreviewHtml.h Normal file
View file

@ -0,0 +1,149 @@
#pragma once
#include <wx/wx.h>
#define PREVIEW_SEP 1
#define PREVIEW_DIGITS 2
#define PREVIEW_WORD 4
#define PREVIEW_SPACE 8
#define PREVIEW_ENDFIELD 16
#define PREVIEW_ENDROW 32
#define PREVIEW_QUOTE 64
#define CHKFLAG(val,par) ((val & par)>0)
enum class fmtpreview {
AUTO, AUTOVACCUM,CSV
};
struct Element {
wxString src;
wxString html;
int flags = 0;
} ;
static wxString titles_log[] = {
L"log_time",
L"user_name",
L"database_name",
L"process_id",
L"connection_from",
L"session_id",
L"session_line_num",
L"command_tag",
L"session_start_time",
L"virtual_transaction_id",
L"transaction_id",
L"error_severity",
L"sql_state_code",
L"message",
L"detail",
L"hint",
L"internal_query",
L"internal_query_pos",
L"context",
L"query",
L"query_pos",
L"location",
L"application_name",
L"backend_type",
L"leader_pid",
L"query_id"
};
class PreviewHtml
{
public:
//void SetColors();
PreviewHtml() { InitColor(); };
wxString Preview(const wxString& txt, fmtpreview type);
private:
void InitColor();
bool saveTokenIfNotEmpty(wxString& savestr, int flag) {
if (savestr.Length() > 0) {
wxString tmp = savestr;
tmp=escapeHtml(tmp,true);
tmp.Replace(" ", "&nbsp;");
if (CHKFLAG(flag, PREVIEW_ENDROW)) tmp = "<br>";
if (CHKFLAG(flag, PREVIEW_DIGITS)) {
int l = savestr.Length();
if (l > 4 && !savestr.Contains('.')) {
int dl = 3;
wxString fmt;
std::vector<wxString> dd;
bool smalll = true;
while (l > 0) {
l = l - dl;
if (l < 0) {
dl = dl + l;
l = 0;
}
wxString d3 = savestr.Mid(l, dl);
if (smalll)
dd.push_back("<font size=+1>" + d3 + "</font>");
else
dd.push_back(d3);
smalll = !smalll;
}
for (auto i = dd.rbegin(); i != dd.rend(); i++)
{
fmt += *i;
}
tmp = fmt;
}
wxString t = wxString::Format("<font color=\"%s\">%s</font>", numcolor, tmp);
tmp = t;
}
if (CHKFLAG(flag, PREVIEW_QUOTE)) {
wxString t = wxString::Format("<font color=\"%s\">%s</font>",quotecolor,tmp);
tmp = t;
}
tokens.push_back({savestr,tmp,flag});
savestr = "";
return true;
}
return false;
}
int FindElement(int start_pos, int flag_find, wxString& value_find, int is_what_find) {
int p = start_pos;
int rez = -1;
while (p < tokens.size()) {
Element t = tokens[p];
bool f1 = is_what_find & 1;
bool f2 = is_what_find & 2;
bool r1 = false;
bool r2 = false;
if (f1 && CHKFLAG(t.flags, flag_find)) {
r1 = true;
}
if (f2 && t.src==value_find ) {
r2 = true;
}
if ((is_what_find == 3 && r1 && r2)
|| (is_what_find == 2 && r2)
|| (is_what_find == 1 && r1)
) {
rez = p;
break;
}
p++;
}
return rez;
}
wxString generateHtml() {
wxString s;
for (size_t i = 0; i < tokens.size(); i++) {
Element t = tokens[i];
s += t.html;
}
// s = "<html><body BGCOLOR=\"" + bgcolor + "\">" + s + "</body></html>";
// s=wxString::Format("<html><body BGCOLOR=\"%s\" FGCOLOR=\"%s\"><font face=\"%s\" size=\"%d\">%s</font></body></html>", bgcolor,fgcolor,fname,fsize, s);
return s;
}
std::vector<Element> tokens;
// colors
wxString bgcolor, numcolor, fgcolor, quotecolor;
wxString fname;
int fsize;
};

View file

@ -8,11 +8,15 @@
#include <wx/regex.h>
#include <map>
#include <vector>
#include "wx/display.h"
class popuphelp :
public wxPopupTransientWindow
{
public:
~popuphelp() {
delete closeTimer;
}
//popuphelp(wxWindow* parent);
bool ProcessLeftDown(wxMouseEvent& event)
{
@ -21,11 +25,38 @@ public:
bool IsValid() {
return isvalid;
}
popuphelp(wxWindow* parent,wxString keyword, FunctionPGHelper *hhelper) : wxPopupTransientWindow(parent) {
SetSize(450,370);
void SetSizePopup(const wxSize& sz) {
SetSize(sz);
Layout();
Fit();
sizew = sz;
}
wxSize GetSizePopup() { return sizew; }
popuphelp(wxWindow* parent,wxString keyword, FunctionPGHelper *hhelper,wxPoint &posit,wxSize &newSz) : wxPopupTransientWindow(parent) {
wxSize top_sz(newSz);
sizew = top_sz;
//SetSize(top_sz);
this->hhelper = hhelper;
SetBackgroundColour(*wxBLACK);
htmlWindow = new wxHtmlWindow(this, -1, wxDefaultPosition,GetSize());
extern sysSettings* settings;
wxFont fnt = settings->GetSQLFont();
int size = fnt.GetPointSize();
SetFont(fnt);
htmlWindow = new wxHtmlWindow(this, -1, wxDefaultPosition, sizew);
wxFont font(size, wxFontFamily::wxFONTFAMILY_MODERN, wxFontStyle::wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
wxString fixf = font.GetFaceName();
wxString scalf = fnt.GetFaceName();
int f_sizes[7];
f_sizes[0] = int(size -4);
f_sizes[1] = int(size -2);
f_sizes[2] = size;
f_sizes[3] = int(size +1);
f_sizes[4] = int(size +3);
f_sizes[5] = int(size +5);
f_sizes[6] = int(size +7);
htmlWindow->SetFonts(scalf, fixf, f_sizes);
htmlWindow->SetRelatedStatusBar(0);
//htmlWindow->SetPage("<html><body><h1>TEST</h1><span fgcolor=\"#332233\">Set Page Works</span></body></hmtl>");
wxString txt = hhelper->getHelpString(keyword);
@ -38,6 +69,7 @@ public:
}
}
SetPage(txt);
//htmlWindow->SetSize(htmlWindow->GetInternalRepresentation()->GetWidth(), htmlWindow->GetInternalRepresentation()->GetHeight());
//wxSize sz= htmlWindow->GetSize();
//sz = htmlWindow->GetBestSize();
//htmlWindow->SetHTMLBackgroundImage(wxBitmapBundle::FromSVGFile("data/bg.svg", wxSize(65, 45)));
@ -56,6 +88,35 @@ public:
SetSizer(topsizer);
topsizer->Fit(this);
int xx, yy;
htmlWindow->GetVirtualSize(&xx, &yy);
//wxSize sz = GetSize();
wxPoint posScreen;
wxSize sizeScreen;
const int displayNum = wxDisplay::GetFromPoint(posit);
if (displayNum != wxNOT_FOUND)
{
const wxRect rectScreen = wxDisplay(displayNum).GetGeometry();
posScreen = rectScreen.GetPosition();
sizeScreen = rectScreen.GetSize();
}
else // outside of any display?
{
// just use the primary one then
posScreen = wxPoint(0, 0);
sizeScreen = wxGetDisplaySize();
}
wxSize top_new(top_sz);
if (xx > sizeScreen.x) xx = sizeScreen.x - 120;
if (yy > sizeScreen.y) yy = sizeScreen.y - 120;
if (xx > top_sz.x || yy > top_sz.y) {
int dx = 0;
if (htmlWindow->IsScrollbarShown(wxHORIZONTAL)) dx=htmlWindow->GetScrollThumb(wxHORIZONTAL);
SetSizePopup(wxSize(xx+dx, yy+5));
}
//this->Bind(wxEVT_HTML_CELL_CLICKED, [&](wxHtmlCellEvent& event) {
// wxHtmlCell* c = event.GetCell();
@ -79,6 +140,9 @@ public:
});
htmlWindow->Bind(wxEVT_RIGHT_UP, [&](wxMouseEvent& event) {
wxString name;
wxLongLong e = wxGetLocalTimeMillis();
if (e - startTimeWin < 150)
return;
//wxString body = this->hhelper->getHelpString(name);
wxString ctext = htmlWindow->SelectionToText();
if (!ctext.IsEmpty()) {
@ -88,6 +152,17 @@ public:
{
}
wxString wname = GetParent()->GetName();
if (wname == "frmStatus") {
//CMD_EVENT_FIND_STR
wxCommandEvent event(wxEVT_MENU, 281);
event.SetEventObject(this);
// Give it some contents
event.SetString(ctext);
// Do send it
GetParent()->ProcessWindowEvent(event);
}
//statusBar->SetStatusText(wxString::Format(" TIMER COUNT %d x:%d,y:%d", count, m.x, m.y));
Hide();
return;
}
@ -95,21 +170,43 @@ public:
//ctext=htmlWindow->SelectionToText();
//wxString s = wxString::Format("cell = %s",ctext.c_str());
});
startTimeWin = wxGetLocalTimeMillis();
int inter = hhelper->GetTimerClose();
if (inter != -1) {
closeTimer = new wxTimer(this);
Bind(wxEVT_TIMER, [&](wxTimerEvent& event) {
closeTimer->Stop();
wxPoint pm = this->GetScreenPosition();
wxRect rc = this->GetSize();
wxPoint m = wxGetMousePosition();
rc.x = pm.x;
rc.y = pm.y;
if (!rc.Contains(m)) {
Hide();
return;
}
});
closeTimer->StartOnce(inter);
}
}
private:
bool isvalid = true;
wxHtmlWindow* htmlWindow;
wxLongLong startTimeWin;
wxSize sizew;
FunctionPGHelper* hhelper;
std::vector<wxString> hist;
void SetPage(wxString innerbody,bool gethistory=false) {
wxString h;
int p = innerbody.Find("<body>");
if (innerbody.Find("<html>")>=0) h = innerbody;
else
if (p > -1) {
innerbody.Replace("<body>", "<html><body TEXT=\"#000000\" BGCOLOR=\"#FFFFA0\" LINK=\"#0000FF\" VLINK=\"#FF0000\" ALINK=\"#000088\">", false);
innerbody.Replace("<body>", "<html><body TEXT=\"#000000\" BGCOLOR=\"#FFFFE0\" LINK=\"#0000FF\" VLINK=\"#FF0000\" ALINK=\"#000088\">", false);
h = "" + innerbody + "";
} else
h = "<html><body TEXT=\"#000000\" BGCOLOR=\"#FFFFA0\" LINK=\"#0000FF\" VLINK=\"#FF0000\" ALINK=\"#000088\">" + innerbody + "</body></hmtl>";
}
else
h = "<html><body TEXT=\"#000000\" BGCOLOR=\"#FFFFE0\" LINK=\"#0000FF\" VLINK=\"#FF0000\" ALINK=\"#000088\">" + innerbody + "</body></hmtl>";
if (gethistory) {
if (hist.size() < 2) {
@ -124,5 +221,7 @@ private:
}
htmlWindow->SetPage(h);
}
private:
wxTimer *closeTimer=NULL;
};
#endif

View file

@ -1062,6 +1062,7 @@
<ClCompile Include="utils\pgconfig.cpp" />
<ClCompile Include="utils\registry.cpp" />
<ClCompile Include="utils\sshTunnel.cpp" />
<ClCompile Include="utils\PreviewHtml.cpp" />
<ClCompile Include="utils\sysLogger.cpp" />
<ClCompile Include="utils\sysProcess.cpp" />
<ClCompile Include="utils\sysSettings.cpp" />
@ -1613,6 +1614,7 @@
<ClInclude Include="include\utils\json\json_defs.h" />
<ClInclude Include="include\utils\TableColsMap.h" />
<ClInclude Include="include\utils\sshTunnel.h" />
<ClInclude Include="include\utils\PreviewHtml.h" />
<ClInclude Include="include\version.h" />
<ClInclude Include="include\utils\csvfiles.h" />
<ClInclude Include="include\utils\factory.h" />

250
utils/PreviewHtml.cpp Normal file
View file

@ -0,0 +1,250 @@
#include "pgAdmin3.h"
#include "utils/PreviewHtml.h"
#include "utils/json/jsonval.h"
#include "utils/csvfiles.h"
#include "log/Storage.h"
void PreviewHtml::InitColor() {
wxJSONValue def(wxJSONType::wxJSONTYPE_OBJECT);
def.SetType(wxJSONType::wxJSONTYPE_NULL);
wxJSONValue opt(wxJSONType::wxJSONTYPE_OBJECT);
opt.SetType(wxJSONType::wxJSONTYPE_NULL);
extern sysSettings* settings;
settings->ReadJsonObect("PreviewOptions", opt, def);
// settings->WriteJsonFile();
if (!opt.IsNull()) {
bgcolor = opt["bgcolor"].AsString();
fgcolor = opt["fgcolor"].AsString();
numcolor = opt["numcolor"].AsString();
quotecolor = opt["quotecolor"].AsString();
//fname = opt["fontname"].AsString();
//fsize=opt["fontsize"].AsInt();
}
else {
wxColour frColor = settings->GetSQLBoxColourForeground();
if (settings->GetSQLBoxUseSystemForeground())
{
frColor = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
}
fgcolor=frColor.GetAsString(wxC2S_HTML_SYNTAX);
opt["fgcolor"] = fgcolor;
bgcolor = "#FFFFE0";
//4
numcolor = settings->GetSQLBoxColour(4);
wxColour cc(numcolor);
if (cc.IsOk()) numcolor = cc.GetAsString(wxC2S_HTML_SYNTAX);
//6
quotecolor = settings->GetSQLBoxColour(6);
wxColour ccc(quotecolor);
if (ccc.IsOk()) quotecolor = ccc.GetAsString(wxC2S_HTML_SYNTAX);
// wxFont fnt = settings->GetSQLFont();
// fname = fnt.GetFaceName();
// fsize = fnt.GetPointSize();
//fnt.SetPointSize(fsize);
opt["fgcolor"] = fgcolor;
opt["bgcolor"] = bgcolor;
opt["numcolor"] = numcolor;
opt["quotecolor"] = quotecolor;
// opt["fontname"] = fname;
// opt["fontsize"]=fsize;
settings->WriteJsonObect("PreviewOptions", opt);
}
}
wxString PreviewHtml::Preview(const wxString& txt, fmtpreview type) {
fmtpreview fmt = type;
wxString fieldSep=",";
wxString rowSep = "\n";
bool iscsv = false;
if (txt.StartsWith("automatic vacuum")&& fmt == fmtpreview::AUTO) fmt = fmtpreview::AUTOVACCUM;
if (txt.StartsWith("automatic analyze") && fmt == fmtpreview::AUTO) fmt = fmtpreview::AUTOVACCUM;
//
if (fmt == fmtpreview::AUTOVACCUM) {
fieldSep = ",";
rowSep = "\n";
}
else if (fmt == fmtpreview::CSV) {
iscsv = true;
}
else if (fmt == fmtpreview::AUTO) {
//CSVTokenizer tk(txt);
//int nfield = 0;
//while (tk.HasMoreTokens()) {
// wxString field = tk.GetNextToken();
// nfield++;
//}
//if (nfield>1) iscsv = true;
}
// prepare csv
std::vector<wxString> strlist;
wxString tmpstr = txt;
if (iscsv) {
CSVTokenizer tk(txt);
tmpstr = "";
int nfield = 0;
while (tk.HasMoreTokens()) {
wxString field = tk.GetNextToken();
if (!field.IsEmpty()) {
if (!tmpstr.IsEmpty()) tmpstr += '\n'; // All not empty field as list rows
tmpstr += field;
}
strlist.push_back(field);
nfield++;
}
if (nfield == 26) {
// log db csv format 14,15,16,17 version
Line l=Storage::getLineParse(txt, true, "");
strlist[15] = Storage::get_field(l, MyConst::colField::logHint); // bind value
strlist[13] = Storage::get_field(l, MyConst::colField::logMessage); // bind value
}
}
if (strlist.size() == 0) strlist.push_back(tmpstr);
wxString html;
int nf = 0;
for (int nf = 0; nf < strlist.size();nf++) {
tmpstr = strlist[nf];
int pos = 0;
int len = tmpstr.Length();
if (len == 0) continue;
wxUniChar c;
wxString currWord;
wxString currDigits;
wxString currSep;
int flag = 0;
tokens.clear();
bool quote = false;
wxUniChar prevchar;
int startstr = -1;
while (pos < len) {
c = tmpstr[pos++];
bool isquote = c == '"';
if (quote) {
if (prevchar == c && isquote) {
// repeat quote
prevchar = '\0';
continue;
}
if (prevchar == '"' && !isquote) {
// end quote string
wxString tmp = tmpstr.Mid(startstr, pos - startstr - 1);
saveTokenIfNotEmpty(tmp, PREVIEW_QUOTE);
quote = false;
}
else {
prevchar = c;
continue;
}
}
if (quote == false && isquote) {
saveTokenIfNotEmpty(currWord, PREVIEW_WORD);
saveTokenIfNotEmpty(currDigits, PREVIEW_DIGITS);
saveTokenIfNotEmpty(currSep, PREVIEW_SEP);
quote = true;
prevchar = '\0';
startstr = pos - 1;
continue;
}
if (fieldSep.Length() > 0 && fieldSep[0] == c) {
//flag |= PREVIEW_ENDFIELD;
saveTokenIfNotEmpty(currWord, PREVIEW_WORD);
saveTokenIfNotEmpty(currDigits, PREVIEW_DIGITS);
saveTokenIfNotEmpty(currSep, PREVIEW_SEP);
currSep = c;
saveTokenIfNotEmpty(currSep, PREVIEW_ENDFIELD);
continue;
}
else if (rowSep.Length() > 0 && rowSep[0] == c) {
//flag |= PREVIEW_ENDROW;
saveTokenIfNotEmpty(currWord, PREVIEW_WORD);
saveTokenIfNotEmpty(currDigits, PREVIEW_DIGITS);
saveTokenIfNotEmpty(currSep, PREVIEW_SEP);
currSep = c;
saveTokenIfNotEmpty(currSep, PREVIEW_ENDROW);
continue;
}
if ((c >= '0' && c <= '9') || (currDigits.Length() > 0 && c == '.')) {
if (currWord.Length() == 0) { // diget not after word
saveTokenIfNotEmpty(currSep, PREVIEW_SEP);
currDigits += c;
continue;
}
}
if (c == '-' || c == '+' || c == '.' || c == ',' ||
c == ':' || c == '~' ||
c == '@' || c == '*' || c == '/' ||
c == '=' || c == '!' || c == '#' ||
c == '&' || c == '%' || c == '^' ||
c == '|' || c == '`' || c == '?' ||
c == '>' || c == '<'
|| c == ';' || c == '_' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}'
|| c == ' '
)
{
saveTokenIfNotEmpty(currWord, PREVIEW_WORD);
saveTokenIfNotEmpty(currDigits, PREVIEW_DIGITS);
currSep += c;
continue;
}
saveTokenIfNotEmpty(currSep, PREVIEW_SEP);
if (currDigits.Length() > 0) {
currWord = currDigits + currWord;
currDigits = "";
}
currWord += c;
}
// last element
if (quote) {
wxString tmp = tmpstr.Mid(startstr);
saveTokenIfNotEmpty(tmp, PREVIEW_QUOTE);
}
saveTokenIfNotEmpty(currWord, PREVIEW_WORD);
saveTokenIfNotEmpty(currDigits, PREVIEW_DIGITS);
saveTokenIfNotEmpty(currSep, PREVIEW_SEP);
// Additonal styled
wxString findstr = "";
int p = 0;
while (p >= 0) {
int fp = FindElement(p, PREVIEW_ENDFIELD | PREVIEW_ENDROW, findstr, 1);
if (fp > 0) {
int pp = fp;
while (pp > 0 && pp > p) {
pp--;
Element t2 = tokens[pp];
if (CHKFLAG(t2.flags, PREVIEW_SEP) && t2.src.StartsWith(":")) {
// Right bound title
if (pp - p > 0) {
tokens[p].html = "<b>" + tokens[p].html;
tokens[pp - 1].html = tokens[pp - 1].html + "</b>";
}
}
}
fp++; // next field
p = fp;
}
else break;
}
if (strlist.size() > 1) {
// csv log
wxString tit="field"+wxString::Format("%d",nf+1);
if (strlist.size() == 26) tit = titles_log[nf];
tit = "<tr><td valign=\"top\"><b>" + tit + "</b></td>";
html=html+tit+"<td>" + generateHtml() + "</td></tr>";
} else
html+= generateHtml(); // tokens -> html
}
if (strlist.size() > 1) html = "<table CELLPADDING=\"1\">" + html + "</table>";
wxString ttt = wxString::Format("<html><body BGCOLOR=\"%s\" FGCOLOR=\"%s\">%s</body></html>", bgcolor, fgcolor, html);
return ttt;
}

View file

@ -560,7 +560,7 @@ wxString replace_bind_parameters(const wxString& values_param, const wxString& t
replacecount = c;
return str;
}
Line Storage::getLineParse(const wxString& str, bool csv) {
Line Storage::getLineParse(const wxString& str, bool csv,const wxString &host) {
Line st;
if (csv) {
CSVTokenizer tk(str);
@ -575,7 +575,7 @@ Line Storage::getLineParse(const wxString& str, bool csv) {
st.loguser = { static_cast<unsigned short int>(t.Len()),static_cast<unsigned short int>(logUser.Len()) };
t += logUser;
wxString logDatabase = tk.GetNextToken();
if (logDatabase.IsEmpty()) logDatabase = GetHost();
if (logDatabase.IsEmpty()) logDatabase = host;
st.logdb = { static_cast<unsigned short int>(t.Len()),static_cast<unsigned short int>(logDatabase.Len()) };
t += logDatabase;
@ -659,7 +659,7 @@ Line Storage::getLineParse(const wxString& str, bool csv) {
wxString logType = tk.GetNextToken();
st.logbtype = { static_cast<unsigned short int>(t.Len()),static_cast<unsigned short int>(logType.Len()) };
t += logType;
logCursorpos = GetHost();
logCursorpos = host;
st.logSERVER = { static_cast<unsigned short int>(t.Len()),static_cast<unsigned short int>(logCursorpos.Len()) };
t += logCursorpos;
//fields.Add(logType);
@ -785,7 +785,7 @@ bool Storage::checkFilter(Line& l) {
return false;
}
bool Storage::AddLineTextCSV(const wxString& strcsv) {
Line st = getLineParse(strcsv, true);
Line st = getLineParse(strcsv, true,GetHost());
if (checkFilter(st)) {
rowsignore++;