Ensure that QDateTimeEdit::calendarWidget() will always return a valid widget.

This case may be triggered in the (admittedly slightly abnormal) case where a
user wishes to embed the calendar widget in a layout or, for whatever reason, do
something else that will change its ownership.

We work around this by detecting when it is deleted and recreating the widget.

This will also have a positive side effect if setCalendarWidget() is called with
a widget which is then subsequently deleted, returning the default widget
instead of a pointer to (now deleted) memory.

Reviewed-by: Denis Dzyubenko

Merge-request: 2568
Reviewed-by: Denis Dzyubenko <denis.dzyubenko@nokia.com>
(cherry picked from commit 124ec3200f8453142717fcfe7a4aa0a55164aaa6)
This commit is contained in:
Robin Burchell 2011-05-05 10:49:59 +02:00 committed by Olivier Goffart
parent 202df2ae89
commit 0bb70c3164
3 changed files with 56 additions and 18 deletions
src/gui/widgets
tests/auto/qdatetimeedit

View File

@ -2538,20 +2538,32 @@ void QDateTimeEditPrivate::syncCalendarWidget()
}
QCalendarPopup::QCalendarPopup(QWidget * parent, QCalendarWidget *cw)
: QWidget(parent, Qt::Popup), calendar(0)
: QWidget(parent, Qt::Popup)
{
setAttribute(Qt::WA_WindowPropagation);
dateChanged = false;
if (!cw) {
cw = new QCalendarWidget(this);
verifyCalendarInstance();
} else {
setCalendarWidget(cw);
}
}
QCalendarWidget *QCalendarPopup::verifyCalendarInstance()
{
if (calendar.isNull()) {
QCalendarWidget *cw = new QCalendarWidget(this);
cw->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
#ifdef QT_KEYPAD_NAVIGATION
if (QApplication::keypadNavigationEnabled())
cw->setHorizontalHeaderFormat(QCalendarWidget::SingleLetterDayNames);
#endif
setCalendarWidget(cw);
return cw;
} else {
return calendar.data();
}
setCalendarWidget(cw);
}
void QCalendarPopup::setCalendarWidget(QCalendarWidget *cw)
@ -2563,28 +2575,29 @@ void QCalendarPopup::setCalendarWidget(QCalendarWidget *cw)
widgetLayout->setMargin(0);
widgetLayout->setSpacing(0);
}
delete calendar;
calendar = cw;
widgetLayout->addWidget(calendar);
delete calendar.data();
calendar = QWeakPointer<QCalendarWidget>(cw);
widgetLayout->addWidget(cw);
connect(calendar, SIGNAL(activated(QDate)), this, SLOT(dateSelected(QDate)));
connect(calendar, SIGNAL(clicked(QDate)), this, SLOT(dateSelected(QDate)));
connect(calendar, SIGNAL(selectionChanged()), this, SLOT(dateSelectionChanged()));
connect(cw, SIGNAL(activated(QDate)), this, SLOT(dateSelected(QDate)));
connect(cw, SIGNAL(clicked(QDate)), this, SLOT(dateSelected(QDate)));
connect(cw, SIGNAL(selectionChanged()), this, SLOT(dateSelectionChanged()));
calendar->setFocus();
cw->setFocus();
}
void QCalendarPopup::setDate(const QDate &date)
{
oldDate = date;
calendar->setSelectedDate(date);
verifyCalendarInstance()->setSelectedDate(date);
}
void QCalendarPopup::setDateRange(const QDate &min, const QDate &max)
{
calendar->setMinimumDate(min);
calendar->setMaximumDate(max);
QCalendarWidget *cw = verifyCalendarInstance();
cw->setMinimumDate(min);
cw->setMaximumDate(max);
}
void QCalendarPopup::mousePressEvent(QMouseEvent *event)
@ -2620,7 +2633,7 @@ bool QCalendarPopup::event(QEvent *event)
void QCalendarPopup::dateSelectionChanged()
{
dateChanged = true;
emit newDateSelected(calendar->selectedDate());
emit newDateSelected(verifyCalendarInstance()->selectedDate());
}
void QCalendarPopup::dateSelected(const QDate &date)
{

View File

@ -148,11 +148,11 @@ class QCalendarPopup : public QWidget
Q_OBJECT
public:
QCalendarPopup(QWidget *parent = 0, QCalendarWidget *cw = 0);
QDate selectedDate() { return calendar->selectedDate(); }
QDate selectedDate() { return verifyCalendarInstance()->selectedDate(); }
void setDate(const QDate &date);
void setDateRange(const QDate &min, const QDate &max);
void setFirstDayOfWeek(Qt::DayOfWeek dow) { calendar->setFirstDayOfWeek(dow); }
QCalendarWidget *calendarWidget() const { return calendar; }
void setFirstDayOfWeek(Qt::DayOfWeek dow) { verifyCalendarInstance()->setFirstDayOfWeek(dow); }
QCalendarWidget *calendarWidget() const { return const_cast<QCalendarPopup*>(this)->verifyCalendarInstance(); }
void setCalendarWidget(QCalendarWidget *cw);
Q_SIGNALS:
void activated(const QDate &date);
@ -171,7 +171,9 @@ protected:
bool event(QEvent *e);
private:
QCalendarWidget *calendar;
QCalendarWidget *verifyCalendarInstance();
QWeakPointer<QCalendarWidget> calendar;
QDate oldDate;
bool dateChanged;
};

View File

@ -275,6 +275,8 @@ private slots:
void focusNextPrevChild();
void taskQTBUG_12384_timeSpecShowTimeOnly();
void deleteCalendarWidget();
private:
EditorDateEdit* testWidget;
@ -3438,5 +3440,26 @@ void tst_QDateTimeEdit::taskQTBUG_12384_timeSpecShowTimeOnly()
QCOMPARE(edit.time(), time.time());
}
void tst_QDateTimeEdit::deleteCalendarWidget()
{
{
// setup
QCalendarWidget *cw = 0;
QDateEdit edit;
QVERIFY(!edit.calendarWidget());
edit.setCalendarPopup(true);
QVERIFY(edit.calendarWidget());
edit.calendarWidget()->setObjectName("cw1");;
// delete
cw = edit.calendarWidget();
delete cw;
// it should create a new widget
QVERIFY(edit.calendarWidget());
QVERIFY(edit.calendarWidget()->objectName() != "cw1");
}
}
QTEST_MAIN(tst_QDateTimeEdit)
#include "tst_qdatetimeedit.moc"