mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 12:00:09 +02:00
✨ Improve multi-window handling
This commit is contained in:
@ -59,6 +59,8 @@
|
||||
C4AF9F7A2754499000D44ED0 /* Valet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F792754499000D44ED0 /* Valet.swift */; };
|
||||
C4AF9F7B2754499000D44ED0 /* Valet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F792754499000D44ED0 /* Valet.swift */; };
|
||||
C4AF9F7D275454A900D44ED0 /* ValetTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F7C275454A900D44ED0 /* ValetTest.swift */; };
|
||||
C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CCBA6B275C567B008C7055 /* PMWindowController.swift */; };
|
||||
C4CCBA6D275C567B008C7055 /* PMWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CCBA6B275C567B008C7055 /* PMWindowController.swift */; };
|
||||
C4D8016622B1584700C6DA1B /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.swift */; };
|
||||
C4EE188422D3386B00E126E5 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EE188322D3386B00E126E5 /* Constants.swift */; };
|
||||
C4F2E4372752F0870020E974 /* HomebrewDiagnostics.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F2E4362752F0870020E974 /* HomebrewDiagnostics.swift */; };
|
||||
@ -148,6 +150,7 @@
|
||||
C4AF9F76275447F100D44ED0 /* ValetConfigParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetConfigParserTest.swift; sourceTree = "<group>"; };
|
||||
C4AF9F792754499000D44ED0 /* Valet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Valet.swift; sourceTree = "<group>"; };
|
||||
C4AF9F7C275454A900D44ED0 /* ValetTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetTest.swift; sourceTree = "<group>"; };
|
||||
C4CCBA6B275C567B008C7055 /* PMWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PMWindowController.swift; sourceTree = "<group>"; };
|
||||
C4D8016522B1584700C6DA1B /* Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Startup.swift; sourceTree = "<group>"; };
|
||||
C4E713562570150F00007428 /* SECURITY.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = SECURITY.md; sourceTree = "<group>"; };
|
||||
C4E713572570151400007428 /* docs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = docs; sourceTree = "<group>"; };
|
||||
@ -305,6 +308,7 @@
|
||||
C476FF9722B0DD830098105B /* Alert.swift */,
|
||||
C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */,
|
||||
C474B00524C0E98C00066A22 /* LocalNotification.swift */,
|
||||
C4CCBA6B275C567B008C7055 /* PMWindowController.swift */,
|
||||
);
|
||||
path = Helpers;
|
||||
sourceTree = "<group>";
|
||||
@ -512,6 +516,7 @@
|
||||
C41C1B4D22B0215A00E7CF16 /* Actions.swift in Sources */,
|
||||
C48D0CA325CC992000CC7490 /* StatsView.swift in Sources */,
|
||||
C4F2E4372752F0870020E974 /* HomebrewDiagnostics.swift in Sources */,
|
||||
C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */,
|
||||
C41CD0292628D8EE0065BBED /* GlobalKeybindPreference.swift in Sources */,
|
||||
C42295DD2358D02000E263B2 /* Command.swift in Sources */,
|
||||
C4811D2422D70A4700B5F6B3 /* App.swift in Sources */,
|
||||
@ -551,6 +556,7 @@
|
||||
C4F780CA25D80B75000DBC97 /* HomebrewPackage.swift in Sources */,
|
||||
C4AF9F7B2754499000D44ED0 /* Valet.swift in Sources */,
|
||||
C4F780C025D80B6E000DBC97 /* Startup.swift in Sources */,
|
||||
C4CCBA6D275C567B008C7055 /* PMWindowController.swift in Sources */,
|
||||
C4F2E4382752F08D0020E974 /* HomebrewDiagnostics.swift in Sources */,
|
||||
C4F780AE25D80B37000DBC97 /* ExtensionParserTest.swift in Sources */,
|
||||
C4F780C725D80B75000DBC97 /* StatusMenu.swift in Sources */,
|
||||
|
@ -141,4 +141,41 @@ class App {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Application State
|
||||
|
||||
/**
|
||||
Keep track of open windows.
|
||||
When this list is updated, the app activation policy is re-evaluated.
|
||||
The app activation policy dictates how the app runs (as a normal app or as a toolbar app).
|
||||
*/
|
||||
var openWindows: [String] = []
|
||||
|
||||
/**
|
||||
Registers a window as currently open.
|
||||
*/
|
||||
public func register(window name: String) {
|
||||
if !openWindows.contains(name) {
|
||||
openWindows.append(name)
|
||||
}
|
||||
updateActivationPolicy()
|
||||
}
|
||||
|
||||
/**
|
||||
Removes a window, assuming it was closed.
|
||||
*/
|
||||
public func remove(window name: String) {
|
||||
openWindows.removeAll { window in
|
||||
window == name
|
||||
}
|
||||
updateActivationPolicy()
|
||||
}
|
||||
|
||||
/**
|
||||
If there are any open windows, the app will be a regular app.
|
||||
If there are no windows open, the app will be an accessory (toolbar) app.
|
||||
*/
|
||||
public func updateActivationPolicy() {
|
||||
NSApp.setActivationPolicy(openWindows.count > 0 ? .regular : .accessory)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -282,9 +282,9 @@
|
||||
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
|
||||
</connections>
|
||||
</application>
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="PHP_Monitor" customModuleProvider="target"/>
|
||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="PHP_Monitor" customModuleProvider="target"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-444" y="-1"/>
|
||||
</scene>
|
||||
@ -578,19 +578,19 @@ Gw
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<scrollView autohidesScrollers="YES" horizontalLineScroll="69" horizontalPageScroll="10" verticalLineScroll="69" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p0j-eB-I2i">
|
||||
<rect key="frame" x="0.0" y="0.0" width="550" height="344"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="550" height="337"/>
|
||||
<clipView key="contentView" id="6IL-DW-37w">
|
||||
<rect key="frame" x="1" y="1" width="548" height="342"/>
|
||||
<rect key="frame" x="1" y="1" width="548" height="335"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" autosaveColumns="NO" rowHeight="69" rowSizeStyle="automatic" viewBased="YES" id="cp3-34-pQj">
|
||||
<rect key="frame" x="0.0" y="0.0" width="548" height="342"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="548" height="335"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<size key="intercellSpacing" width="17" height="0.0"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn width="536" minWidth="40" maxWidth="1000" id="oeH-B2-0rA">
|
||||
<tableColumn width="536" minWidth="40" maxWidth="10000" id="oeH-B2-0rA">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
@ -656,7 +656,7 @@ Gw
|
||||
<rect key="frame" x="301" y="27" width="51" height="14"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="PHP 8.0" id="d9R-tV-Dlk">
|
||||
<font key="font" metaFont="system" size="11"/>
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
@ -712,7 +712,7 @@ Gw
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="550" id="iRQ-sz-oyv"/>
|
||||
</constraints>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="TDE-ff-DQT">
|
||||
<rect key="frame" x="1" y="356" width="527" height="15"/>
|
||||
<rect key="frame" x="1" y="328" width="548" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="wFn-93-f10">
|
||||
|
36
phpmon/Domain/Helpers/PMWindowController.swift
Normal file
36
phpmon/Domain/Helpers/PMWindowController.swift
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// PMWindowController.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 05/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
/**
|
||||
This window class keeps track of which windows are currently visible, and reports this info back to the App class.
|
||||
For more information, check the `windows` property on `App`.
|
||||
|
||||
- Note: This class does make a simple assumption: each window controller corresponds to a single view.
|
||||
*/
|
||||
class PMWindowController: NSWindowController, NSWindowDelegate {
|
||||
|
||||
public var windowName: String {
|
||||
fatalError("Please specify a window name")
|
||||
}
|
||||
|
||||
override func showWindow(_ sender: Any?) {
|
||||
super.showWindow(sender)
|
||||
App.shared.register(window: self.windowName)
|
||||
}
|
||||
|
||||
func windowWillClose(_ notification: Notification) {
|
||||
App.shared.remove(window: self.windowName)
|
||||
}
|
||||
|
||||
deinit {
|
||||
print("Window controller '\(windowName)' was deinitialized")
|
||||
}
|
||||
|
||||
}
|
@ -12,6 +12,8 @@ import Carbon
|
||||
|
||||
class PrefsVC: NSViewController {
|
||||
|
||||
// MARK: - Window Identifier
|
||||
|
||||
// Labels on the left
|
||||
@IBOutlet weak var leftLabelDynamicIcon: NSTextField!
|
||||
@IBOutlet weak var leftLabelServices: NSTextField!
|
||||
@ -39,17 +41,24 @@ class PrefsVC: NSViewController {
|
||||
|
||||
// MARK: - Display
|
||||
|
||||
public static func create(delegate: NSWindowDelegate?) {
|
||||
let storyboard = NSStoryboard(name: "Main" , bundle : nil)
|
||||
|
||||
let windowController = storyboard.instantiateController(
|
||||
withIdentifier: "preferencesWindow"
|
||||
) as! PrefsWC
|
||||
|
||||
windowController.window!.title = "prefs.title".localized
|
||||
windowController.window!.delegate = delegate
|
||||
windowController.window!.styleMask = [.titled, .closable, .miniaturizable]
|
||||
windowController.window!.delegate = windowController
|
||||
|
||||
App.shared.preferencesWindowController = windowController
|
||||
}
|
||||
|
||||
public static func show(delegate: NSWindowDelegate? = nil) {
|
||||
if (App.shared.preferencesWindowController == nil) {
|
||||
let vc = NSStoryboard(name: "Main", bundle: nil)
|
||||
.instantiateController(withIdentifier: "preferences") as! PrefsVC
|
||||
let window = NSWindow(contentViewController: vc)
|
||||
|
||||
window.title = "prefs.title".localized
|
||||
window.delegate = delegate
|
||||
window.styleMask = [.titled, .closable]
|
||||
|
||||
App.shared.preferencesWindowController = PrefsWC(window: window)
|
||||
Self.create(delegate: delegate)
|
||||
}
|
||||
|
||||
App.shared.preferencesWindowController!.showWindow(self)
|
||||
|
@ -13,12 +13,22 @@ struct Keys {
|
||||
static let Space = 49
|
||||
}
|
||||
|
||||
class PrefsWC: NSWindowController {
|
||||
class PrefsWC: PMWindowController {
|
||||
|
||||
// MARK: - Window Identifier
|
||||
|
||||
override var windowName: String {
|
||||
return "Preferences"
|
||||
}
|
||||
|
||||
// MARK: - Window Lifecycle
|
||||
|
||||
override func windowDidLoad() {
|
||||
super.windowDidLoad()
|
||||
}
|
||||
|
||||
// MARK: - Key Interaction
|
||||
|
||||
override func keyDown(with event: NSEvent) {
|
||||
super.keyDown(with: event)
|
||||
|
||||
|
@ -16,27 +16,36 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
|
||||
@IBOutlet weak var tableView: NSTableView!
|
||||
|
||||
public var editorAvailability: [String] = []
|
||||
|
||||
public var sites: [Valet.Site] = []
|
||||
// MARK: - Variables
|
||||
|
||||
var sites: [Valet.Site] = []
|
||||
var editorAvailability: [String] = []
|
||||
var lastSearchedFor = ""
|
||||
|
||||
// MARK: - Display
|
||||
|
||||
public static func create(delegate: NSWindowDelegate?) {
|
||||
let storyboard = NSStoryboard(name: "Main" , bundle : nil)
|
||||
|
||||
let windowController = storyboard.instantiateController(
|
||||
withIdentifier: "siteListWindow"
|
||||
) as! SiteListWC
|
||||
|
||||
windowController.window!.title = "site_list.title".localized
|
||||
windowController.window!.subtitle = "site_list.subtitle".localized
|
||||
windowController.window!.delegate = delegate
|
||||
windowController.window!.styleMask = [
|
||||
.titled, .closable, .resizable, .miniaturizable
|
||||
]
|
||||
windowController.window!.minSize = NSSize(width: 550, height: 200)
|
||||
windowController.window!.delegate = windowController
|
||||
|
||||
App.shared.siteListWindowController = windowController
|
||||
}
|
||||
|
||||
public static func show(delegate: NSWindowDelegate? = nil) {
|
||||
if (App.shared.siteListWindowController == nil) {
|
||||
let storyboard = NSStoryboard(name: "Main" , bundle : nil)
|
||||
let windowController = (storyboard.instantiateController(withIdentifier: "siteListWindow")) as! SiteListWC
|
||||
|
||||
windowController.window!.title = "site_list.title".localized
|
||||
windowController.window!.subtitle = "site_list.subtitle".localized
|
||||
windowController.window!.delegate = delegate
|
||||
windowController.window!.styleMask = [.titled, .closable, .resizable]
|
||||
windowController.window!.minSize = NSSize(width: 550, height: 200)
|
||||
windowController.window!.maxSize = NSSize(width: 800, height: 10000)
|
||||
|
||||
App.shared.siteListWindowController = windowController
|
||||
Self.create(delegate: delegate)
|
||||
}
|
||||
|
||||
App.shared.siteListWindowController!.showWindow(self)
|
||||
@ -57,9 +66,7 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
self.sites = Valet.shared.sites
|
||||
}
|
||||
|
||||
override func viewWillAppear() {}
|
||||
|
||||
override func viewWillDisappear() {}
|
||||
|
||||
|
||||
// MARK: - Site Data Loading
|
||||
|
||||
|
@ -8,16 +8,28 @@
|
||||
|
||||
import Cocoa
|
||||
|
||||
class SiteListWC: NSWindowController, NSSearchFieldDelegate, NSToolbarDelegate {
|
||||
class SiteListWC: PMWindowController, NSSearchFieldDelegate, NSToolbarDelegate {
|
||||
|
||||
// MARK: - Window Identifier
|
||||
|
||||
override var windowName: String {
|
||||
return "SiteList"
|
||||
}
|
||||
|
||||
// MARK: - Outlets
|
||||
|
||||
@IBOutlet weak var searchToolbarItem: NSSearchToolbarItem!
|
||||
|
||||
// MARK: - Window Lifecycle
|
||||
|
||||
override func windowDidLoad() {
|
||||
super.windowDidLoad()
|
||||
self.searchToolbarItem.searchField.delegate = self
|
||||
self.searchToolbarItem.searchField.becomeFirstResponder()
|
||||
}
|
||||
|
||||
// MARK: - Search functionality
|
||||
|
||||
var contentVC: SiteListVC {
|
||||
return self.contentViewController as! SiteListVC
|
||||
}
|
||||
@ -31,6 +43,8 @@ class SiteListWC: NSWindowController, NSSearchFieldDelegate, NSToolbarDelegate {
|
||||
contentVC.searchedFor(text: searchField.stringValue)
|
||||
}
|
||||
|
||||
// MARK: - Reload functionality
|
||||
|
||||
@IBAction func pressedReload(_ sender: Any) {
|
||||
contentVC.reloadSites()
|
||||
}
|
||||
|
Reference in New Issue
Block a user