1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-08-12 10:45:38 +02:00

FileDialog: make a single instance filedialog

Modify the presentDialog method to account for single instance windows and implement a "hack" around the modality issues of Qt.

GitLab: #1905
Change-Id: I166bfc028939240955f20ec9b5777d6f282ccf78
This commit is contained in:
pmagnier-slimani 2025-02-18 16:12:23 -05:00 committed by François-Simon Fauteux-Chapleau
parent 9b51f26e80
commit aa375a7f89
5 changed files with 60 additions and 29 deletions

View file

@ -19,19 +19,17 @@ import QtQuick.Window
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import Qt5Compat.GraphicalEffects import Qt5Compat.GraphicalEffects
import net.jami.Models 1.1 import net.jami.Models 1.1
import net.jami.Adapters 1.1 import net.jami.Adapters 1.1
import net.jami.Enums 1.1 import net.jami.Enums 1.1
import net.jami.Helpers 1.1 import net.jami.Helpers 1.1
import net.jami.Constants 1.1 import net.jami.Constants 1.1
import "mainview" import "mainview"
import "mainview/components" import "mainview/components"
import "wizardview" import "wizardview"
import "commoncomponents" import "commoncomponents"
import QWindowKit import QWindowKit
import QtQuick.Dialogs
ApplicationWindow { ApplicationWindow {
id: appWindow id: appWindow
@ -87,9 +85,11 @@ ApplicationWindow {
appContainer: fullscreenContainer appContainer: fullscreenContainer
} }
// Used to manage dynamic view loading and unloading. // Used to manage dynamic view loading and unloading.
property ViewManager viewManager: ViewManager {} property ViewManager viewManager: ViewManager {
}
// Used to manage the view stack and the current view. // Used to manage the view stack and the current view.
property ViewCoordinator viewCoordinator: ViewCoordinator {} property ViewCoordinator viewCoordinator: ViewCoordinator {
}
// Used to prevent the window from being visible until the // Used to prevent the window from being visible until the
// window geometry has been restored and the view stack has // window geometry has been restored and the view stack has
@ -199,7 +199,6 @@ ApplicationWindow {
if (useFrameless) { if (useFrameless) {
windowAgent.setup(appWindow); windowAgent.setup(appWindow);
} }
mainViewLoader.active = true; mainViewLoader.active = true;
// Dbus error handler for Linux. // Dbus error handler for Linux.
@ -216,10 +215,14 @@ ApplicationWindow {
"confirmLabel": JamiStrings.send, "confirmLabel": JamiStrings.send,
"rejectLabel": JamiStrings.dontSend, "rejectLabel": JamiStrings.dontSend,
"textHAlign": Text.AlignLeft, "textHAlign": Text.AlignLeft,
"textMaxWidth": 400, "textMaxWidth": 400
});
dlg.accepted.connect(function () {
crashReporter.uploadLastReport();
});
dlg.rejected.connect(function () {
crashReporter.clearReports();
}); });
dlg.accepted.connect(function () { crashReporter.uploadLastReport(); });
dlg.rejected.connect(function () { crashReporter.clearReports(); });
} }
} }
@ -293,7 +296,7 @@ ApplicationWindow {
target: MainApplication target: MainApplication
function onAboutToQuit() { function onAboutToQuit() {
cleanupMainView() cleanupMainView();
} }
function onCloseRequested() { function onCloseRequested() {
@ -382,7 +385,7 @@ ApplicationWindow {
presentUpdateInfoDialog(JamiStrings.updateNotFound); presentUpdateInfoDialog(JamiStrings.updateNotFound);
} else { } else {
// Show a dialog describing that an update were found, and offering to install it. // Show a dialog describing that an update were found, and offering to install it.
presentUpdateConfirmInstallDialog() presentUpdateConfirmInstallDialog();
} }
} }
@ -393,4 +396,20 @@ ApplicationWindow {
} }
onClosing: appWindow.close() onClosing: appWindow.close()
// Capture the inputs to the main window while the File Dialog is open
// This is used to mitigate modality issues on Ubuntu 22.04 systems that use wayland.
Loader {
active: JamiQmlUtils.openFileDialogCount > 0
sourceComponent: Popup {
modal: true
visible: true
closePolicy: Popup.NoAutoClose
width: appWindow.width
height: appWindow.height
background: Rectangle {
color: "#80808080" // Semi-transparent grey
}
}
}
} }

View file

@ -49,13 +49,13 @@ QtObject {
// right side when not in RTL and should represent the main or content-type view. // right side when not in RTL and should represent the main or content-type view.
readonly property var visibleViews: { readonly property var visibleViews: {
if (!currentView) if (!currentView)
return [] return [];
if (isDualPane) { if (isDualPane) {
if (isInSinglePaneMode) if (isInSinglePaneMode)
return [currentView.rightPaneItem] return [currentView.rightPaneItem];
return [currentView.leftPaneItem, currentView.rightPaneItem] return [currentView.leftPaneItem, currentView.rightPaneItem];
} }
return [currentView] return [currentView];
} }
// Aggregate this info and expose it as a single string for convenience. // Aggregate this info and expose it as a single string for convenience.
// JSON indented by 2 spaces. // JSON indented by 2 spaces.
@ -69,7 +69,7 @@ QtObject {
}), }),
visibleViewWidths: visibleViews.map(function (view) { visibleViewWidths: visibleViews.map(function (view) {
return view && view.width || null; return view && view.width || null;
}), })
}; };
return JSON.stringify(info, null, 2); return JSON.stringify(info, null, 2);
} }
@ -96,9 +96,10 @@ QtObject {
} }
// Create, present, and return a dialog object. // Create, present, and return a dialog object.
function presentDialog(parent, path, props = {}) { function presentDialog(parent, path, props = {}, singleInstance = false) {
// Open the dialog once the object is created // Open the dialog once the object is created
return viewManager.createUniqueView(path, parent, function (obj) { let createFunc = singleInstance ? viewManager.createView : viewManager.createUniqueView;
return createFunc(path, parent, function (obj) {
const doneCb = function () { const doneCb = function () {
viewManager.destroyView(path); viewManager.destroyView(path);
}; };

View file

@ -27,6 +27,14 @@ FileDialog {
signal fileAccepted(string file) signal fileAccepted(string file)
signal filesAccepted(var files) signal filesAccepted(var files)
Component.onCompleted: {
JamiQmlUtils.openFileDialogCount++;
}
Component.onDestruction: {
JamiQmlUtils.openFileDialogCount--;
}
onAccepted: { onAccepted: {
switch (fileMode) { switch (fileMode) {
case FileDialog.OpenFile: case FileDialog.OpenFile:

View file

@ -66,7 +66,6 @@ Rectangle {
messageBar.fileContainer.filesToSendListModel.addToPending(restoredContent["files"][i]); messageBar.fileContainer.filesToSendListModel.addToPending(restoredContent["files"][i]);
} }
} }
} }
Connections { Connections {
@ -203,7 +202,7 @@ Rectangle {
var dlg = viewCoordinator.presentDialog(appWindow, "commoncomponents/JamiFileDialog.qml", { var dlg = viewCoordinator.presentDialog(appWindow, "commoncomponents/JamiFileDialog.qml", {
"fileMode": JamiFileDialog.OpenFiles, "fileMode": JamiFileDialog.OpenFiles,
"nameFilters": [JamiStrings.allFiles] "nameFilters": [JamiStrings.allFiles]
}); }, true); // is a single instance
dlg.filesAccepted.connect(function (files) { dlg.filesAccepted.connect(function (files) {
setFilePathsToSend(files); setFilePathsToSend(files);
}); });

View file

@ -83,7 +83,8 @@ Item {
function onDonationCampaignSettingsChanged() { function onDonationCampaignSettingsChanged() {
// Changing any of the donation campaign settings will trigger a recompute // Changing any of the donation campaign settings will trigger a recompute
// of the banner visibility. // of the banner visibility.
updateIsDonationBannerVisible(); } updateIsDonationBannerVisible();
}
} }
function updateIsDonationBannerVisible() { function updateIsDonationBannerVisible() {
@ -99,4 +100,7 @@ Item {
const now = new Date(); const now = new Date();
return isVisible && now < endDate && now >= startDate; return isVisible && now < endDate && now >= startDate;
} }
// Track if a fileDialog is opened. Is int to account for eventual future features including multiple FileDialog
property int openFileDialogCount: 0
} }