saving to finder.plist

  1. 6 weeks ago

    James P

    Jan 9 Pre-Release Testers Jamaica

    I'm trying to programmatically change the colour of tags in Apple Finder.

    I can add tags using folder item.setTagNamesMBS, but there doesn't seem to be an equivalent to set the colours. So instead I am trying to edit the content of com.apple.finder.plist.

    I can find the appropriate cfDictionaryMBS in the plist, but I don't seem to be able to change the content prior to saving. Here's the latter part of the routine...

    Public Function updateTag(oldName as string, newName as string = "", colourNumber as integer) as boolean
      
      
      Dim cd As cfDictionaryMBS = get_CFDict_forTag(oldName) //returned from the array in plist
      
      If cd = Nil Then Return False
      
      //make it editable
      Dim cdm As CFMutableDictionaryMBS = cd.edit
      
      If newName = "" Then newName = oldName
      
      cdm.set(NewCFStringMBS("n"), NewCFStringMBS("newName") )
      cdm.set(NewCFStringMBS("l"),  NewCFNumberMBSInteger( colourNumber ) )
      
      //commit??
      //cd = cdm
      //this has modified the dictionary within the file
      //now need to write back the whole file I think - can't just update the one item
      
      Dim b As Boolean = cd_plist.writeToFile(fPlist, True) //this is working but the plist still has old values in it
      
      If b = False Then
        MsgBox "failed to write to plist"
      End If
      
      
      //return true if it worked
      Return b
      
      
    End Function

    Basically I am unclear as to how to get the mutable dictionary back into the original dictionary (cd_plist) - which I have also made as mutable. Do I have to make all intermediate dictionaries in the hierarchy mutable too or is there something else I am missing?

  2. James P

    Jan 10 Pre-Release Testers Jamaica

    I have updated the routines to make all cfDictionaries and cfArrays in the hierarchy mutable per the methods below, but still not saving the amended dictionary to file. Does anything else need to be mutable?

    Public Sub updateSystemTags()
      
      If fPlist = Nil Then Return 
      
      //now load the plist into an xml reader
      Dim b As LargeBinaryStreamMBS = fPlist.OpenAsLargeBinaryStreamMBS(False)
      Dim s As String = b.Read(b.Length)
      
      Dim cb As CFBinaryDataMBS = NewCFBinaryDataMBSStr(s)
      Dim co As CFObjectMBS = NewCFObjectMBSFromXML(cb)
      
      cdm_plist = CFDictionaryMBS(co).edit  //save it for later use
      
      co = cdm_plist.value(NewCFStringMBS("values"))
      
      Dim cdm As CFMutableDictionaryMBS
      cdm = CFDictionaryMBS(co).edit
      
      co = cdm.value(NewCFStringMBS("FinderTagDict"))
      cdm = CFDictionaryMBS(co).edit
      
      co = cdm.value(NewCFStringMBS("value"))
      cdm = CFDictionaryMBS(co).edit
      
      co = cdm.value(NewCFStringMBS("FinderTags"))
      cam = CFArrayMBS(co).edit //saved as a property so can be accessed later
      
      //ca should be an array of dictionaries
      //each has key n for name, l for colour number (0-7), p for binary
      
      Dim c As Integer = cam.count-1
      
      //clear the dictionary
      diTags.RemoveAll
      
      Dim o As CFObjectMBS
      
      For i As Integer = 0 To c
        co = cam.item(i)
        cdm = CFDictionaryMBS(co).edit
        
        Dim sysT As New systemTag
        o= cdm.Value(NewCFStringMBS("n"))
        If o <> Nil Then 
          
          sysT.name = CFStringMBS(o).Str
          
          o = cdm.value(NewCFStringMBS("l"))
          If o <> Nil Then sysT.colorNo= cfNumberMBS(o).integerValue
          
          o= cdm.Value(NewCFStringMBS("p"))
          If o <> Nil Then sysT.p = CFBooleanMBS(o).Value
          
          o= cdm.Value(NewCFStringMBS("v"))
          If o <> Nil Then sysT.v = CFBooleanMBS(o).Value
          
          //add the contents to the dictionary
          diTags.Value(sysT.name) = sysT
          
        End If
        
      Next
      
    End Sub
    Public Function updateTag(oldName as string, newName as string = "", colourNumber as integer) as boolean
      
      Dim cdm As cfMutableDictionaryMBS = get_CFDict_forTag(oldName) //returned from the array in plist
      
      If cdm = Nil Then Return False
      
      If newName = "" Then newName = oldName
      
      cdm.set(NewCFStringMBS("n"), NewCFStringMBS("newName") )
      cdm.set(NewCFStringMBS("l"),  NewCFNumberMBSInteger( colourNumber ) )
      
      Dim b As Boolean = cdm_plist.writeToFile(fPlist, True) //this is working but the plist still has old values in it
      
      If b = False Then
        MsgBox "failed to write to plist"
      End If
      
      //return true if it worked
      Return b
      
    End Function
    
  3. Norman P

    Jan 10 Pre-Release Testers, Xojo Pro outside listening to the silen...

    if you read and alter the plist and save it back you _may_ need to synchronize it to make sure the chnages get pushed into the file ASAP
    For some time Apple has used an in memory cache that will periodically save chnages to disk
    But there is a plist API to force that to occur

    As well you should be able to use the defaults command in terminal once you have made changes to see the results

  4. James P

    Jan 10 Pre-Release Testers Jamaica

    Thanks Norman, but it appears the problem is before that. When I save the plist to a new test location I can see that the various dictionary/array elements have not been changed from their originals, so something seems to be wrong in my code.

  5. Norman P

    Jan 10 Pre-Release Testers, Xojo Pro outside listening to the silen...

    quite possibly a permissions issue :)

  6. James P

    Jan 10 Pre-Release Testers Jamaica

    No, I don't think so. I am able to save the file to desktop OK, but the file still has the old unchanged content.

  7. 5 weeks ago

    Greg O

    Jan 12 Xojo Inc scout.galaxy.barn

    It’s worth noting that Finder Labels and Finder Label Colors are read-only in NSWorkspace. It could be that only the Finder itself is allowed to change these now.

  8. Emile S

    Jan 12 Europe (France, Strasbourg)

    Have you tried AppleScript ?

    Example:
    set label index of item "Testing.sqlite" of front window to 2 # Red

  9. Sam R

    Jan 12 Pre-Release Testers, Xojo Pro, Third Party Store Hengchun, Pingtung, Taiwan

    @James P No, I don't think so. I am able to save the file to desktop OK, but the file still has the old unchanged content.

    This is odd, because if you try to send a mutating message to a non-mutable object in Object-C, you get an exception. So I would assume that you'd be aware if your dictionary was just a NSDictionary and not a NSMutableDictionary. Unless there some code (maybe in a plugin) that's capturing the exception and not correctly forwarding it to your application.

    Looking at your code, I see you're using CFDictionaries, the same should still apply.

    I see that you're updating a value called "cdm", but are writing out "cdm_plist". Are these the same object?

  10. James P

    Jan 14 Pre-Release Testers Jamaica

    Thanks Sam

    @Sam R I see that you're updating a value called "cdm", but are writing out "cdm_plist". Are these the same object?

    No they are different objects. cdm_plist is the dictionary at the top of the plist hierarchy whereas cdm is the dictionary lower down in the hierarchy. The hierarchy goes something like this:
    <dict>
    <key>
    <dict>
    <key>
    <array>
    <dict>
    <key>
    <string>

    So I've converted each of the dicts and arrays to mutable in the hierarchy - but still doesn't seem to change the resultant file saved.

or Sign Up to reply!