/* DING: Desktop Icons New Generation for GNOME Shell * * Gtk4 Port Copyright (C) 2023 Sundeep Mediratta (smedius@gmail.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import {Gtk, Gdk, Gio, Adw} from '../dependencies/gi.js'; import {_} from '../dependencies/gettext.js'; export {AppChooserDialog}; const AppChooserDialog = class { constructor(fileItems, activeFileItem = null, dbusUtils, desktopIconsUtil) { if (!activeFileItem) activeFileItem = fileItems[0]; if (fileItems.length === 1) { this.fileName = activeFileItem.displayName; this.singleContentType = true; } else { this.fileName = null; this.singleContentType = this._detectSingleContentType(fileItems); } this._dbusUtils = dbusUtils; this._desktopIconsUtil = desktopIconsUtil; this.mimeType = activeFileItem.attributeContentType; this.mimeTypeIsDirectory = this.mimeType === 'inode/directory'; const appwindow = this._desktopIconsUtil.getMainApp().get_active_window(); this.builderObject = Gtk.Builder .new_from_resource('/com/desktop/ding/ui/ding-app-chooser.ui'); this.builderObject.set_translation_domain('gtk4-ding'); this.appChooserDialog = this.builderObject.get_object('DingAppChooser'); this.appChooserDialog.set_transient_for(appwindow); this.appChooserDialog.set_title('DingAppChooser'); this.appChooserDialog.set_name('DingAppChooser'); const modal = true; this._desktopIconsUtil .windowHidePagerTaskbarModal(this.appChooserDialog, modal); this.appChooserBox = this.builderObject.get_object('app_chooser_widget_box'); this.appChooserBox.set_hexpand(true); this.appChooserBox.set_halign(Gtk.Align.FILL); this.appChooserWidget = Gtk.AppChooserWidget.new(this.mimeType); this.appChooserWidget.set_show_default(true); this.appChooserWidget.set_show_fallback(true); this.appChooserWidget.set_show_other(true); this.appChooserBox.append(this.appChooserWidget); this.appChooserWidget.set_vexpand(true); this.appChooserWidget.set_halign(Gtk.Align.FILL); this.appChooserWidget.set_hexpand(true); if (this.fileName !== null) { const description = _('Choose an application to open {foo}') .replace('{foo}', this.fileName.replaceAll('&', '&')); this.appChooserLabel = this.builderObject.get_object('label_description'); this.appChooserLabel.set_markup(description); } let headerTitle; if (!this.singleContentType) headerTitle = _('Open Items'); else if (this.mimeTypeIsDirectory) headerTitle = _('Open Folder'); else headerTitle = _('Open File'); this.appChooserDialogHeaderBar = this.appChooserDialog.get_header_bar(); this.appChooserDialogHeaderBar .set_title_widget(Adw.WindowTitle.new(headerTitle, '')); this.appChooserRowBox = this.builderObject.get_object('set_default_box'); this.appChooserRow = this.builderObject.get_object('set_default_row'); this.appChooserRowSwitch = this.builderObject.get_object('set_as_default_switch'); this.selectedAppInfo = this.appChooserWidget.get_app_info(); if (this.selectedAppInfo !== null) { this._onApplicationSelected( this.appChooserWidget, this.selectedAppInfo ); } this.appChooserWidget.connect( 'application-activated', this._onApplicationActivated.bind(this) ); this.appChooserWidget.connect( 'application-selected', this._onApplicationSelected.bind(this) ); if (this.singleContentType && !this.mimeTypeIsDirectory) { let description = Gio.content_type_get_description(this.mimeType); this.appChooserRow.set_subtitle(description); } else { this.appChooserRowBox.set_visible(false); } this.appChooserDialog.connect('close', () => { this.appChooserDialog.response(Gtk.ResponseType.CANCEL); }); this.appChooserDialog.connect('response', (actor, retval) => { if (retval === Gtk.ResponseType.OK) { this._checkUpdateDefaultAppForMimeType(); this.applicationSelectionComplete(this.selectedAppInfo); } else { this.applicationSelectionComplete(null); } }); } _checkUpdateDefaultAppForMimeType() { if (!this.singleContentType) return; let newAppSelected = false; if (this.appChooserRowSwitch.get_sensitive()) newAppSelected = this.appChooserRowSwitch.get_active(); if (newAppSelected) { let success = this.selectedAppInfo.set_as_default_for_type(this.mimeType); if (!success) { let header = _('Error changing default application'); let message = _('Error while setting {foo} as default application for {mimetype}'); message = message.replace( '{foo}', this.selectedAppInfo.get_display_name() ); message = message .replace( '{mimetype}', Gio.content_type_get_description(this.mimeType) ); this._dbusUtils.doNotify(header, message); } } } _onApplicationActivated(actor, appInfo) { this.selectedAppInfo = appInfo; this.appChooserDialog.response(Gtk.ResponseType.OK); } _onApplicationSelected(actor, appInfo) { if (!this.appChooserDialog) return; this.selectedAppInfo = appInfo; this.appChooserDialog .set_response_sensitive( Gtk.ResponseType.OK, this.selectedAppInfo !== null ); let defaultAppInfo = Gio.AppInfo.get_default_for_type(this.mimeType, false); let defaultSelected = false; if (defaultAppInfo) defaultSelected = defaultAppInfo.equal(this.selectedAppInfo); this.appChooserRowSwitch.set_state(defaultSelected); this.appChooserRowSwitch.set_sensitive(!defaultSelected); } _detectSingleContentType(fileItems) { let mimetype = fileItems[0].attributeContentType; for (let fileItem of fileItems) { if (fileItem.attributeContentType !== mimetype) return false; } return true; } show() { this.appChooserDialog.show(); this.appChooserDialog.present_with_time(Gdk.CURRENT_TIME); } hide() { this.appChooserDialog.hide(); } finalize() { this.appChooserDialog.destroy(); this.appChooserDialog = null; this.builderObject = null; } getApplicationSelected() { return new Promise(resolve => { this.applicationSelectionComplete = resolve; }); } };