Add support for showing pgAdmin shortcuts on Electron menus. #1923
parent
6dc5807192
commit
bec47845be
|
|
@ -10,6 +10,7 @@
|
|||
import { app, ipcMain, dialog, BrowserWindow, shell } from 'electron';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import Buffer from 'buffer';
|
||||
import { setBadge, clearBadge, clearProgress, setProgress } from './progress.js';
|
||||
import { writeServerLog } from './misc.js';
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,28 @@
|
|||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import { app, Menu, ipcMain, BrowserWindow } from 'electron';
|
||||
import { app, Menu, ipcMain, BrowserWindow, globalShortcut } from 'electron';
|
||||
|
||||
const isMac = process.platform == 'darwin';
|
||||
const isLinux = process.platform == 'linux';
|
||||
let mainMenu;
|
||||
|
||||
// Use to convert shortcut to accelerator for electron.
|
||||
function convertShortcutToAccelerator({ control, meta, shift, alt, key } = {}) {
|
||||
// Store active modifier keys into an array.
|
||||
const mods = [
|
||||
control && 'Ctrl',
|
||||
meta && 'Cmd',
|
||||
shift && 'Shift',
|
||||
alt && 'Alt',
|
||||
].filter(Boolean); // Remove any falsy values
|
||||
// Get the actual key character and convert to uppercase.
|
||||
const k = key?.char?.toUpperCase();
|
||||
if (!k) return;
|
||||
// Combine modifiers and key into a single string.
|
||||
return [...mods, k].join('+');
|
||||
}
|
||||
|
||||
function buildMenu(pgadminMenus, pgAdminMainScreen, callbacks) {
|
||||
const template = [];
|
||||
|
||||
|
|
@ -24,13 +40,27 @@ function buildMenu(pgadminMenus, pgAdminMainScreen, callbacks) {
|
|||
const smName = `${menuItem.name}_${subMenuItem.name}`;
|
||||
return {
|
||||
...subMenuItem,
|
||||
click: ()=>{
|
||||
accelerator: convertShortcutToAccelerator(subMenuItem.shortcut),
|
||||
click: (_menuItem, _browserWindow, event)=>{
|
||||
if(event?.triggeredByAccelerator) {
|
||||
// We will ignore the click event if it is triggered by an accelerator.
|
||||
// We use accelerator to only show the shortcut title in the menu.
|
||||
// The actual shortcut is already handled by pgAdmin.
|
||||
return;
|
||||
}
|
||||
pgAdminMainScreen.webContents.send('menu-click', smName);
|
||||
},
|
||||
submenu: subMenuItem.submenu?.map((deeperSubMenuItem)=>{
|
||||
return {
|
||||
...deeperSubMenuItem,
|
||||
click: ()=>{
|
||||
accelerator: convertShortcutToAccelerator(deeperSubMenuItem.shortcut),
|
||||
click: (_menuItem, _browserWindow, event)=>{
|
||||
if(event?.triggeredByAccelerator) {
|
||||
// We will ignore the click event if it is triggered by an accelerator.
|
||||
// We use accelerator to only show the shortcut title in the menu.
|
||||
// The actual shortcut is already handled by pgAdmin.
|
||||
return;
|
||||
}
|
||||
pgAdminMainScreen.webContents.send('menu-click', `${smName}_${deeperSubMenuItem.name}`);
|
||||
},
|
||||
};
|
||||
|
|
@ -109,6 +139,9 @@ function buildMenu(pgadminMenus, pgAdminMainScreen, callbacks) {
|
|||
export function setupMenu(pgAdminMainScreen, callbacks={}) {
|
||||
ipcMain.on('setMenus', (event, menus)=>{
|
||||
mainMenu = buildMenu(menus, pgAdminMainScreen, callbacks);
|
||||
// this is important because the shortcuts are registered multiple times
|
||||
// when the menu is set multiple times using accelerators.
|
||||
globalShortcut.unregisterAll();
|
||||
if(isMac) {
|
||||
Menu.setApplicationMenu(mainMenu);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ ipcMain.on('log', (_e, text) => ()=>{
|
|||
});
|
||||
ipcMain.on('focus', (e) => {
|
||||
app.focus({steal: true});
|
||||
const callerWindow = BrowserWindow.fromWebContents(e.sender)
|
||||
const callerWindow = BrowserWindow.fromWebContents(e.sender);
|
||||
if (callerWindow) {
|
||||
if (callerWindow.isMinimized()) callerWindow.restore();
|
||||
callerWindow.focus();
|
||||
|
|
|
|||
|
|
@ -31,5 +31,5 @@ contextBridge.exposeInMainWorld('electronUI', {
|
|||
downloadStreamSaveTotal: (...args) => ipcRenderer.send('download-stream-save-total', ...args),
|
||||
downloadStreamSaveEnd: (...args) => ipcRenderer.send('download-stream-save-end', ...args),
|
||||
downloadBase64UrlData: (...args) => ipcRenderer.invoke('download-base64-url-data', ...args),
|
||||
downloadTextData: (...args) => ipcRenderer.invoke('download-text-data', ...args)
|
||||
downloadTextData: (...args) => ipcRenderer.invoke('download-text-data', ...args),
|
||||
});
|
||||
|
|
@ -46,6 +46,12 @@ export default class MainMenuFactory {
|
|||
});
|
||||
}
|
||||
|
||||
static listenToElectronMenuClick() {
|
||||
window.electronUI?.onMenuClick((menuName)=>{
|
||||
MainMenuFactory.electronCallbacks[menuName]?.();
|
||||
});
|
||||
}
|
||||
|
||||
static createMainMenus() {
|
||||
pgAdmin.Browser.MainMenus = [];
|
||||
MAIN_MENUS.forEach((_menu) => {
|
||||
|
|
@ -61,10 +67,6 @@ export default class MainMenuFactory {
|
|||
// enable disable will take care of dynamic menus.
|
||||
MainMenuFactory.enableDisableMenus();
|
||||
|
||||
window.electronUI?.onMenuClick((menuName)=>{
|
||||
MainMenuFactory.electronCallbacks[menuName]?.();
|
||||
});
|
||||
|
||||
window.electronUI?.setMenus(MainMenuFactory.toElectron());
|
||||
}
|
||||
|
||||
|
|
@ -117,6 +119,7 @@ export default class MainMenuFactory {
|
|||
};
|
||||
let allMenus = pgAdmin.Browser?.all_menus_cache || {};
|
||||
Object.values(allMenus).forEach(updateShortcuts);
|
||||
MainMenuFactory.createMainMenus();
|
||||
};
|
||||
|
||||
// Assign and Update menu shortcuts using preference.
|
||||
|
|
|
|||
|
|
@ -375,6 +375,7 @@ define('pgadmin.browser', [
|
|||
_m.callback = () => {
|
||||
showQuickSearch();
|
||||
};
|
||||
_m.shortcut_preference =['browser', 'open_quick_search'];
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@ define('app', [
|
|||
// Create menus after all modules are initialized.
|
||||
MainMenuFactory.createMainMenus();
|
||||
|
||||
// Listen to menu click events and callback pgAdmin js code.
|
||||
// This will be internally ignored if not running in electron.
|
||||
MainMenuFactory.listenToElectronMenuClick();
|
||||
|
||||
const root = ReactDOM.createRoot(document.querySelector('#root'));
|
||||
root.render(
|
||||
<Theme>
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ export const PgMenuItem = (({hasCheck=false, checked=false, accesskey, shortcut,
|
|||
<Box
|
||||
sx={{
|
||||
marginLeft: 'auto',
|
||||
fontSize: '0.8em',
|
||||
paddingLeft: '12px',
|
||||
display: 'flex',
|
||||
gap: '1px',
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ export class MenuItem {
|
|||
priority: this.priority,
|
||||
type: [true, false].includes(this.checked) ? 'checkbox' : this.type,
|
||||
checked: this.checked,
|
||||
shortcut: this.shortcut,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue