Tuesday, August 20, 2019

#1 2013-03-07 10:57:06 pm

simpletireman
Member
Registered: 2013-02-08
Posts: 31

Activity Indicator - Similar to Domain or Network Status LED/Orb

I'm back again...

I am attempting to program a status indicator similar to that of the Domain (Network Account Server) or Network connectivity status LED light (green/yellow/red, sometimes referred to as the 'jelly'). I would like to attempt this on my own, but I cannot find where in the documentation it exists. I would like to use this functionality to tell users of my application that a file path (my application references other software that must be installed) exists on the machine. This indicator will let the user know it is okay to proceed with specific functions of the application (green), or that installation or troubleshooting should be attempted (red).

Does anyone know where to find this type of indicator as either a class or subclass, potentially even a method. Bonus points would be if I can also use the dialog popup from the >10.7 loginwindow that indicates that network accounts are unavailable. Is there any way for me to find this item specifically, i.e., some (unknown to me) database that matches classes that contain GUI items to their class names?

Thanks in advance for any insight. Even the correct terminology would be helpful so I can attempt to find a starting place for this functionality.


Filed under: status, Indicator, Activity, LED

Offline

 

#2 2013-03-07 11:32:38 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5825

Re: Activity Indicator - Similar to Domain or Network Status LED/Orb

They're not separate classes -- they're just images added to buttons or image wells. To change appearance, you change the image. Have a look in the Resources folder of something like Airport Utility.app to get an idea of what to use.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Online

 

#3 2013-03-08 12:02:23 am

StefanK
Member
From:: St. Gallen, Switzerland
Registered: 2006-10-21
Posts: 11578
Website

Re: Activity Indicator - Similar to Domain or Network Status LED/Orb

Hi,

short example, the variable statusImage is a NSImageView outlet (16 x 16 borderless)
Call the handler with values -1 (not available), 0 (partially available) or 1 (available)

Applescript:


on setImageForStatus_(status)
   if status = 1 then
       set imageName to current application's NSImageNameStatusAvailable
   else if status = 0 then
       set imageName to current application's NSImageNameStatusPartiallyAvailable
   else
       set imageName to current application's NSImageNameStatusUnavailable
   end if
   
   statusImage's setImage_(current application's NSImage's imageNamed_(imageName))
end setImageForStatus_


regards

Stefan

Offline

 

#4 2013-03-08 01:15:28 am

simpletireman
Member
Registered: 2013-02-08
Posts: 31

Re: Activity Indicator - Similar to Domain or Network Status LED/Orb

Shane Stanley wrote:

They're not separate classes -- they're just images added to buttons or image wells. To change appearance, you change the image. Have a look in the Resources folder of something like Airport Utility.app to get an idea of what to use.


I had been looking at NSImageView for changing an image based on whether or not the file/folder path existed, so it seems I was on the right track. I originally got the idea from the tableview example in your book regarding multiple columns. I'll re-read the section as I go to see what I can use. Thanks Shane. One more way your book has helped me immensely.

Hi,

short example, the variable statusImage is a NSImageView outlet (16 x 16 borderless)
Call the handler with values -1 (not available), 0 (partially available) or 1 (available)


Stefan's example helps me tremendously, and it looks like I was on the right path. I plan to add this as a repeating (read, background) task in the application, upon launch. You guys are awesome! I'll work on my code tomorrow and post back with what I come up with for critiquing and documentation.

Offline

 

#5 2013-03-10 12:39:17 pm

simpletireman
Member
Registered: 2013-02-08
Posts: 31

Re: Activity Indicator - Similar to Domain or Network Status LED/Orb

Ok guys, spent a little time on this...I think I have found the best way to check for each file's status, now I am just wondering the best way to call the sender Stefan posted. Below is my current code for searching for each log file's presence in the file system:

Applescript:


on applicationWillFinishLaunching_(aNotification)
-- Set First Log File Variable and Timer
set manager to current application's NSFileManager's defaultManager()
set fileOne to "/Library/company/folder/place/subplace/log" as string
current application's NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(30, me, "checkFileOne:", missing value, 1)

--Set Second Log File Variable and Timerr
set manager to current application's NSFileManager's defaultManager()
set fileTwo to "/Library/Logs/somefile.log" as string
current application's NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(30, me, "checkFileTwo:", missing value, 1)

-- Check for first log file's existence in the file system
on checkFileOne_(sender)
set var1 to manager's fileExistsAtPath_(fileOne)
if var1 as integer = 1 then
log "First Log File found"
set fileOneStatus to 1
sender's invalidate()
else
log "No Log File Found"
set fileOneStatus to 0
end if
end checkFileOne_

-- Check for second log file's existence in the file system
on checkFileTwo_(sender)
set var1 to manager's fileExistsAtPath_(encFile)
if var1 as integer = 1 then
log "2nd Log File found"
set fileTwoStatus to 1
sender's invalidate() -- this stops the timer
else
log "No #2 Log File Found"
set fileTwoStatus to 0
end if
end checkFileTwo_
end applicationWillFinishLaunching_

I think that it is better for my application's function to break each file exists check up for each file. That being said, I will probably have 2 of stefan's suggested code to set the image, one for each file. What is the best way to call that from the checkFileOne and checkFileTwo for each file? It would need to be called whether the file is present or not, so as to set the icon to available or not available indication.

Last edited by simpletireman (2013-03-10 12:40:57 pm)

Offline

 

#6 2013-03-10 12:48:14 pm

StefanK
Member
From:: St. Gallen, Switzerland
Registered: 2006-10-21
Posts: 11578
Website

Re: Activity Indicator - Similar to Domain or Network Status LED/Orb

you could also pass the reference to the image view (the name of the property) in the handler

Applescript:


on setImageOfImageView_forStatus_(imageView, status)
   if status = 1 then
       set imageName to current application's NSImageNameStatusAvailable
   else if status = 0 then
       set imageName to current application's NSImageNameStatusPartiallyAvailable
   else
       set imageName to current application's NSImageNameStatusUnavailable
   end if
   
   imageView's setImage_(current application's NSImage's imageNamed_(imageName))
end setImageOfImageView_forStatus_


regards

Stefan

Offline

 

#7 2013-03-10 01:07:03 pm

simpletireman
Member
Registered: 2013-02-08
Posts: 31

Re: Activity Indicator - Similar to Domain or Network Status LED/Orb

Thanks Stefan,

If I leave these:

Applescript:

-- Check for first log file's existence in the file system
on checkFileOne_(sender)
set var1 to manager's fileExistsAtPath_(fileOne)
if var1 as integer = 1 then
log "First Log File found"
set fileOneStatus to 1
sender's invalidate()
else
log "No Log File Found"
set fileOneStatus to 0
end if
end checkFileOne_

-- Check for second log file's existence in the file system
on checkFileTwo_(sender)
set var1 to manager's fileExistsAtPath_(encFile)
if var1 as integer = 1 then
log "2nd Log File found"
set fileTwoStatus to 1
sender's invalidate() -- this stops the timer
else
log "No #2 Log File Found"
set fileTwoStatus to 0
end if
end checkFileTwo_
end applicationWillFinishLaunching_

under on applicationWillFinishLaunching_(aNotification), I get an error:

error: Expected “end” but found “on”. (-2741)


So I move them to another location in my applescript file, just under the property declarations, and this allows the build to succeed. I know it shouldn't matter where in the script things reside as long as they are being called correctly, but what is a good way to troubleshoot that they are being called? I can set logs in all the right places, I'm just wondering if that is the best way to show something is being called.

I just set the logs and the checks are not being called by the timers. I'm trying to troubleshoot to see why.

Last edited by simpletireman (2013-03-10 01:10:01 pm)

Offline

 

#8 2013-03-10 01:16:43 pm

StefanK
Member
From:: St. Gallen, Switzerland
Registered: 2006-10-21
Posts: 11578
Website

Re: Activity Indicator - Similar to Domain or Network Status LED/Orb

where is on applicationWillFinishLaunching_() ??

you cannot nest handlers, handlers must be always on the top level of the script object

Applescript:


on applicationWillFinishLaunching_()
   --    
end applicationWillFinishLaunching_

on checkFileOne_(sender)
   --
end checkFileOne_

-- Check for second log file's existence in the file system
on checkFileTwo_(sender)
   --
end checkFileTwo_


regards

Stefan

Offline

 

#9 2013-03-10 10:43:05 pm

simpletireman
Member
Registered: 2013-02-08
Posts: 31

Re: Activity Indicator - Similar to Domain or Network Status LED/Orb

StefanK wrote:

where is on applicationWillFinishLaunching_() ??

you cannot nest handlers, handlers must be always on the top level of the script object

Applescript:


on applicationWillFinishLaunching_()
   --    
end applicationWillFinishLaunching_

on checkFileOne_(sender)
   --
end checkFileOne_

-- Check for second log file's existence in the file system
on checkFileTwo_(sender)
   --
end checkFileTwo_


Sorry Stefan, it escaped my copy/paste I believe. I think I have a pretty good solution in the code below, what do you think? I have only posted below what I have applied to one log file, for the second, the code is duplicated, and variables and handlers are changed accordingly.

Applescript:


on applicationWillFinishLaunching_(aNotification)
-- Set Log Files as variables for checkFiles repeated task below
set logOneManager to current application's NSFileManager's defaultManager()
set logOneFile to "/Library/company/folder/subfolder/place/file" as string
current application's NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(300, me, "checkLogOne:", missing value, 1)

checkLogOne(me)
end applicationWillFinishLaunching_

on checkLogOne_(sender)
log "Performing 5 minute First Log File Check"
set var1 to logOneManager's fileExistsAtPath_(logOneFile)
if var1 as integer = 1 then
log "First Log File found"
set logOneStatus to 1
else
log "First Log File Not Found"
set logOneStatus to 0
end if
if logOneStatus = 1 then
set imageName to current application's NSImageNameStatusAvailable
else if logOneStatus = 0 then
set imageName to current application's NSImageNameStatusUnavailable
else
set imageName to current application's NSImageNameStatusPartiallyAvailable
end if
logOneOrb's setImage_(current application's NSImage's imageNamed_(imageName))
end checkLogOne_

The above code gets me a repeating task every 300 seconds (5 minutes) to check the status of the Log File and display the indicator accordingly. It does not, however, run at startup. To get around that, I called the handler at the end of the application launch with checkLogOne(me), and it runs every 300 seconds afterwards. As I mentioned above, I duplicate the code for the 2nd log file, and change the variables and handlers accordingly (ie., logTwoStatus, checkLogTwo, etc.

Last edited by simpletireman (2013-03-11 07:45:08 am)

Offline

 

#10 2013-03-11 04:05:32 am

StefanK
Member
From:: St. Gallen, Switzerland
Registered: 2006-10-21
Posts: 11578
Website

Re: Activity Indicator - Similar to Domain or Network Status LED/Orb

A huge advantage of Cocoa over AppleScript is the presence of callbacks and notifications.
Here is a smarter way to monitor the directory. No timers, no loops.
FSEvents notify every time the directory changes, the callback invokes a delegate method (directoryDidChange) in the script.

First, create an Objective-C class in your project (⌘N), name it FSEDirectoryWatcher (subclass of NSObject)

Replace the contents of FSEDirectoryWatcher.h with

Applescript:


#import <Foundation/Foundation.h>

@class FSEDirectoryWatcher;

@protocol FSEDirectoryWatcherDelegate
- (void)directoryDidChange:(NSString *)path;
@end

@interface FSEDirectoryWatcher : NSObject

+ (id)directoryWatcherWithPath:(NSString *)path delegate:(id)delegate;
- (id)initWithPath:(NSString *)path delegate:(id)delegate;

- (void)start;
- (void)stop;

@property (copy) NSString *directory;
@property (weak) id<FSEDirectoryWatcherDelegate> delegate;

@end

Replace the contents of FSEDirectoryWatcher.m with

Applescript:


#import "FSEDirectoryWatcher.h"

static void fileSystemEventCallback(ConstFSEventStreamRef streamRef, void *userData, size_t numEvents, void *eventPaths,
const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]);

@interface FSEDirectoryWatcher ()
{
dispatch_queue_t queue;
   FSEventStreamRef stream;
}
@end

@implementation FSEDirectoryWatcher

+ (id)directoryWatcherWithPath:(NSString *)path delegate:(id)delegate

{
   return [[FSEDirectoryWatcher alloc] initWithPath:path delegate:delegate];
}

- (id)initWithPath:(NSString *)path delegate:(id)delegate
{
   self = [super init];
if (self) {
       _directory = path;
       _delegate = delegate;
queue = dispatch_queue_create("com.myself.FSEDirectoryWatcher", DISPATCH_QUEUE_SERIAL);
   }
   return self;
}

- (void) dealloc
{
if (queue) dispatch_release(queue);
   [self stop];
}

- (void)start
{
   NSArray *pathsToWatch = @[self.directory];
   FSEventStreamContext context = {0, (__bridge void *)self, NULL, NULL, NULL};
CFAbsoluteTime latency = 3.0; /* Latency in seconds */
   
   stream = FSEventStreamCreate(NULL, &fileSystemEventCallback, &context, (__bridge CFArrayRef)pathsToWatch,
                                kFSEventStreamEventIdSinceNow, latency, kFSEventStreamCreateFlagUseCFTypes);
   
   FSEventStreamSetDispatchQueue(stream, queue);
   FSEventStreamStart(stream);
}

- (void)stop
{
   if (stream) {
       FSEventStreamStop(stream);
       FSEventStreamInvalidate(stream);
       FSEventStreamRelease(stream);
stream = nil;
   }
}

@end

static void fileSystemEventCallback(ConstFSEventStreamRef streamRef, void *userData, size_t numEvents, void *eventPaths,
const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) {
FSEDirectoryWatcher *directoryWatcher = (__bridge FSEDirectoryWatcher *)userData;
NSArray *paths = (__bridge NSArray *)eventPaths;

[paths enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (directoryWatcher.delegate) [directoryWatcher.delegate directoryDidChange:obj];
       
}];
}

Note: the FSEDirectoryWatcher class requires ARC (automatic reference counting)

This is the AppleScript code

Applescript:


property DirectoryWatcher : class "FSEDirectoryWatcher"

property statusImage1 : missing value -- image view 1
property statusImage2 : missing value -- image view 2

on applicationWillFinishLaunching_(aNotification)
   set hotFolder to current application's NSString's stringWithString_("/Path/to/directory")
   directoryDidChange_(hotFolder)
   set watcher to DirectoryWatcher's directoryWatcherWithPath_delegate_(hotFolder, me)
   watcher's start()
end applicationWillFinishLaunching_

on imageForStatus_(status)
   if status = true then
       set imageName to current application's NSImageNameStatusAvailable
   else
       set imageName to current application's NSImageNameStatusUnavailable
   end if
   return current application's NSImage's imageNamed_(imageName)
end imageForStatus_

on directoryDidChange_(directoryPath)
   set filePath to directoryPath's stringByAppendingPathComponent_("logfile1.log")
   set fileExists to NSFileManager's defaultManager()'s fileExistsAtPath_(filePath) as boolean
   statusImage1's setImage_(imageForStatus_(fileExists))
   set filePath to directoryPath's stringByAppendingPathComponent_("logfile2.log")
   set fileExists to NSFileManager's defaultManager()'s fileExistsAtPath_(filePath) as boolean
   statusImage2's setImage_(imageForStatus_(fileExists))
end directoryDidChange_

Last edited by StefanK (2013-03-11 04:09:14 am)


regards

Stefan

Offline

 

#11 2013-03-11 05:52:00 am

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5825

Re: Activity Indicator - Similar to Domain or Network Status LED/Orb

StefanK wrote:

Note: the FSEDirectoryWatcher class requires ARC (automatic reference counting)


It's probably worth pointing out that that means it can only be used as-is under OS X 10.8.

Stefan:

• Have you made any ARC ASObjC apps, and if so have you seen any memory leaks?

• I like the design of your FSEDirectoryWatcher class, but have you considered using dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE ...) instead of FSEvents?


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Online

 

#12 2013-03-11 08:00:35 am

StefanK
Member
From:: St. Gallen, Switzerland
Registered: 2006-10-21
Posts: 11578
Website

Re: Activity Indicator - Similar to Domain or Network Status LED/Orb

Shane Stanley wrote:

It's probably worth pointing out that that means it can only be used as-is under OS X 10.8.


Actually ARC is supported in Lion too (64 bit only) and even in Snow Leopard (no weak references).
But it's very easy to create a Garbage Collection or Memory Management version

Shane Stanley wrote:

Stefan:

• Have you made any ARC ASObjC apps, and if so have you seen any memory leaks?


No, I've written a Cocoa app with a lot of ASOC classes, which I use frequently.
I'll run Instruments the next time.

Shane Stanley wrote:

• I like the design of your FSEDirectoryWatcher class, but have you considered using dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE ...) instead of FSEvents?


Yes, I know that too (as well as kqueue). FSEvents is preferable for multiple directories or a directory hierarchy,
for a single file or single directory indeed dispatch_source_create is the better solution


regards

Stefan

Offline

 

#13 2013-03-11 04:14:11 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5825

Re: Activity Indicator - Similar to Domain or Network Status LED/Orb

StefanK wrote:

Actually ARC is supported in Lion too (64 bit only) and even in Snow Leopard (no weak references).


Yes, but you can't use ARC with ASObjC under versions before 10.8. As I understand it, the AppleScriptObjC runtime does its own memory management in 10.8, so it works with ARC or GC (or manual management). But because it's part of the runtime, it's not available in earlier versions, so apps that are to run under them are restricted to GC or manual management.

I've written a Cocoa app with a lot of ASOC classes, which I use frequently.
I'll run Instruments the next time.


Thanks!


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Online

 

#14 2019-07-23 02:16:59 am

maro
Member
From:: Nerima, Tokyo, Japan
Registered: 2004-05-30
Posts: 16
Website

Re: Activity Indicator - Similar to Domain or Network Status LED/Orb

I'm using StefanK's Objectve-C program as a Cocoa Framework.It is easy to call FSEvents via StefanK's program. This AppleScript runs on Script Editor or Script Debugger.

Thanks StefanK!


--
--    Created by: Takaaki Naganoya
--    Created on: 2019/07/23
--
--    Copyright © 2019 Piyomaru Software, All Rights Reserved
--

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions
use framework "FSWatcher" --Original By  StefanK http://macscripter.net/viewtopic.php?pid=161125

property filesInADir : {}
property currentFilesInADir : {}
property dlRes : "" --Watch Folder Path (POSIX path)

on run
    set dlRes to getSafariDownloadFolder() of me
    set hotFolder to current application's NSString's stringWithString:dlRes
    set aWatcher to current application's FSEDirectoryWatcher's alloc()'s initWithPath:hotFolder delegate:me
    my aWatcher's start()
end run


on getSafariDownloadFolder()
    set theID to id of application "Safari" --> "com.apple.Safari"
    set dlRes2 to getAppDefaultsValue(theID, "DownloadsPath")
    return dlRes2
end getSafariDownloadFolder


on getAppDefaultsValue(appBundleID, appKey)
    set storedDefaults to (current application's NSUserDefaults's standardUserDefaults()'s persistentDomainForName:appBundleID)
    set keyList to storedDefaults's allKeys() as list
    if appKey is not in keyList then return missing value
    set dlRes to (storedDefaults's valueForKeyPath:appKey)
    set dlRes2 to (dlRes's stringByExpandingTildeInPath()) as list of string or string
    return dlRes2
end getAppDefaultsValue



on directoryDidChange:aDirPath
    set aTmpPath to aDirPath as string
    if aTmpPath is not equal to dlRes then
        tell current application
            display notification "Download Folder Changed with..." & return & aTmpPath
        end tell
    end if
end directoryDidChange:

Model: MacBook Pro
AppleScript: 2.5
Browser: Safari 605.1.15
Operating System: macOS 10.12


I wrote thousands of AppleScript to realize my idea. Natural language interface, voice recognition commander and so on. Though my mother toungue is strange language, Japanese, my most frequently write language is AppleScript. I believe it is for making things easy and powerful.


Filed under: file, cocoa, file path, FSEvents

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)