PDA

View Full Version : Crash: using a dialog in a model



Brandybuck
10th April 2006, 07:23
I am getting some strange behavior that has me stumped. An otherwise working model/view/delegate program will crash if a static dialog is used within the Method::setData() or Delegate::setModelData() methods. The program will pop up two dialogs, then segfault when both are closed.

I am trying to use a QMessageBox::warning() when the user enters invalid data. This is something the program needs to do. I get the same behavior with other static dialogs (QColorDialog, etc). It happens with both QTableView and QListView. The double dialog and crash happens when the user presses the enter or tab keys when finished editing in the delegate. It does NOT happen if the user clicks elsewhere in the view to finish editing.

I have created a tiny sample program to demonstrate. It's as short as I can get it with both a model and delegate. Remove the QMessageBox dialog and the program works. Keep it in and watch the strangeness when you edit a value.


#include <QtGui>

class TestModel : public QAbstractTableModel {
Q_OBJECT
public:
TestModel(QObject *parent);
~TestModel();

QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole);
Qt::ItemFlags flags(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;

private:
QStringList items;
};

class TestDelegate : public QItemDelegate
{
Q_OBJECT
public:
TestDelegate(QObject *parent = 0);
~TestDelegate();

QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;
};



#include <QtGui>
#include "model.h"

TestModel::TestModel(QObject *parent) : QAbstractTableModel(parent)
{
items << "one" << "two" << "three" << "four";
}

TestModel::~TestModel() {}

QVariant TestModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) return QVariant();
if (index.row() >= items.count()) return QVariant();

if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) {
return items[index.row()];
} else {
return QVariant();
}
}

bool TestModel::setData(const QModelIndex &index,
const QVariant &value, int role)
{
if (!index.isValid()) return false;
if (index.row() >= items.count()) return false;
if (role != Qt::EditRole) return false;

QMessageBox::information(0, "Test", "This is a test");

items[index.row()] = value.toString();

emit dataChanged(index, index);
return true;
}

Qt::ItemFlags TestModel::flags(const QModelIndex &index) const
{
if (!index.isValid()) return Qt::ItemIsEnabled;
return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}

int TestModel::rowCount(const QModelIndex &) const
{
return items.count();
}

int TestModel::columnCount(const QModelIndex &) const
{
return 1;
}

TestDelegate::TestDelegate(QObject *parent) : QItemDelegate(parent) {}

TestDelegate::~TestDelegate() {}

QWidget *TestDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/*option*/,
const QModelIndex &index) const
{
QStringList items;
items << "one" <<"two" <<"three" <<"four";

QLineEdit *edit = new QLineEdit(parent);
edit->installEventFilter(const_cast<TestDelegate*>(this));
return edit;
}

void TestDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
QVariant value = index.model()->data(index, Qt::EditRole);

QLineEdit *edit =static_cast<QLineEdit*>(editor);
if (!edit) return;
edit->setText(value.toString());
}

void TestDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QLineEdit *edit = static_cast<QLineEdit*>(editor);
if (!edit) return;
QVariant value = edit->text();
model->setData(index, value);

}

void TestDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &/*index*/) const
{
if (editor) editor->setGeometry(option.rect);
}


#include <QtGui>
#include "model.h"

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

TestModel model(0);

QTableView view;
view.setModel(&model);

TestDelegate delegate;
view.setItemDelegate(&delegate);

view.show();
return app.exec();
}


I am using qt-4.1.2 on FreeBSD 6.0. I am going to submit this a bug to Trolltech as well, as I've not found anything similar in their tracker.

wysota
10th April 2006, 09:07
Apart from anything else... you are violating the model-view-delegate separation. You shouldn't be asking any questions or displaying any dialogs in the "model part". You should confirm the data on the view or delegate level. What if you want to change the data in the model without confirmation or even without user's knowledge?

About the crash -- run your application under debugger and show us the stack trace you get.

Brandybuck
10th April 2006, 21:30
Apart from anything else... you are violating the model-view-delegate separation. You shouldn't be asking any questions or displaying any dialogs in the "model part". You should confirm the data on the view or delegate level. What if you want to change the data in the model without confirmation or even without user's knowledge?
I have to validate the input in the model, because only the model has sufficient information to do so. All the delegate knows about is one particular index, and all the view knows about is what the model tells is through the standard model/view API. Only the model knows if the input is valid for the model.

But regardless, the crash happens when I pop up the dialog in the delegate instead, and even if I send a signal from the model to the view. You can't get better model/view separation than that! I can simply just reject the input, but that's rude to the user, who's left scratching his head as to why the delegate editor isn't working.

Brandybuck
11th April 2006, 01:39
I got a reply from Trolltech. This is a known issue, bug #106260, which is fixed in the latest snapshot and will be in 4.1.3.