WhereIsMyMac
============

* :download:`Download example <PyObjCExample-WhereIsMyMac.zip>`

This example shows how to use the CoreLocation
framework and is a translation in Python
of the example at `"Cocoa with Love"`__

.. __: https://www.cocoawithlove.com/2009/09/whereismymac-snow-leopard-corelocation.html


.. rst-class:: tabber

Sources
-------

.. rst-class:: tabbertab

WhereIsMyMacAppDelegate.py
..........................

.. sourcecode:: python

    """
    This file is a translation from Objective-C. The original
    copy-right:
    
    //  Copyright 2009 Matt Gallagher. All rights reserved.
    //
    //  Permission is given to use this source code file, free of charge, in any
    //  project, commercial or otherwise, entirely at your risk, with the condition
    //  that any redistribution (in part or whole) of source code must retain
    //  this copyright and permission notice. Attribution in compiled projects is
    //  appreciated but not required.
    """
    
    import math
    
    import Cocoa
    import WebKit  # noqa: F401
    import CoreLocation
    import objc
    
    
    class WhereIsMyMacAppDelegate(Cocoa.NSObject):
        window = objc.ivar()
        webView = objc.IBOutlet()
        locationManager = objc.ivar()
        locationLabel = objc.IBOutlet()
        accuracyLabel = objc.IBOutlet()
    
        def applicationDidFinishLaunching_(self, notification):
            self.locationManager = CoreLocation.CLLocationManager.alloc().init()
            self.locationManager.setDelegate_(self)
            self.locationManager.startUpdatingLocation()
    
        @classmethod
        def latitudeRangeForLocation_(self, location):
            M = 6_367_000.0
            # approximate average meridional radius of curvature of earth
            metersToLatitude = 1.0 / ((math.pi / 180.0) * M)
            accuracyToWindowScale = 2.0
    
            return location.horizontalAccuracy() * metersToLatitude * accuracyToWindowScale
    
        @classmethod
        def longitudeRangeForLocation_(self, location):
            latitudeRange = WhereIsMyMacAppDelegate.latitudeRangeForLocation_(location)
    
            return latitudeRange * math.cos(
                location.coordinate().latitude * math.pi / 180.0
            )
    
        @objc.IBAction
        def openInDefaultBrowser_(self, sender):
            currentLocation = self.locationManager.location()
    
            externalBrowserURL = Cocoa.NSURL.URLWithString_(
                "http://maps.google.com/maps?ll=%f,%f&amp;spn=%f,%f"
                % (
                    currentLocation.coordinate().latitude,
                    currentLocation.coordinate().longitude,
                    WhereIsMyMacAppDelegate.latitudeRangeForLocation_(currentLocation),
                    WhereIsMyMacAppDelegate.longitudeRangeForLocation_(currentLocation),
                )
            )
    
            Cocoa.NSWorkspace.sharedWorkspace().openURL_(externalBrowserURL)
    
        def locationManager_didUpdateToLocation_fromLocation_(
            self, manager, newLocation, oldLocation
        ):
            # Ignore updates where nothing we care about changed
            if newLocation is None:
                return
            if oldLocation is None:
                pass
            elif (
                newLocation.coordinate().longitude == oldLocation.coordinate().longitude
                and newLocation.coordinate().latitude == oldLocation.coordinate().latitude
                and newLocation.horizontalAccuracy() == oldLocation.horizontalAccuracy()
            ):
                return
    
            # Load the HTML for displaying the Google map from a file and replace the
            # format placeholders with our location data
            path = Cocoa.NSBundle.mainBundle().pathForResource_ofType_(
                "HTMLFormatString", "html"
            )
            with open(path) as fp:
                htmlString = fp.read() % (
                    newLocation.coordinate().latitude,
                    newLocation.coordinate().longitude,
                    WhereIsMyMacAppDelegate.latitudeRangeForLocation_(newLocation),
                    WhereIsMyMacAppDelegate.longitudeRangeForLocation_(newLocation),
                )
    
            # Load the HTML in the WebView and set the labels
            self.webView.mainFrame().loadHTMLString_baseURL_(htmlString, None)
            self.locationLabel.setStringValue_(
                "%f, %f"
                % (newLocation.coordinate().latitude, newLocation.coordinate().longitude)
            )
            self.accuracyLabel.setStringValue_(f"{newLocation.horizontalAccuracy():f}")
    
        def locationManager_didFailWithError_(self, manager, error):
            self.webView.mainFrame.loadHTMLString_baseURL_(
                Cocoa.NSLocalizedString("Location manager failed with error: %s", objc.nil)
                % (error.localizedDescription()),
                None,
            )
            self.locationLabel.setStringValue_("")
            self.accuracyLabel.setStringValue_("")
    
        def applicationWillTerminate_(self, aNotification):
            self.locationManager.stopUpdatingLocation()

.. rst-class:: tabbertab

main.py
.......

.. sourcecode:: python

    import WhereIsMyMacAppDelegate  # noqa: F401
    from PyObjCTools import AppHelper
    
    AppHelper.runEventLoop()

.. rst-class:: tabbertab

setup.py
........

.. sourcecode:: python

    """
    Script for building the example.
    
    Usage:
        python3 setup.py py2app
    """
    from setuptools import setup
    
    setup(
        name="WhereIsMyMac",
        app=["main.py"],
        data_files=["English.lproj", "HTMLFormatString.html"],
        setup_requires=[
            "py2app",
            "pyobjc-framework-Cocoa",
            "pyobjc-framework-CoreLocation",
        ],
    )

