pgadmin3/ctl/calbox.cpp
2020-07-07 22:19:12 +05:00

519 lines
11 KiB
C++

//////////////////////////////////////////////////////////////////////////
//
// pgAdmin III - PostgreSQL Tools
//
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
// calbox.cpp - Date-picker control box
//
//////////////////////////////////////////////////////////////////////////
#include "pgAdmin3.h"
#include <wx/wx.h>
#include "ctl/calbox.h"
#if !defined(wxUSE_DATEPICKCTRL) || !wxUSE_DATEPICKCTRL
#if defined(__WXMSW__)
#define TXTCTRL_FLAGS wxNO_BORDER
#define CALBORDER 0
#define TXTPOSX 0
#define TXTPOSY 1
#elif defined(__WXGTK__)
#define TXTCTRL_FLAGS 0
#define CALBORDER 4
#define TXTPOSX 0
#define TXTPOSY 0
#else
#define TXTCTRL_FLAGS 0
#define CALBORDER 4
#define TXTPOSX 0
#define TXTPOSY 0
#endif
#define CTRLID_TXT 101
#define CTRLID_CAL 102
#define CTRLID_BTN 103
#define CTRLID_PAN 104
BEGIN_EVENT_TABLE(wxCalendarBox, wxControl)
EVT_BUTTON(CTRLID_BTN, wxCalendarBox::OnClick)
EVT_TEXT(CTRLID_TXT, wxCalendarBox::OnText)
EVT_CHILD_FOCUS(wxCalendarBox::OnChildSetFocus)
EVT_SIZE(wxCalendarBox::OnSize)
END_EVENT_TABLE()
IMPLEMENT_DYNAMIC_CLASS(wxCalendarBox, wxControl)
wxCalendarBox::wxCalendarBox(wxWindow *parent,
wxWindowID id,
const wxDateTime &date,
const wxPoint &pos,
const wxSize &size,
long style,
const wxString &name)
{
Init();
Create(parent, id, date, pos, size, style, name);
}
bool wxCalendarBox::Create(wxWindow *parent,
wxWindowID id,
const wxDateTime &date,
const wxPoint &pos,
const wxSize &size,
long style,
const wxString &name)
{
wxString txt;
if (date.IsValid())
txt = date.FormatISODate();
if ( !wxControl::Create(parent, id, pos, size,
style | wxCLIP_CHILDREN | wxWANTS_CHARS,
wxDefaultValidator, name) )
{
return false;
}
InheritAttributes();
wxSize cs = GetClientSize();
wxSize bs = ConvertDialogToPixels(wxSize(10, 0));
wxBitmap bmp(8, 4);
{
wxMemoryDC dc;
dc.SelectObject(bmp);
dc.SetBrush(wxBrush(GetBackgroundColour()));
dc.SetPen(wxPen(GetBackgroundColour()));
dc.DrawRectangle(0, 0, 8, 4);
dc.SetBrush(wxBrush(GetForegroundColour()));
dc.SetPen(wxPen(GetForegroundColour()));
wxPoint pt[3] = { wxPoint(0, 0), wxPoint(6, 0), wxPoint(3, 3) };
dc.DrawPolygon(3, pt);
dc.SelectObject(wxNullBitmap);
}
m_txt = new wxTextCtrl(this, CTRLID_TXT, txt, wxDefaultPosition, size, TXTCTRL_FLAGS);
m_txt->Connect(wxID_ANY, wxID_ANY, wxEVT_KEY_DOWN, wxKeyEventHandler(wxCalendarBox::OnEditKey), 0, this);
m_txt->Connect(wxID_ANY, wxID_ANY, wxEVT_KILL_FOCUS, wxFocusEventHandler(wxCalendarBox::OnKillFocus), 0, this);
SetFormat(wxT("%Y-%m-%d"));
m_btn = new wxBitmapButton(this, CTRLID_BTN, bmp, wxDefaultPosition, bs);
m_dlg = new wxDialog(this, CTRLID_CAL, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER);
m_dlg->SetFont(GetFont());
wxPanel *panel = new wxPanel(m_dlg, CTRLID_PAN, wxPoint(0, 0), wxDefaultSize, wxSUNKEN_BORDER | wxCLIP_CHILDREN);
m_cal = new pgCompatCalendarCtrl(panel, CTRLID_CAL, wxDefaultDateTime, wxPoint(0, 0), wxDefaultSize, wxSUNKEN_BORDER);
m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_SEL_CHANGED, wxCalendarEventHandler(wxCalendarBox::OnSelChange), 0, this);
m_cal->Connect(wxID_ANY, wxID_ANY, wxEVT_KEY_DOWN, wxKeyEventHandler(wxCalendarBox::OnCalKey), 0, this);
m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_DOUBLECLICKED, wxCalendarEventHandler(wxCalendarBox::OnSelChange), 0, this);
m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_DAY_CHANGED, wxCalendarEventHandler(wxCalendarBox::OnSelChange), 0, this);
m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_MONTH_CHANGED, wxCalendarEventHandler(wxCalendarBox::OnSelChange), 0, this);
m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_YEAR_CHANGED, wxCalendarEventHandler(wxCalendarBox::OnSelChange), 0, this);
wxWindow *yearControl = m_cal->GetYearControl();
Connect(wxID_ANY, wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(wxCalendarBox::OnSetFocus));
wxClientDC dc(yearControl);
dc.SetFont(m_font);
wxCoord width, dummy;
dc.GetTextExtent(wxT("2000"), &width, &dummy);
width += ConvertDialogToPixels(wxSize(20, 0)).x;
wxSize calSize = m_cal->GetBestSize();
wxSize yearSize = yearControl->GetSize();
yearSize.x = width;
wxPoint yearPosition = yearControl->GetPosition();
width = yearPosition.x + yearSize.x + 2 + CALBORDER / 2;
if (width < calSize.x - 4)
width = calSize.x - 4;
int calPos = (width - calSize.x) / 2;
if (calPos == -1)
{
calPos = 0;
width += 2;
}
m_cal->SetSize(calPos, 0, calSize.x, calSize.y);
yearControl->SetSize(width - yearSize.x - CALBORDER / 2, yearPosition.y, yearSize.x, yearSize.y);
m_cal->GetMonthControl()->Move(0, 0);
SetInitialSize(size);
panel->SetClientSize(width + CALBORDER / 2, calSize.y - 2 + CALBORDER);
m_dlg->SetClientSize(panel->GetSize());
return true;
}
void wxCalendarBox::Init()
{
m_dlg = NULL;
m_txt = NULL;
m_cal = NULL;
m_btn = NULL;
m_dropped = false;
m_ignoreDrop = false;
}
bool wxCalendarBox::Destroy()
{
if (m_cal)
m_cal->Destroy();
if (m_dlg)
m_dlg->Destroy();
if (m_txt)
m_txt->Destroy();
if (m_btn)
m_btn->Destroy();
m_dlg = NULL;
m_txt = NULL;
m_cal = NULL;
m_btn = NULL;
return wxControl::Destroy();
}
void wxCalendarBox::DoMoveWindow(int x, int y, int w, int h)
{
wxControl::DoMoveWindow(x, y, w, h);
if (m_dropped)
{
DropDown();
}
}
wxSize wxCalendarBox::DoGetBestSize() const
{
int bh = m_btn->GetBestSize().y;
int eh = m_txt->GetBestSize().y;
return wxSize(100, bh > eh ? bh : eh);
}
void wxCalendarBox::OnSize(wxSizeEvent &event)
{
if ( m_btn )
{
wxSize sz = GetClientSize();
wxSize bs = m_btn->GetSize();
int eh = m_txt->GetBestSize().y;
m_txt->SetSize(TXTPOSX, TXTPOSY, sz.x - bs.x - TXTPOSX, sz.y > eh ? eh - TXTPOSY : sz.y - TXTPOSY);
m_btn->SetSize(sz.x - bs.x, 0, bs.x, sz.y);
}
event.Skip();
}
bool wxCalendarBox::Show(bool show)
{
if ( !wxControl::Show(show) )
{
return false;
}
if (!show)
{
if (m_dlg)
{
m_dlg->Hide();
m_dropped = false;
}
}
return true;
}
bool wxCalendarBox::Enable(bool enable)
{
if ( !wxControl::Enable(enable) )
{
return false;
}
if (m_cal)
{
if (enable)
m_cal->Show();
else
m_cal->Hide();
}
if (m_btn)
m_btn->Enable(enable);
return true;
}
bool wxCalendarBox::SetFormat(const wxChar *fmt)
{
wxDateTime dt;
dt.ParseFormat(wxT("2003-10-13"), wxT("%Y-%m-%d"));
wxString str = dt.Format(fmt);
const wxChar *p = (const wxChar *) str;
m_format = wxEmptyString;
while (*p)
{
int n = wxAtoi(p);
if (n == dt.GetDay())
{
m_format.Append(wxT("%d"));
p += 2;
}
else if (n == (int)dt.GetMonth() + 1)
{
m_format.Append(wxT("%m"));
p += 2;
}
else if (n == dt.GetYear())
{
m_format.Append(wxT("%Y"));
p += 4;
}
else
m_format.Append(*p++);
}
if (m_txt)
{
wxArrayString valArray;
wxChar c;
for (c = '0'; c <= '9'; c++)
valArray.Add(wxString(c, 1));
const wxChar *p = (const wxChar *) m_format;
while (*p)
{
if (*p == '%')
p += 2;
else
valArray.Add(wxString(*p++, 1));
}
wxTextValidator tv(wxFILTER_INCLUDE_CHAR_LIST);
tv.SetIncludes(valArray);
m_txt->SetValidator(tv);
}
return true;
}
wxDateTime wxCalendarBox::GetValue()
{
wxDateTime dt;
wxString txt = m_txt->GetValue();
if (!txt.IsEmpty())
dt.ParseFormat(txt, m_format);
return dt;
}
bool wxCalendarBox::SetValue(const wxDateTime &date)
{
bool retval = false;
if (m_cal)
{
if (date.IsValid())
m_txt->SetValue(date.FormatISODate());
else
m_txt->SetValue(wxEmptyString);
}
return retval;
}
void wxCalendarBox::DropDown(bool down)
{
if (m_dlg)
{
if (down)
{
if (m_txt->GetValue().IsEmpty())
m_cal->SetDate(wxDateTime::Today());
else
{
wxDateTime dt;
dt.ParseFormat(m_txt->GetValue(), m_format);
m_cal->SetDate(dt);
}
wxPoint pos = GetParent()->ClientToScreen(GetPosition());
m_dlg->Move(pos.x, pos.y + GetSize().y);
m_dlg->Show();
m_dropped = true;
}
else
{
if (m_dropped)
m_dlg->Hide();
m_dropped = false;
}
}
}
void wxCalendarBox::OnChildSetFocus(wxChildFocusEvent &ev)
{
ev.Skip();
m_ignoreDrop = false;
wxWindow *w = (wxWindow *)ev.GetEventObject();
while (w)
{
if (w == m_dlg)
return;
w = w->GetParent();
}
if (m_dropped)
{
DropDown(false);
if (ev.GetEventObject() == m_btn)
m_ignoreDrop = true;
}
}
void wxCalendarBox::OnClick(wxCommandEvent &event)
{
if (m_ignoreDrop)
{
m_ignoreDrop = false;
m_txt->SetFocus();
}
else
{
DropDown();
m_cal->SetFocus();
}
}
void wxCalendarBox::OnSetFocus(wxFocusEvent &ev)
{
if (m_txt)
{
m_txt->SetFocus();
m_txt->SetSelection(0, 100);
}
}
void wxCalendarBox::OnKillFocus(wxFocusEvent &ev)
{
wxDateTime dt;
dt.ParseFormat(m_txt->GetValue(), m_format);
if (!dt.IsValid())
m_txt->SetValue(wxEmptyString);
else
m_txt->SetValue(dt.Format(m_format));
}
void wxCalendarBox::OnSelChange(wxCalendarEvent &ev)
{
if (m_cal)
{
m_txt->SetValue(m_cal->GetDate().FormatISODate());
if (ev.GetEventType() == wxEVT_CALENDAR_DOUBLECLICKED)
{
DropDown(false);
m_txt->SetFocus();
}
}
ev.SetEventObject(this);
ev.SetId(GetId());
#if wxCHECK_VERSION(2, 9, 0)
GetParent()->GetEventHandler()->ProcessEvent(ev);
#else
GetParent()->ProcessEvent(ev);
#endif
}
void wxCalendarBox::OnText(wxCommandEvent &ev)
{
ev.SetEventObject(this);
ev.SetId(GetId());
#if wxCHECK_VERSION(2, 9, 0)
GetParent()->GetEventHandler()->ProcessEvent(ev);
#else
GetParent()->ProcessEvent(ev);
#endif
// We'll create an additional event if the date is valid.
// If the date isn't valid, the user's probably in the middle of typing
wxString txt = m_txt->GetValue();
wxDateTime dt;
if (!txt.IsEmpty())
dt.ParseFormat(txt, m_format);
#if wxCHECK_VERSION(2, 9, 0)
wxCalendarEvent cev(m_cal, dt, wxEVT_CALENDAR_SEL_CHANGED);
#else
wxCalendarEvent cev(m_cal, wxEVT_CALENDAR_SEL_CHANGED);
cev.SetDate(dt);
#endif
cev.SetEventObject(this);
cev.SetId(GetId());
#if wxCHECK_VERSION(2, 9, 0)
GetParent()->GetEventHandler()->ProcessEvent(cev);
#else
GetParent()->ProcessEvent(cev);
#endif
}
void wxCalendarBox::OnEditKey(wxKeyEvent &ev)
{
if (ev.GetKeyCode() == WXK_DOWN && !ev.HasModifiers())
DropDown();
else
ev.Skip();
}
void wxCalendarBox::OnCalKey(wxKeyEvent &ev)
{
if (ev.GetKeyCode() == WXK_ESCAPE && !ev.HasModifiers())
DropDown(false);
else
ev.Skip();
}
#endif // !defined(wxUSE_DATEPICKCTRL) || !wxUSE_DATEPICKCTRL