mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 08:08:42 +00:00
Using to non-native filedialog on MacOS for DirectoryPathWidget (#4720)
Moved the filebrowsing from the widget to the delegate (MacOS only) Fixes #4719
This commit is contained in:
committed by
GitHub
parent
0ce00abd5f
commit
c8da333ab0
@@ -339,16 +339,16 @@ DirectoryPathWidget::DirectoryPathWidget
|
||||
{
|
||||
lineEdit = new QLineEdit();
|
||||
|
||||
openButton = new QPushButton(tr("Browse"));
|
||||
browseButton = new QPushButton(tr("Browse"));
|
||||
|
||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
layout->addWidget(lineEdit, 1);
|
||||
layout->addWidget(openButton, 0);
|
||||
layout->addWidget(browseButton, 0);
|
||||
|
||||
connect(openButton, SIGNAL(clicked()), this, SLOT(openDialog()));
|
||||
connect(lineEdit, SIGNAL(editingFinished()), this, SLOT(lineEditFinished()));
|
||||
connect(browseButton, &QPushButton::clicked, this, &DirectoryPathWidget::handleBrowseClicked);
|
||||
connect(lineEdit, &QLineEdit::editingFinished, this, &DirectoryPathWidget::lineEditFinished);
|
||||
}
|
||||
|
||||
|
||||
@@ -377,28 +377,63 @@ DirectoryPathWidget::setPlaceholderText
|
||||
|
||||
|
||||
void
|
||||
DirectoryPathWidget::openDialog
|
||||
DirectoryPathWidget::setDelegateMode
|
||||
(bool delegateMode)
|
||||
{
|
||||
this->delegateMode = delegateMode;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DirectoryPathWidget::handleBrowseClicked
|
||||
()
|
||||
{
|
||||
QFileDialog fileDialog(this);
|
||||
QStringList selectedDirs;
|
||||
fileDialog.setFileMode(QFileDialog::Directory);
|
||||
fileDialog.setOptions(QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
||||
if (delegateMode) {
|
||||
QTimer::singleShot(0, this, [=]() {
|
||||
openFileDialog();
|
||||
});
|
||||
} else {
|
||||
openFileDialog();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DirectoryPathWidget::openFileDialog
|
||||
()
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
// On macOS in delegate mode, emit a signal and let the delegate handle the dialog.
|
||||
// This avoids widget lifecycle issues where the editor is destroyed during
|
||||
// QFileDialog::exec().
|
||||
if (delegateMode) {
|
||||
emit browseRequested();
|
||||
return; // The delegate must take over.
|
||||
}
|
||||
#endif
|
||||
|
||||
// Standard modal dialog approach for non-delegate mode or non-macOS
|
||||
QFileDialog dialog(window());
|
||||
dialog.setFileMode(QFileDialog::Directory);
|
||||
dialog.setOptions( QFileDialog::ShowDirsOnly
|
||||
| QFileDialog::DontResolveSymlinks);
|
||||
QString path = lineEdit->text();
|
||||
if (path.isEmpty()) {
|
||||
path = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
|
||||
}
|
||||
fileDialog.setDirectory(path);
|
||||
if (fileDialog.exec()) {
|
||||
selectedDirs = fileDialog.selectedFiles();
|
||||
}
|
||||
if (selectedDirs.count() > 0) {
|
||||
QString dir = selectedDirs.at(0);
|
||||
if (dir != "") {
|
||||
lineEdit->setText(dir);
|
||||
dialog.setDirectory(path);
|
||||
bool accepted = false;
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
const QStringList selectedDirs = dialog.selectedFiles();
|
||||
if (! selectedDirs.isEmpty()) {
|
||||
QString selectedDir = selectedDirs.first();
|
||||
if (! selectedDir.isEmpty()) {
|
||||
setPath(selectedDir);
|
||||
accepted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
emit editingFinished();
|
||||
emit editingFinished(accepted);
|
||||
}
|
||||
|
||||
|
||||
@@ -412,8 +447,8 @@ DirectoryPathWidget::lineEditFinished
|
||||
}
|
||||
lineEditAlreadyFinished = true;
|
||||
|
||||
if (! openButton->hasFocus()) {
|
||||
emit editingFinished();
|
||||
if (! browseButton->hasFocus()) {
|
||||
emit editingFinished(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,8 +470,17 @@ DirectoryPathDelegate::createEditor
|
||||
Q_UNUSED(index)
|
||||
|
||||
DirectoryPathWidget *editor = new DirectoryPathWidget(parent);
|
||||
editor->setDelegateMode(true);
|
||||
editor->setPlaceholderText(placeholderText);
|
||||
connect(editor, SIGNAL(editingFinished()), this, SLOT(commitAndCloseEditor()));
|
||||
|
||||
DirectoryPathDelegate *delegate = const_cast<DirectoryPathDelegate*>(this);
|
||||
#ifdef Q_OS_MACOS
|
||||
// On macOS, the delegate handles the dialog to prevent lifecycle crashes.
|
||||
connect(editor, &DirectoryPathWidget::browseRequested, delegate, [delegate, editor, index]() {
|
||||
delegate->openFileDialogForEditor(editor, index);
|
||||
});
|
||||
#endif
|
||||
connect(editor, &DirectoryPathWidget::editingFinished, delegate, &DirectoryPathDelegate::onEditingFinished);
|
||||
|
||||
return editor;
|
||||
}
|
||||
@@ -446,8 +490,9 @@ void
|
||||
DirectoryPathDelegate::setEditorData
|
||||
(QWidget *editor, const QModelIndex &index) const
|
||||
{
|
||||
DirectoryPathWidget *filepath = static_cast<DirectoryPathWidget*>(editor);
|
||||
filepath->setPath(index.data(Qt::DisplayRole).toString());
|
||||
if (DirectoryPathWidget *pathEditor = qobject_cast<DirectoryPathWidget*>(editor)) {
|
||||
pathEditor->setPath(index.data(Qt::EditRole).toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -455,8 +500,9 @@ void
|
||||
DirectoryPathDelegate::setModelData
|
||||
(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
|
||||
{
|
||||
DirectoryPathWidget *filepath = static_cast<DirectoryPathWidget*>(editor);
|
||||
model->setData(index, filepath->getPath(), Qt::DisplayRole);
|
||||
if (DirectoryPathWidget *pathEditor = qobject_cast<DirectoryPathWidget*>(editor)) {
|
||||
model->setData(index, pathEditor->getPath(), Qt::EditRole);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -518,15 +564,62 @@ DirectoryPathDelegate::setPlaceholderText
|
||||
|
||||
|
||||
void
|
||||
DirectoryPathDelegate::commitAndCloseEditor
|
||||
()
|
||||
DirectoryPathDelegate::onEditingFinished
|
||||
(bool accepted)
|
||||
{
|
||||
QWidget *editor = qobject_cast<QWidget*>(sender());
|
||||
emit commitData(editor);
|
||||
emit closeEditor(editor);
|
||||
DirectoryPathWidget *editor = qobject_cast<DirectoryPathWidget*>(sender());
|
||||
if (editor) {
|
||||
if (accepted) {
|
||||
emit commitData(editor);
|
||||
}
|
||||
emit closeEditor(editor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
void
|
||||
DirectoryPathDelegate::closeEditorForWidget
|
||||
(QWidget *editor)
|
||||
{
|
||||
if (editor) {
|
||||
emit closeEditor(editor, QAbstractItemDelegate::NoHint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DirectoryPathDelegate::openFileDialogForEditor
|
||||
(QWidget *editor, const QModelIndex &index) const
|
||||
{
|
||||
QPointer<QWidget> pathEditor(editor);
|
||||
QFileDialog dialog(pathEditor.data());
|
||||
dialog.setFileMode(QFileDialog::Directory);
|
||||
dialog.setOption(QFileDialog::ShowDirsOnly, true);
|
||||
dialog.setOption(QFileDialog::DontUseNativeDialog, true);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
// Check if the editor widget still exists before using it
|
||||
if (!pathEditor.isNull()) {
|
||||
QString selectedDir = dialog.selectedFiles().first();
|
||||
// Write directly to the model - this persists the data
|
||||
QAbstractItemModel *model = const_cast<QAbstractItemModel*>(index.model());
|
||||
model->setData(index, selectedDir, Qt::EditRole);
|
||||
}
|
||||
}
|
||||
|
||||
// The editor might have been destroyed during dialog.exec().
|
||||
// Schedule the closeEditor call to happen safely in the event loop.
|
||||
if (!pathEditor.isNull()) {
|
||||
QTimer::singleShot(0, const_cast<DirectoryPathDelegate*>(this), [this, pathEditor]() {
|
||||
if (!pathEditor.isNull()) {
|
||||
const_cast<DirectoryPathDelegate*>(this)->closeEditorForWidget(pathEditor.data());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// ListEditWidget //////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -534,7 +627,7 @@ ListEditWidget::ListEditWidget
|
||||
(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
dialog = new QDialog(this);
|
||||
dialog = new QDialog(parent);
|
||||
dialog->setModal(true);
|
||||
|
||||
title = new QLabel();
|
||||
|
||||
@@ -145,20 +145,28 @@ class DirectoryPathWidget: public QWidget
|
||||
public:
|
||||
DirectoryPathWidget(QWidget *parent = nullptr);
|
||||
|
||||
void setPath(const QString &path);
|
||||
QString getPath() const;
|
||||
void setPlaceholderText(const QString &placeholder);
|
||||
void setDelegateMode(bool delegateMode);
|
||||
|
||||
public slots:
|
||||
void setPath(const QString &path);
|
||||
|
||||
signals:
|
||||
void editingFinished();
|
||||
void editingFinished(bool accepted);
|
||||
#ifdef Q_OS_MACOS
|
||||
void browseRequested();
|
||||
#endif
|
||||
|
||||
private:
|
||||
QPushButton *openButton;
|
||||
bool delegateMode = false;
|
||||
QPushButton *browseButton;
|
||||
QLineEdit *lineEdit;
|
||||
bool lineEditAlreadyFinished = false;
|
||||
|
||||
private slots:
|
||||
void openDialog();
|
||||
void handleBrowseClicked();
|
||||
void openFileDialog();
|
||||
void lineEditFinished();
|
||||
};
|
||||
|
||||
@@ -179,12 +187,16 @@ public:
|
||||
void setMaxWidth(int maxWidth);
|
||||
void setPlaceholderText(const QString &placeholderText);
|
||||
|
||||
private slots:
|
||||
void commitAndCloseEditor();
|
||||
|
||||
private:
|
||||
int maxWidth = -1;
|
||||
QString placeholderText;
|
||||
#ifdef Q_OS_MACOS
|
||||
void closeEditorForWidget(QWidget *editor);
|
||||
void openFileDialogForEditor(QWidget *editor, const QModelIndex &index) const;
|
||||
#endif
|
||||
|
||||
private slots:
|
||||
void onEditingFinished(bool accepted);
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user