Get dates directly from table in wxGridCellDateEditor if possible

Unlike wxGridCellDateRenderer, which already did it, the editor class
always got the cell value from the table as a string, even if the table
supported returning the dates directly.

Fix this by using the same code in the editor as in the renderer, which
required a further refactoring in order to make it reusable: the helper
TryParseDate() was replaced with TryGetValueAsDate() and DateParseParams
was added to allow overriding the arguments passed to it in the
overridden wxGridCellDateTimeRenderer::GetDateParseParams().
This commit is contained in:
Vadim Zeitlin
2020-11-03 17:30:54 +01:00
parent 9311dc8ffb
commit ce0f10c377
4 changed files with 100 additions and 44 deletions

View File

@@ -171,6 +171,8 @@ public:
#include "wx/datetime.h" #include "wx/datetime.h"
namespace wxGridPrivate { class DateParseParams; }
// renderer for the cells containing dates only, without time component // renderer for the cells containing dates only, without time component
class WXDLLIMPEXP_ADV wxGridCellDateRenderer : public wxGridCellStringRenderer class WXDLLIMPEXP_ADV wxGridCellDateRenderer : public wxGridCellStringRenderer
{ {
@@ -207,7 +209,11 @@ public:
protected: protected:
wxString GetString(const wxGrid& grid, int row, int col); wxString GetString(const wxGrid& grid, int row, int col);
virtual bool Parse(const wxString& text, wxDateTime& result);
// This is overridden in wxGridCellDateTimeRenderer which uses a separate
// input format and forbids fallback to ParseDate().
virtual void
GetDateParseParams(wxGridPrivate::DateParseParams& params) const;
wxString m_oformat; wxString m_oformat;
wxDateTime::TimeZone m_tz; wxDateTime::TimeZone m_tz;
@@ -229,7 +235,8 @@ public:
virtual wxGridCellRenderer *Clone() const wxOVERRIDE; virtual wxGridCellRenderer *Clone() const wxOVERRIDE;
protected: protected:
virtual bool Parse(const wxString& text, wxDateTime& result) wxOVERRIDE; virtual void
GetDateParseParams(wxGridPrivate::DateParseParams& params) const wxOVERRIDE;
wxString m_iformat; wxString m_iformat;
}; };

View File

@@ -1089,11 +1089,51 @@ namespace wxGridPrivate
#if wxUSE_DATETIME #if wxUSE_DATETIME
// Helper function trying to parse the given string using the specified date // This is used as TryGetValueAsDate() parameter.
// format and then using ParseDate() as a fallback if it failed. If this still class DateParseParams
// fails, returns false. {
public:
// Unfortunately we have to provide the default ctor (and also make the
// members non-const) because we use these objects as out-parameters as
// they are not fully declared in the public headers. The factory functions
// below must be used to create a really usable object.
DateParseParams() : fallbackParseDate(false) { }
// Use these functions to really initialize the object.
static DateParseParams WithFallback(const wxString& format)
{
return DateParseParams(format, true);
}
static DateParseParams WithoutFallback(const wxString& format)
{
return DateParseParams(format, false);
}
// The usual format, e.g. "%x" or "%Y-%m-%d".
wxString format;
// Whether fall back to ParseDate() is allowed.
bool fallbackParseDate;
private:
DateParseParams(const wxString& format_, bool fallbackParseDate_)
: format(format_),
fallbackParseDate(fallbackParseDate_)
{
}
};
// Helper function trying to get a date from the given cell: if possible, get
// the date value from the table directly, otherwise get the string value for
// this cell and try to parse it using the specified date format and, if this
// doesn't work and fallbackParseDate is true, try using ParseDate() as a
// fallback. If this still fails, returns false.
bool bool
TryParseDate(wxDateTime& result, const wxString& text, const wxString& format); TryGetValueAsDate(wxDateTime& result,
const DateParseParams& params,
const wxGrid& grid,
int row, int col);
#endif // wxUSE_DATETIME #endif // wxUSE_DATETIME

View File

@@ -77,22 +77,46 @@ void wxGridCellRenderer::Draw(wxGrid& grid,
#if wxUSE_DATETIME #if wxUSE_DATETIME
bool bool
wxGridPrivate::TryParseDate(wxDateTime& result, wxGridPrivate::TryGetValueAsDate(wxDateTime& result,
const wxString& text, const DateParseParams& params,
const wxString& format) const wxGrid& grid,
int row, int col)
{ {
wxGridTableBase *table = grid.GetTable();
if ( table->CanGetValueAs(row, col, wxGRID_VALUE_DATETIME) )
{
void * tempval = table->GetValueAsCustom(row, col,wxGRID_VALUE_DATETIME);
if (tempval)
{
result = *((wxDateTime *)tempval);
delete (wxDateTime *)tempval;
return true;
}
}
const wxString text = table->GetValue(row, col);
wxString::const_iterator end; wxString::const_iterator end;
// Try parsing using the same format we use for output first. if ( result.ParseFormat(text, params.format, &end) && end == text.end() )
if ( result.ParseFormat(text, format, &end) && end == text.end() )
return true; return true;
// But fall back to free-form parsing, which notably allows us to parse // Check if we can fall back to free-form parsing, which notably allows us
// strings such as "today" or "tomorrow" which would be never accepted by // to parse strings such as "today" or "tomorrow" which would be never
// ParseFormat(). // accepted by ParseFormat().
return result.ParseDate(text, &end) && end == text.end(); if ( params.fallbackParseDate &&
result.ParseDate(text, &end) && end == text.end() )
return true;
return false;
} }
using namespace wxGridPrivate;
// Enables a grid cell to display a formatted date // Enables a grid cell to display a formatted date
wxGridCellDateRenderer::wxGridCellDateRenderer(const wxString& outformat) wxGridCellDateRenderer::wxGridCellDateRenderer(const wxString& outformat)
@@ -115,40 +139,23 @@ wxGridCellRenderer *wxGridCellDateRenderer::Clone() const
wxString wxGridCellDateRenderer::GetString(const wxGrid& grid, int row, int col) wxString wxGridCellDateRenderer::GetString(const wxGrid& grid, int row, int col)
{ {
wxGridTableBase *table = grid.GetTable();
bool hasDatetime = false;
wxDateTime val;
wxString text; wxString text;
if ( table->CanGetValueAs(row, col, wxGRID_VALUE_DATETIME) )
{
void * tempval = table->GetValueAsCustom(row, col,wxGRID_VALUE_DATETIME);
if (tempval) DateParseParams params;
{ GetDateParseParams(params);
val = *((wxDateTime *)tempval);
hasDatetime = true;
delete (wxDateTime *)tempval;
}
} wxDateTime val;
if ( TryGetValueAsDate(val, params, grid, row, col) )
if (!hasDatetime )
{
text = table->GetValue(row, col);
hasDatetime = Parse(text, val);
}
if ( hasDatetime )
text = val.Format(m_oformat, m_tz ); text = val.Format(m_oformat, m_tz );
// If we failed to parse string just show what we where given? // If we failed to parse string just show what we where given?
return text; return text;
} }
bool wxGridCellDateRenderer::Parse(const wxString& text, wxDateTime& result) void
wxGridCellDateRenderer::GetDateParseParams(DateParseParams& params) const
{ {
return wxGridPrivate::TryParseDate(result, text, m_oformat); params = DateParseParams::WithFallback(m_oformat);
} }
void wxGridCellDateRenderer::Draw(wxGrid& grid, void wxGridCellDateRenderer::Draw(wxGrid& grid,
@@ -216,10 +223,10 @@ wxGridCellRenderer *wxGridCellDateTimeRenderer::Clone() const
return new wxGridCellDateTimeRenderer(*this); return new wxGridCellDateTimeRenderer(*this);
} }
bool wxGridCellDateTimeRenderer::Parse(const wxString& text, wxDateTime& result) void
wxGridCellDateTimeRenderer::GetDateParseParams(DateParseParams& params) const
{ {
const char * const end = result.ParseFormat(text, m_iformat); params = DateParseParams::WithoutFallback(m_iformat);
return end && !*end;
} }
#endif // wxUSE_DATETIME #endif // wxUSE_DATETIME

View File

@@ -1920,8 +1920,10 @@ void wxGridCellDateEditor::BeginEdit(int row, int col, wxGrid* grid)
{ {
wxASSERT_MSG(m_control, "The wxGridCellDateEditor must be created first!"); wxASSERT_MSG(m_control, "The wxGridCellDateEditor must be created first!");
const wxString dateStr = grid->GetTable()->GetValue(row, col); using namespace wxGridPrivate;
if ( !wxGridPrivate::TryParseDate(m_value, dateStr, m_format) )
if ( !TryGetValueAsDate(m_value, DateParseParams::WithFallback(m_format),
*grid, row, col) )
{ {
// Invalidate m_value, so that it always compares different // Invalidate m_value, so that it always compares different
// to any value returned from DatePicker()->GetValue(). // to any value returned from DatePicker()->GetValue().