Qt: Handle UAT editor dialogs explicitly.
QAbstractItemView assumes that editors are widgets, not windows. QAbstractItemView::edit calls QAbstractItemViewPrivate::openEditor, which simply calls show() and setFocus() on the editor widget. If that widget happens to be a native dialog, its event loop might not be processed. This is the case on macOS at least. Create widgets derived from QLineEdit that edit the value directly along with a button that can open the associated modal dialog. Install event filters so that we keep the correct tab behavior between fields of the UAT. Bug: 13958 Ping-Bug: 14031 Bug: 7761 Change-Id: Ie5f0a5cbde33bb9add8217029c2063a0bbfd804a Reviewed-on: https://code.wireshark.org/review/23015 Reviewed-by: Gerald Combs <gerald@wireshark.org> Petri-Dish: Gerald Combs <gerald@wireshark.org> Tested-by: Petri Dish Buildbot Reviewed-by: Roland Knall <rknall@gmail.com>
This commit is contained in:
parent
9a5217bdd4
commit
f789736521
|
@ -23,6 +23,9 @@
|
|||
#include <ui/qt/widgets/editor_file_dialog.h>
|
||||
#include <ui/qt/widgets/editor_color_dialog.h>
|
||||
|
||||
// The Qt docs suggest overriding updateEditorGeometry, but the
|
||||
// defaults seem sane.
|
||||
|
||||
UatDelegate::UatDelegate(QObject *parent) : QStyledItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
|
@ -42,12 +45,10 @@ QWidget *UatDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &
|
|||
case PT_TXTMOD_DIRECTORYNAME:
|
||||
if (index.isValid()) {
|
||||
QString filename_old = index.model()->data(index, Qt::EditRole).toString();
|
||||
EditorFileDialog* fileDialog = new EditorFileDialog(index, parent, QString(field->title), filename_old);
|
||||
|
||||
fileDialog->setFileMode(QFileDialog::DirectoryOnly);
|
||||
EditorFileDialog* fileDialog = new EditorFileDialog(index, EditorFileDialog::Directory, parent, QString(field->title), filename_old);
|
||||
|
||||
//Use signals to accept data from cell
|
||||
connect(fileDialog, SIGNAL(acceptEdit(const QModelIndex &)), this, SLOT(applyDirectory(const QModelIndex&)));
|
||||
connect(fileDialog, SIGNAL(acceptEdit(const QModelIndex &)), this, SLOT(applyFilename(const QModelIndex&)));
|
||||
return fileDialog;
|
||||
}
|
||||
|
||||
|
@ -57,9 +58,8 @@ QWidget *UatDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &
|
|||
case PT_TXTMOD_FILENAME:
|
||||
if (index.isValid()) {
|
||||
QString filename_old = index.model()->data(index, Qt::EditRole).toString();
|
||||
EditorFileDialog* fileDialog = new EditorFileDialog(index, parent, QString(field->title), filename_old);
|
||||
EditorFileDialog* fileDialog = new EditorFileDialog(index, EditorFileDialog::ExistingFile, parent, QString(field->title), filename_old);
|
||||
|
||||
fileDialog->setFileMode(QFileDialog::ExistingFile);
|
||||
fileDialog->setOption(QFileDialog::DontConfirmOverwrite);
|
||||
|
||||
//Use signals to accept data from cell
|
||||
|
@ -73,9 +73,7 @@ QWidget *UatDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &
|
|||
case PT_TXTMOD_COLOR:
|
||||
if (index.isValid()) {
|
||||
QColor color(index.model()->data(index, Qt::DecorationRole).toString());
|
||||
EditorColorDialog *colorDialog = new EditorColorDialog(index, color, new QWidget(parent));
|
||||
|
||||
colorDialog->setWindowFlags(Qt::Window);
|
||||
EditorColorDialog *colorDialog = new EditorColorDialog(index, color, parent);
|
||||
|
||||
//Use signals to accept data from cell
|
||||
connect(colorDialog, SIGNAL(acceptEdit(const QModelIndex &)), this, SLOT(applyColor(const QModelIndex &)));
|
||||
|
@ -179,8 +177,6 @@ void UatDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
|||
model->setData(index, data, Qt::EditRole);
|
||||
break;
|
||||
}
|
||||
case PT_TXTMOD_DIRECTORYNAME:
|
||||
case PT_TXTMOD_FILENAME:
|
||||
case PT_TXTMOD_COLOR:
|
||||
//do nothing, dialog signals will update table
|
||||
break;
|
||||
|
@ -190,58 +186,18 @@ void UatDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
|||
}
|
||||
}
|
||||
|
||||
void UatDelegate::updateEditorGeometry(QWidget *editor,
|
||||
const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
uat_field_t *field = indexToField(index);
|
||||
|
||||
switch (field->mode) {
|
||||
case PT_TXTMOD_DIRECTORYNAME:
|
||||
{
|
||||
QRect rect = option.rect;
|
||||
rect.setBottom(rect.width());
|
||||
editor->setGeometry(rect);
|
||||
break;
|
||||
}
|
||||
case PT_TXTMOD_FILENAME:
|
||||
{
|
||||
QRect rect = option.rect;
|
||||
rect.setWidth(600);
|
||||
rect.setHeight(600);
|
||||
editor->setGeometry(rect);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
//the defaults for other editors seem sane.
|
||||
QStyledItemDelegate::updateEditorGeometry(editor, option, index);
|
||||
}
|
||||
}
|
||||
|
||||
void UatDelegate::applyFilename(const QModelIndex& index)
|
||||
{
|
||||
if (index.isValid()) {
|
||||
EditorFileDialog* fileDialog = static_cast<EditorFileDialog*>(sender());
|
||||
|
||||
QStringList files = fileDialog->selectedFiles();
|
||||
if (files.size() > 0) {
|
||||
((QAbstractItemModel *)index.model())->setData(index, files[0], Qt::EditRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UatDelegate::applyDirectory(const QModelIndex& index)
|
||||
{
|
||||
if (index.isValid()) {
|
||||
EditorFileDialog* fileDialog = static_cast<EditorFileDialog*>(sender());
|
||||
const QString &data = fileDialog->directory().absolutePath();
|
||||
((QAbstractItemModel *)index.model())->setData(index, data, Qt::EditRole);
|
||||
((QAbstractItemModel *)index.model())->setData(index, fileDialog->text(), Qt::EditRole);
|
||||
}
|
||||
}
|
||||
|
||||
void UatDelegate::applyColor(const QModelIndex& index)
|
||||
{
|
||||
if (index.isValid()) {
|
||||
QColorDialog *colorDialog = static_cast<QColorDialog*>(sender());
|
||||
EditorColorDialog *colorDialog = static_cast<EditorColorDialog*>(sender());
|
||||
QColor newColor = colorDialog->currentColor();
|
||||
((QAbstractItemModel *)index.model())->setData(index, newColor.name(), Qt::EditRole);
|
||||
}
|
||||
|
|
|
@ -32,11 +32,7 @@ public:
|
|||
void setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const;
|
||||
|
||||
void updateEditorGeometry(QWidget *editor,
|
||||
const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
|
||||
private slots:
|
||||
void applyDirectory(const QModelIndex& index);
|
||||
void applyFilename(const QModelIndex& index);
|
||||
void applyColor(const QModelIndex& index);
|
||||
|
||||
|
|
|
@ -10,24 +10,67 @@
|
|||
|
||||
#include <ui/qt/widgets/editor_color_dialog.h>
|
||||
|
||||
EditorColorDialog::EditorColorDialog(const QModelIndex& index, QWidget* parent)
|
||||
: QColorDialog(parent)
|
||||
, index_(index)
|
||||
{
|
||||
|
||||
}
|
||||
#include <QColorDialog>
|
||||
#include <QKeyEvent>
|
||||
#include <QStyle>
|
||||
|
||||
EditorColorDialog::EditorColorDialog(const QModelIndex& index, const QColor& initial, QWidget* parent)
|
||||
: QColorDialog(initial, parent)
|
||||
: QLineEdit(parent)
|
||||
, color_button_(new QPushButton(this))
|
||||
, index_(index)
|
||||
, current_(initial)
|
||||
{
|
||||
|
||||
connect(color_button_, SIGNAL(clicked()), this, SLOT(applyColor()));
|
||||
}
|
||||
|
||||
void EditorColorDialog::accept()
|
||||
// QAbstractItemView installs QAbstractItemDelegate's event filter after
|
||||
// we've been created. We need to install our own event filter after that
|
||||
// happens so that we can steal tab keypresses.
|
||||
void EditorColorDialog::focusInEvent(QFocusEvent *event)
|
||||
{
|
||||
emit acceptEdit(index_);
|
||||
QColorDialog::accept();
|
||||
installEventFilter(this);
|
||||
QLineEdit::focusInEvent(event);
|
||||
}
|
||||
|
||||
void EditorColorDialog::focusOutEvent(QFocusEvent *event)
|
||||
{
|
||||
removeEventFilter(this);
|
||||
QLineEdit::focusOutEvent(event);
|
||||
}
|
||||
|
||||
bool EditorColorDialog::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent* key = static_cast<QKeyEvent*>(event);
|
||||
if ( (key->key() == Qt::Key_Tab) && !color_button_->hasFocus()) {
|
||||
color_button_->setFocus();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QLineEdit::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void EditorColorDialog::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
// Move the button to the end of the line edit and set its height.
|
||||
QSize sz = color_button_->sizeHint();
|
||||
int frame_width = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
||||
color_button_->move(rect().right() - frame_width - sz.width(),
|
||||
contentsRect().top());
|
||||
color_button_->setMinimumHeight(contentsRect().height());
|
||||
color_button_->setMaximumHeight(contentsRect().height());
|
||||
}
|
||||
|
||||
void EditorColorDialog::applyColor()
|
||||
{
|
||||
QColorDialog color_dlg;
|
||||
|
||||
color_dlg.setCurrentColor(current_);
|
||||
if (color_dlg.exec() == QDialog::Accepted) {
|
||||
current_ = color_dlg.currentColor();
|
||||
emit acceptEdit(index_);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -11,23 +11,33 @@
|
|||
#ifndef EDITOR_COLOR_DIALOG_H_
|
||||
#define EDITOR_COLOR_DIALOG_H_
|
||||
|
||||
#include <QColorDialog>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QModelIndex>
|
||||
|
||||
class EditorColorDialog : public QColorDialog
|
||||
class EditorColorDialog : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
EditorColorDialog(const QModelIndex& index, QWidget* parent = 0);
|
||||
EditorColorDialog(const QModelIndex& index, const QColor& initial, QWidget* parent = 0);
|
||||
|
||||
void accept();
|
||||
QColor currentColor() { return current_; }
|
||||
virtual void focusInEvent(QFocusEvent *event);
|
||||
virtual void focusOutEvent(QFocusEvent *event);
|
||||
virtual bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
signals:
|
||||
void acceptEdit(const QModelIndex& index);
|
||||
|
||||
private slots:
|
||||
void applyColor();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *);
|
||||
|
||||
QPushButton* color_button_;
|
||||
const QModelIndex index_; //saved index of table cell
|
||||
QColor current_; //initial color in edit
|
||||
};
|
||||
|
||||
#endif /* EDITOR_COLOR_DIALOG_H_ */
|
||||
|
|
|
@ -10,22 +10,100 @@
|
|||
|
||||
#include <ui/qt/widgets/editor_file_dialog.h>
|
||||
|
||||
EditorFileDialog::EditorFileDialog(const QModelIndex& index, QWidget* parent, Qt::WindowFlags flags)
|
||||
: QFileDialog(parent, flags)
|
||||
#include <QKeyEvent>
|
||||
#include <QStyle>
|
||||
|
||||
#include "wsutil/utf8_entities.h"
|
||||
|
||||
EditorFileDialog::EditorFileDialog(const QModelIndex& index, enum FileMode mode, QWidget* parent, const QString& caption, const QString& directory, const QString& filter)
|
||||
: QLineEdit(parent)
|
||||
, file_dialog_button_(new QPushButton(this))
|
||||
, index_(index)
|
||||
, mode_(mode)
|
||||
, caption_(caption)
|
||||
, directory_(directory)
|
||||
, filter_(filter)
|
||||
, options_(0)
|
||||
{
|
||||
if (mode_ == Directory)
|
||||
options_ = QFileDialog::ShowDirsOnly;
|
||||
|
||||
if (!directory.isEmpty())
|
||||
setText(directory);
|
||||
|
||||
file_dialog_button_->setText(UTF8_HORIZONTAL_ELLIPSIS);
|
||||
connect(file_dialog_button_, SIGNAL(clicked()), this, SLOT(applyFilename()));
|
||||
}
|
||||
|
||||
EditorFileDialog::EditorFileDialog(const QModelIndex& index, QWidget* parent, const QString& caption, const QString& directory, const QString& filter)
|
||||
: QFileDialog(parent, caption, directory, filter)
|
||||
, index_(index)
|
||||
void EditorFileDialog::setOption(QFileDialog::Option option, bool on)
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
options_ |= option;
|
||||
}
|
||||
else
|
||||
{
|
||||
options_ &= (~option);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorFileDialog::accept()
|
||||
// QAbstractItemView installs QAbstractItemDelegate's event filter after
|
||||
// we've been created. We need to install our own event filter after that
|
||||
// happens so that we can steal tab keypresses.
|
||||
void EditorFileDialog::focusInEvent(QFocusEvent *event)
|
||||
{
|
||||
emit acceptEdit(index_);
|
||||
QFileDialog::accept();
|
||||
installEventFilter(this);
|
||||
QLineEdit::focusInEvent(event);
|
||||
}
|
||||
|
||||
void EditorFileDialog::focusOutEvent(QFocusEvent *event)
|
||||
{
|
||||
removeEventFilter(this);
|
||||
QLineEdit::focusOutEvent(event);
|
||||
}
|
||||
|
||||
bool EditorFileDialog::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent* key = static_cast<QKeyEvent*>(event);
|
||||
if ( (key->key() == Qt::Key_Tab) && !file_dialog_button_->hasFocus()) {
|
||||
file_dialog_button_->setFocus();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QLineEdit::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void EditorFileDialog::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
// Move the button to the end of the line edit and set its height.
|
||||
QSize sz = file_dialog_button_->sizeHint();
|
||||
int frame_width = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
||||
file_dialog_button_->move(rect().right() - frame_width - sz.width(),
|
||||
contentsRect().top());
|
||||
file_dialog_button_->setMinimumHeight(contentsRect().height());
|
||||
file_dialog_button_->setMaximumHeight(contentsRect().height());
|
||||
|
||||
}
|
||||
|
||||
void EditorFileDialog::applyFilename()
|
||||
{
|
||||
QString file;
|
||||
|
||||
if (mode_ == Directory)
|
||||
{
|
||||
file = QFileDialog::getExistingDirectory(this, caption_, directory_, options_);
|
||||
}
|
||||
else
|
||||
{
|
||||
file = QFileDialog::getOpenFileName(this, caption_, directory_, filter_, NULL, options_);
|
||||
}
|
||||
|
||||
if (!file.isEmpty())
|
||||
{
|
||||
setText(file);
|
||||
emit acceptEdit(index_);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -11,23 +11,39 @@
|
|||
#ifndef EDITOR_FILE_DIALOG_H_
|
||||
#define EDITOR_FILE_DIALOG_H_
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QModelIndex>
|
||||
#include <QLineEdit>
|
||||
#include <QFileDialog>
|
||||
#include <QPushButton>
|
||||
|
||||
class EditorFileDialog : public QFileDialog
|
||||
class EditorFileDialog : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit EditorFileDialog(const QModelIndex& index, QWidget* parent, Qt::WindowFlags flags);
|
||||
explicit EditorFileDialog(const QModelIndex& index, QWidget* parent = 0, const QString & caption = QString(), const QString & directory = QString(), const QString & filter = QString());
|
||||
enum FileMode { ExistingFile, Directory };
|
||||
|
||||
void accept();
|
||||
explicit EditorFileDialog(const QModelIndex& index, enum FileMode mode, QWidget* parent = 0, const QString & caption = QString(), const QString & directory = QString(), const QString & filter = QString());
|
||||
|
||||
void setOption(QFileDialog::Option option, bool on = true);
|
||||
virtual void focusInEvent(QFocusEvent *event);
|
||||
virtual void focusOutEvent(QFocusEvent *event);
|
||||
virtual bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
signals:
|
||||
void acceptEdit(const QModelIndex& index);
|
||||
|
||||
private slots:
|
||||
void applyFilename();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *);
|
||||
QPushButton* file_dialog_button_;
|
||||
const QModelIndex index_; //saved index of table cell
|
||||
enum FileMode mode_;
|
||||
QString caption_;
|
||||
QString directory_;
|
||||
QString filter_;
|
||||
QFileDialog::Options options_;
|
||||
};
|
||||
|
||||
#endif /* EDITOR_FILE_DIALOG_H_ */
|
||||
|
|
Loading…
Reference in New Issue