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"
namespace wxGridPrivate { class DateParseParams; }
// renderer for the cells containing dates only, without time component
class WXDLLIMPEXP_ADV wxGridCellDateRenderer : public wxGridCellStringRenderer
{
@@ -207,7 +209,11 @@ public:
protected:
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;
wxDateTime::TimeZone m_tz;
@@ -229,7 +235,8 @@ public:
virtual wxGridCellRenderer *Clone() const wxOVERRIDE;
protected:
virtual bool Parse(const wxString& text, wxDateTime& result) wxOVERRIDE;
virtual void
GetDateParseParams(wxGridPrivate::DateParseParams& params) const wxOVERRIDE;
wxString m_iformat;
};

View File

@@ -1089,11 +1089,51 @@ namespace wxGridPrivate
#if wxUSE_DATETIME
// Helper function trying to parse the given string using the specified date
// format and then using ParseDate() as a fallback if it failed. If this still
// fails, returns false.
// This is used as TryGetValueAsDate() parameter.
class DateParseParams
{
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
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

View File

@@ -77,22 +77,46 @@ void wxGridCellRenderer::Draw(wxGrid& grid,
#if wxUSE_DATETIME
bool
wxGridPrivate::TryParseDate(wxDateTime& result,
const wxString& text,
const wxString& format)
wxGridPrivate::TryGetValueAsDate(wxDateTime& result,
const DateParseParams& params,
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;
// Try parsing using the same format we use for output first.
if ( result.ParseFormat(text, format, &end) && end == text.end() )
if ( result.ParseFormat(text, params.format, &end) && end == text.end() )
return true;
// But fall back to free-form parsing, which notably allows us to parse
// strings such as "today" or "tomorrow" which would be never accepted by
// ParseFormat().
return result.ParseDate(text, &end) && end == text.end();
// Check if we can fall back to free-form parsing, which notably allows us
// to parse strings such as "today" or "tomorrow" which would be never
// accepted by ParseFormat().
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
wxGridCellDateRenderer::wxGridCellDateRenderer(const wxString& outformat)
@@ -115,40 +139,23 @@ wxGridCellRenderer *wxGridCellDateRenderer::Clone() const
wxString wxGridCellDateRenderer::GetString(const wxGrid& grid, int row, int col)
{
wxGridTableBase *table = grid.GetTable();
bool hasDatetime = false;
wxDateTime val;
wxString text;
if ( table->CanGetValueAs(row, col, wxGRID_VALUE_DATETIME) )
{
void * tempval = table->GetValueAsCustom(row, col,wxGRID_VALUE_DATETIME);
if (tempval)
{
val = *((wxDateTime *)tempval);
hasDatetime = true;
delete (wxDateTime *)tempval;
}
DateParseParams params;
GetDateParseParams(params);
}
if (!hasDatetime )
{
text = table->GetValue(row, col);
hasDatetime = Parse(text, val);
}
if ( hasDatetime )
wxDateTime val;
if ( TryGetValueAsDate(val, params, grid, row, col) )
text = val.Format(m_oformat, m_tz );
// If we failed to parse string just show what we where given?
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,
@@ -216,10 +223,10 @@ wxGridCellRenderer *wxGridCellDateTimeRenderer::Clone() const
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);
return end && !*end;
params = DateParseParams::WithoutFallback(m_iformat);
}
#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!");
const wxString dateStr = grid->GetTable()->GetValue(row, col);
if ( !wxGridPrivate::TryParseDate(m_value, dateStr, m_format) )
using namespace wxGridPrivate;
if ( !TryGetValueAsDate(m_value, DateParseParams::WithFallback(m_format),
*grid, row, col) )
{
// Invalidate m_value, so that it always compares different
// to any value returned from DatePicker()->GetValue().