37 Replies Latest reply on Jun 12, 2012 1:49 PM by areohbee

    Writing a plugin to create Smart Collections

    John Spacey Level 1

      Hi folks

       


      Is it possible to use the SDK to create a plugin that creates a Collection Set that contains a number of Smart collections.

       

      I'd also like to be able to select a Folder and have the plugin use the folder name as one of the parameters in the Smart collections and the title of the Collection Set

       

      Cheers in advance

        • 1. Re: Writing a plugin to create Smart Collections
          johnrellis Most Valuable Participant

          It should be straightforward.  In the LrCatalog class, see the methods catalog:createSmartCollection() and catalog:createCollectionSet().

           

          To find out which folder or folders are currently selected, see the method catalog:getActiveSources().

          • 2. Re: Writing a plugin to create Smart Collections
            areohbee Level 5

            You may be interested in:

             

            Folder Collections:

             

            http://www.robcole.com/Rob/ProductsAndServices/FolderCollectionsLrPlugin

             

            Download is source code format.

             

            It uses dumb collections because there is no way to have smart collection content match folder content - I got close using smart collections, but ultimately had to rely on dumb collections and a background task.

             

            Still, the original version used smart collections, and the code for it is still mostly in there...

             

            Cheers,

            Rob

            • 3. Re: Writing a plugin to create Smart Collections
              John Spacey Level 1

              thanks guys

               

              Yes it looks like it shouldn't be too difficult to get something up and running that meets my needs. I'm pretty experienced in PHP programming, but do need to learn LUA.

              • 4. Re: Writing a plugin to create Smart Collections
                areohbee Level 5

                The "closures" feature of Lua, among other things, makes it a delightful language to program with, in my opinion. - very simple, but very powerful - a shining example of good programming language design, in my opinion.

                 

                Enjoy!

                Rob

                • 5. Re: Writing a plugin to create Smart Collections
                  John Spacey Level 1

                  Ok, I'm admitting defeat at an early stage ...

                   

                  I think I've managed to return the array of selected sources from catalog:getActiveSources()

                   

                  However I can't find any documentation on the actual structure of this array or how to access it

                   

                  The docs for catalog:getActiveSources() say

                   

                  Returned:

                  (array of LrCollection, LrCollectionSet, LrPublishedCollection, LrPublishedCollectionSet or LrFolder)

                   

                   

                  • 6. Re: Writing a plugin to create Smart Collections
                    Don McKee Level 1

                    Hi John,

                     

                    Try something like this:

                     

                    local sources = catalog:getActiveSources()

                     

                    for _notUsed, source in ipairs(sources) do

                     

                        if source:type() == 'LrCollection' then

                           -- do something

                        elseif source:type() == 'LrCollectionSet' then

                           -- do something

                        elseif source:type() == 'LrPublishedCollection' then

                           -- do something

                        elseif source:type() == 'LrPublishedCollectionSet' then

                           -- do something

                        elseif source:type() == 'LrFolder' then

                           -- do something

                        end

                     

                    end

                     

                    Does this help?

                     

                    -Don

                    • 7. Re: Writing a plugin to create Smart Collections
                      John Spacey Level 1

                      Thanks Don, that helps enormously.   I'm still having trouble extracting the source names though.  Guessing from source:type() I tried getting the names by trying source:name() or source:title() but it didn't work.   Sorry about these possibly dumb questions, but I can't find any documentation on the structure of the array.

                      • 8. Re: Writing a plugin to create Smart Collections
                        Don McKee Level 1

                        Hi John,

                         

                        The array is just a Lua array (e.g. sources[1], sources[2], ...) that, according to the Lightroom SDK doc contains one of the listed objects.  Also referring to the SDK doc for the objects, they all have a "getName()" method.  Is that what you're looking for?

                         

                        -Don

                        • 9. Re: Writing a plugin to create Smart Collections
                          John Spacey Level 1

                          Ahh getName()

                           

                          I  tried this by inserting  sourceName = source:getName() in your code abvoe @  -- do something and I got the followimg error

                           

                          "An internal error has occoured: We can only wait from within a task"

                          • 10. Re: Writing a plugin to create Smart Collections
                            Don McKee Level 1

                            What object were you looking at?  For example, the LrPublishedCollection's getName() method documentation includes:

                             

                            This function must be called from within an asynchronous task started using LrTasks.

                             

                            Did you do that?

                             

                            -Don

                            • 11. Re: Writing a plugin to create Smart Collections
                              John Spacey Level 1

                              I was looking at the object LrFolder in the returned array

                               

                              I tried to get the name of the selected folder like this:

                               

                              elseif source:type() == 'LrFolder' then

                                     sourceName = source:getName()

                                  end

                               

                               

                               

                              /Adobe Lightroom 4 SDK/API Reference/modules/LrFolder.html#folder:getName

                               

                              which says:

                               

                              ------------------------------------------------------------------------------------------

                              folder:getName() Retrieves the name of this folder.

                              First supported in version 3.0 of the Lightroom SDK.

                              Return value

                              (string) The name.

                              ------------------------------------------------------------------------------------------

                              and mentions nothing about 'an asynchronous task started using LrTasks.' whatever that is

                               

                              Stumped

                              • 12. Re: Writing a plugin to create Smart Collections
                                areohbee Level 5

                                Lots of stuff only works in an asynchronous task.

                                 

                                The first thing I do in response to a menu or button is create an asynchronous task to process it, with an error handler attached to the processing context (LrFunctionContext).

                                 

                                That way, I never have to worry about something needing to be done from an asynchronous task, because *everything* is being done from an asynchronous task.

                                 

                                If you want to make sure another instance of the task doesn't get started before the other is finished, you can use recursion guarding.

                                 

                                I don't use the LrRecursionGuard, but it's one possibility.

                                 

                                Rob

                                • 13. Re: Writing a plugin to create Smart Collections
                                  John Spacey Level 1

                                  Where can I learn about how to create an asyncronous task?

                                   

                                  This is where I am at so far. I'm able to show a dialog box that lists the types of active sources

                                   

                                  https://fbcdn-sphotos-a.akamaihd.net/hphotos-ak-ash3/543743_424084167624887_174437144_n.jpg

                                   

                                  I modified one of the SDK programmers guide tutorials thus:

                                   

                                  ShowSources.lua

                                  ****************************************************************************************** ******

                                   

                                  local LrFunctionContext = import 'LrFunctionContext'

                                  local LrBinding = import 'LrBinding'

                                  local LrDialogs = import 'LrDialogs'

                                  local LrView = import 'LrView'

                                  local LrColor = import 'LrColor'

                                  local LrTasks = import 'LrTasks'

                                  local LrApplication = import 'LrApplication'

                                   

                                   

                                  MyHWLibraryItem = {}

                                   

                                  -- function to interrogate active sources array

                                  function read_activeSources_array( sources )

                                      source_type = "Active Sources:\n"

                                   

                                          for i, source in ipairs( sources ) do

                                              if source:type() == 'LrCollection'  then   

                                                  source_type = source_type .. i .. " is a Collection\n"

                                              elseif source:type() == 'LrFolder'  then

                                                  source_type = source_type .. i .. " is a folder\n"                   

                                              end           

                                              --local sourceName = source:getName()    -- this produces ***ERROR***

                                          end

                                   

                                          return source_type

                                  end

                                   

                                   

                                  -- ***ERROR*** "An internal error has occoured: We can only wait from within a task"

                                   

                                   

                                   

                                  function MyHWLibraryItem.showCustomDialog()

                                  -- body of show-dialog function

                                   

                                  LrFunctionContext.callWithContext( "ShowSources",

                                   

                                      function( context )

                                   

                                          catalog = LrApplication.activeCatalog()

                                          local path = catalog:getPath()

                                          local sources = catalog:getActiveSources()

                                   

                                          --string = LrTasks.startAsyncTask( read_activeSources_array( sources ) )

                                          display_string = read_activeSources_array( sources )

                                   

                                   

                                   

                                      -- create view hierarchy for dialog box

                                      local f = LrView.osFactory() -- get the view factory object

                                   

                                   

                                      local c = f:column { -- the root node

                                   

                                   

                                          f:row { -- Display contents of active sources Array

                                              f:static_text {

                                   

                                                  text_color = LrColor( 0, 0, 1 ),

                                                  alignment = "Left",

                                                  -- add title with binding later

                                   

                                                  title = display_string

                                              },

                                          },

                                      }

                                   

                                      local result = LrDialogs.presentModalDialog(

                                          {

                                          title = "Show Sources",

                                          contents = c, -- the view hierarchy we defined

                                          }

                                      )

                                   

                                      end )

                                   

                                  end

                                   

                                   

                                   

                                  MyHWLibraryItem.showCustomDialog()

                                   

                                  ******************************************************************************************

                                  • 14. Re: Writing a plugin to create Smart Collections
                                    areohbee Level 5

                                    LrFunctionContext.postAsyncTaskWithContext is my personal favorite, since you can create the task and the processing context in one swipe that way.

                                     

                                    Put that at the outermost level.

                                     

                                    Then assign a cleanup, or error handler to the context, so errors don't just silently abort, or at least that's what used to happen to button handlers, unless Adobe changed that in Lr4 (I haven't checked).

                                     

                                    I simply check/set a variable upon entry, then clear it in the cleanup handler to implement recursion guarding, which I have rolled into a set of classes which I use in my plugin framework.

                                     

                                    You can see said framework (elare plugin framework) in any of my plugins (e.g. http://www.robcole.com/Rob/ProductsAndServices), all of which include source code, and you can use the framework by going here:

                                     

                                    https://www.assembla.com/spaces/lrdevplugin/

                                     

                                    R

                                    • 15. Re: Writing a plugin to create Smart Collections
                                      Don McKee Level 1

                                      > Where can I learn about how to create an asyncronous task?

                                       

                                      From the sample plug-ins included with the SDK, and the SDK doc.  But, basically,

                                       

                                      LrTasks.startAsyncTask(function()

                                       

                                           MyHWLibraryItem.showCustomDialog()

                                       

                                      end)

                                       

                                      would run all of your code in a task.

                                       

                                      -Don

                                      • 16. Re: Writing a plugin to create Smart Collections
                                        Don McKee Level 1

                                        Oh, and what Rob said. 

                                         

                                        -Don

                                        • 17. Re: Writing a plugin to create Smart Collections
                                          areohbee Level 5

                                          Yeah, - what Don said too.

                                           

                                          Just remember that recursion guarding can become an issue when everything is done asynchronously, since impatient users or those with twitchy fingers may get 3 or 4 of the same things going at once if not careful. Obviously, if there isn't enough time to click twice before the first/next (modal) dialog box comes up..., it's a non-problem. But if processing takes more than a fraction of a second...  (Next up: LrProgressScope...).

                                           

                                          Also, tasks don't abort when reloading the plugin, until they're finished, *if* they finish. It's possible to have multiple instances of the same task running with different environments...

                                           

                                          I use LrShutdownPlugin to set a global shutdown flag and check it in async loops, so plugin reloads happen gracefully. (I wish LrTasks.sleep would automatically return a code upon a plugin reload / shutdown (like java...), but since it doesn't, I implemented my own sleeper in the framework).

                                           

                                          PS - There is some new shutdown handling which I've yet to investigate. Since it would be ignored in Lr3, it's hardly worth using unless plugin is Lr4 only.

                                           

                                          My apology in advance if this is too much too soon - maybe return to this thread and re-read if you start having problems...

                                           

                                          Also, as Obewankanobee said: read the docs, Luke...

                                           

                                          Rob

                                          • 18. Re: Writing a plugin to create Smart Collections
                                            John Spacey Level 1

                                            HURRAH! You guys Rock! Thanks ever so much. https://fbcdn-sphotos-a.akamaihd.net/hphotos-ak-ash4/481157_424096430956994_427450149_n.jpg

                                             

                                            I did

                                             

                                            LrTasks.startAsyncTask(function()

                                                MyHWLibraryItem.showCustomDialog()

                                            end)

                                             

                                            And then modified my function to

                                             

                                            -- function to interrogate active sources array

                                            function read_activeSources_array( sources )

                                                source_type = "Active Sources:\n"

                                             

                                                    for i, source in ipairs( sources ) do

                                                        local sourceName = source:getName()

                                                        if source:type() == 'LrCollection'  then   

                                                            source_type = source_type .. i .. " is a Collection called " .. sourceName .. "\n"

                                                        elseif source:type() == 'LrFolder'  then

                                                            source_type = source_type .. i .. " is a folder called " .. sourceName .. "\n"   

                                                            --source_type = source_type .. sourceName .."\n"           

                                                        end           

                                                       

                                                    end

                                                       

                                                    return source_type

                                            end

                                             

                                             

                                            ******************************************

                                            Rob, errors seem pretty verbose in LR4.1 when something has gone wrong an error dialog appears everytime on the cide I've been mangling

                                             

                                            I've bookmarked your site and the assembla site

                                             

                                            Thanks again peeps

                                            • 19. Re: Writing a plugin to create Smart Collections
                                              John Spacey Level 1

                                              Rob Cole wrote:

                                               

                                              Yeah, - what Don said too.

                                               

                                              Just remember that recursion guarding can become an issue when everything is done asynchronously, since impatient users or those with twitchy fingers may get 3 or 4 of the same things going at once if not careful. Obviously, if there isn't enough time to click twice before the first/next (modal) dialog box comes up..., it's a non-problem. But if processing takes more than a fraction of a second...  (Next up: LrProgressScope...).

                                               

                                              Also, tasks don't abort when reloading the plugin, until they're finished, *if* they finish. It's possible to have multiple instances of the same task running with different environments...

                                               

                                              I use LrShutdownPlugin to set a global shutdown flag and check it in async loops, so plugin reloads happen gracefully. (I wish LrTasks.sleep would automatically return a code upon a plugin reload / shutdown (like java...), but since it doesn't, I implemented my own sleeper in the framework).

                                               

                                              PS - There is some new shutdown handling which I've yet to investigate. Since it would be ignored in Lr3, it's hardly worth using unless plugin is Lr4 only.

                                               

                                              My apology in advance if this is too much too soon - maybe return to this thread and re-read if you start having problems...

                                               

                                              Also, as Obewankanobee said: read the docs, Luke...

                                               

                                              Rob

                                               

                                              Cheers Rob

                                               

                                              I am reading the docs as much as possible. I'm not finding them that intuitive to be honest, but I am trying to source the answers myself before coming here and shouting 'Help!      I hadn't even heard of LUA a few days ago so it is a bit of a jump in the deep end

                                              • 20. Re: Writing a plugin to create Smart Collections
                                                areohbee Level 5

                                                John Spacey wrote:

                                                 

                                                HURRAH! You guys Rock! Thanks ever so much.

                                                 

                                                ******************************************

                                                Rob, errors seem pretty verbose in LR4.1 when something has gone wrong an error dialog appears everytime on the cide I've been mangling

                                                 

                                                I've bookmarked your site and the assembla site

                                                 

                                                Thanks again peeps

                                                 

                                                Congrats, and you're welcome.

                                                 

                                                In some cases, Lightroom provides the error handling, in other cases - it doesn't.

                                                 

                                                I no longer remember which cases it does, and which cases it doesn't, since I always provide my own.

                                                 

                                                One case I do remember is button handlers. You *must* handle errors in button handlers or they will just silently malfunction, or at least that's true for Lr3-.

                                                 

                                                Oh yeah, change handlers (ui property observers) and ui validator functions are 2 more cases that need error handlers (unless you don't mind silent failure upon error).

                                                 

                                                R

                                                • 21. Re: Writing a plugin to create Smart Collections
                                                  areohbee Level 5

                                                  John Spacey wrote:

                                                   

                                                  Cheers Rob

                                                   

                                                  I am reading the docs as much as possible. I'm not finding them that intuitive to be honest, but I am trying to source the answers myself before coming here and shouting 'Help!      I hadn't even heard of LUA a few days ago so it is a bit of a jump in the deep end

                                                   

                                                  Hi John,

                                                   

                                                  Yeah, the docs are perhaps best digested along with a big dose of experience.

                                                   

                                                  Enjoy (I think Lua is great).

                                                   

                                                  Rob

                                                  • 22. Re: Writing a plugin to create Smart Collections
                                                    John Spacey Level 1

                                                    Right tonight's takst is to come up with a routine to create collection sets and collections based upon those fodler names. I shall go and digest as much documentionation as possible before shouting for help

                                                    • 23. Re: Writing a plugin to create Smart Collections
                                                      John Spacey Level 1

                                                      Excellent! On a roll tonight. Managed to create a collection set containing a number of Smart collections!   Only issue I have now is finding an existing collection set of a known name and using that as a parent to the newly created collection set.

                                                      • 24. Re: Writing a plugin to create Smart Collections
                                                        areohbee Level 5

                                                        I have a number of plugins that deal with collections which may have some good example source code:

                                                         

                                                        FolderCollections

                                                        CollectionAgent

                                                        Stacker

                                                        SQLiteroom

                                                        LrFourB

                                                        PublishServiceAssistant

                                                         

                                                        http://www.robcole.com/Rob/ProductsAndServices

                                                         

                                                        R

                                                        • 25. Re: Writing a plugin to create Smart Collections
                                                          John Spacey Level 1

                                                          Thanks Rob

                                                           

                                                          I've already had a look in your FolderCollections.lua and there was some helpful code in there I'll check out the others soon

                                                           

                                                          tongiht I've written a recursive function that gets an activeSource's parent and then gets the parent's parent, and so on until the 'root' is reached. The recursive function adds the succesive parents to an Array. ( a table in LUA speak I believe )

                                                           

                                                          ******************************************************

                                                           

                                                          -- Function to create array of folder of collection parental structure

                                                          function MyHWLibraryItem.CreateParentStructure( source, parent_table,  x )       

                                                                      local source_parent = source:getParent()           

                                                                      --add to parent table ( array )

                                                                      parent_table[x] = source_parent

                                                                     

                                                                      if parent_table[x] ~= nil then -- parent exists

                                                                          x=x+1

                                                                          -- call itself to interrogate further up the parent branch

                                                                          parent_table = MyHWLibraryItem.CreateParentStructure( source_parent, parent_table,  x )

                                                                      else -- parent doesn't exist - top of branch

                                                                          parent_table[x] = false       

                                                                      end

                                                                      return parent_table    

                                                          end

                                                           

                                                           

                                                          ******************************************************

                                                           

                                                          Interesting to note that I couldn't get this to work until I realised I couldn't assign an element of the array a value of "nil" ( which is returned when getParent() finds no parent ) and had to assign it a value of 'false' instead.

                                                           

                                                          I think your Folder Collections plug deals with recreating path structures so I'll take another look at that shortly

                                                          • 26. Re: Writing a plugin to create Smart Collections
                                                            areohbee Level 5

                                                            Looks good John.

                                                             

                                                            A couple lua-y things to note:

                                                             

                                                            You can assign nil to an array, but:

                                                             

                                                            * ipairs stops on the first nil.

                                                            * #tbl counts items (at positive integer indexes) up unitl the last nil.

                                                             

                                                            I mean, assigning non-nil values (e.g. false) is probably the preferred approach in this case, but just so ya know:

                                                             

                                                            #{ x=1 } == 0 -- is true

                                                            #{ 1, nil, 3 } == 3 -- true too

                                                            #{ 1, nil } == 1 -- also true

                                                            #{ x=1, 2 } == 1 -- true

                                                            { x=1, 2 }[1] == 2 -- true

                                                            local x = {}

                                                            x[0] = 1

                                                            #x == 0 -- true

                                                             

                                                            for i,v in ipairs{ 1, nil, 3 } do

                                                                 local nothing = 1 -- executes only once

                                                            end

                                                             

                                                            R

                                                            • 27. Re: Writing a plugin to create Smart Collections
                                                              John Spacey Level 1

                                                              Cheers Rob very helpful   

                                                              • 28. Re: Writing a plugin to create Smart Collections
                                                                John Spacey Level 1

                                                                Hi peeps.

                                                                 

                                                                Just about finished. Seems to be working OK. Just gotta tidy up the dialog box. I'll post the code when done. 

                                                                • 29. Re: Writing a plugin to create Smart Collections
                                                                  areohbee Level 5

                                                                  Standing by... (thanks).

                                                                  R

                                                                  • 30. Re: Writing a plugin to create Smart Collections
                                                                    John Spacey Level 1

                                                                    Here ya go - A huge thanks to you chaps for all your help!.

                                                                     

                                                                    **************************************************************************************

                                                                     

                                                                     

                                                                    local LrFunctionContext = import 'LrFunctionContext'

                                                                    local LrBinding = import 'LrBinding'

                                                                    local LrDialogs = import 'LrDialogs'

                                                                    local LrView = import 'LrView'

                                                                    local LrColor = import 'LrColor'

                                                                    local LrTasks = import 'LrTasks'

                                                                    local LrApplication = import 'LrApplication'

                                                                    local LrLogger = import 'LrLogger'

                                                                     

                                                                     

                                                                    local myLogger = LrLogger( 'libraryLogger' )

                                                                    myLogger:enable( "logfile" ) -- or "print"

                                                                     

                                                                     

                                                                    MyHWLibraryItem = {}

                                                                     

                                                                     

                                                                     

                                                                    -- Logger function

                                                                     

                                                                    function MyHWLibraryItem.outputToLog( message )

                                                                        myLogger:trace( message )

                                                                    end

                                                                     

                                                                     

                                                                     

                                                                    -- Function to extract names from parent table

                                                                    function MyHWLibraryItem.Path_String_From_Parent_Table( parent_table )

                                                                        -- stuff goes in here

                                                                        local path_string =""   

                                                                        for y, source in ipairs( parent_table ) do

                                                                            if source ~= false then       

                                                                                parent = source:getName()

                                                                            else

                                                                                parent = "ROOT"

                                                                            end

                                                                            if y == #parent_table then

                                                                                path_string = path_string .. parent .. "/.."

                                                                            else

                                                                                path_string = path_string .. parent .. "/"

                                                                            end

                                                                        end       

                                                                        return path_string

                                                                    end

                                                                     

                                                                     

                                                                     

                                                                    -- Function to create array of folder of collection parental structure

                                                                    function MyHWLibraryItem.CreateParentStructure( source, parent_table,  x )       

                                                                                local source_parent = source:getParent()           

                                                                                --add to parent table ( array )

                                                                                parent_table[x] = source_parent       

                                                                                if parent_table[x] ~= nil then -- parent exists

                                                                                    x=x+1

                                                                                    -- call itself to interrogate further up the parent branch

                                                                                    parent_table = MyHWLibraryItem.CreateParentStructure( source_parent, parent_table,  x )

                                                                                else -- parent doesn't exist - top of branch

                                                                                    parent_table[x] = false

                                                                                end       

                                                                                return  parent_table   

                                                                    end

                                                                     

                                                                     

                                                                     

                                                                    function MyHWLibraryItem.showCustomDialog()

                                                                    -- body of show-dialog function

                                                                     

                                                                    LrFunctionContext.callWithContext( "ShowSources",

                                                                     

                                                                        function( context )

                                                                     

                                                                            catalog = LrApplication.activeCatalog()

                                                                            local source_type

                                                                            local source_name

                                                                            local source_parent

                                                                            local source_parent_name

                                                                            local collection_set

                                                                            local path = catalog:getPath()

                                                                            local sources = catalog:getActiveSources()

                                                                            --local folders = catalog:getFolders()

                                                                           

                                                                            source_type = "Active Sources:\n***********\n\n"

                                                                     

                                                                            -- analyse source table

                                                                            for i, source in ipairs( sources ) do

                                                                     

                                                                                -- Create table for parent structure of source

                                                                                local parent_table = {}

                                                                                source_name = source:getName()

                                                                                x=1 -- init counter for parent table

                                                                                -- call recursive function

                                                                                parent_table = MyHWLibraryItem.CreateParentStructure( source, parent_table, x )

                                                                               

                                                                                -- now reverse the parent table

                                                                                local y=1

                                                                                local z = #parent_table

                                                                                local parent_table_rev = {} -- create empty rev table

                                                                                for a = z , 1, -1 do

                                                                                    parent_table_rev[y] = parent_table[z]

                                                                                    y=y+1    z=z-1

                                                                                end           

                                                                                parent_table = parent_table_rev

                                                                                -- end reverse parent table

                                                                       

                                                                                -- create path string from parent_table

                                                                                source_parent_name = MyHWLibraryItem.Path_String_From_Parent_Table( parent_table )

                                                                       

                                                                                local name_and_parent_display = "\"" .. source_name .. "\" \n          Parent(s) = " .. source_parent_name .."\n"

                                                                     

                                                                                if source:type() == 'LrFolder'  then

                                                                                        smart_coll_report = ""

                                                                                        -- ********* CREATE COLLECTION SETS and SMART COLLECTIONS *****************

                                                                                        -- create collection set hierarchy

                                                                                        for i = 1, #parent_table do

                                                                                             MyHWLibraryItem.outputToLog( "STEP = " .. i )

                                                                                             if i==1 then -- root

                                                                                                 --do nothing

                                                                                             else

                                                                                                 --create collection set

                                                                                                 if parent_table[i-1] == false then

                                                                                                 MyHWLibraryItem.outputToLog( "parent table = FALSE." )

                                                                                                     parent = nil

                                                                                                 else

                                                                                                     --parent = parent_table[i-1]

                                                                                                     MyHWLibraryItem.outputToLog( "parent name = " .. parent:getName() )

                                                                                                 end

                                                                                                 catalog:withWriteAccessDo( "Create Collection Set 2" , function( context )

                                                                                                     parent = catalog:createCollectionSet( parent_table[i]:getName() , parent , true )

                                                                                                 end)

                                                                                                MyHWLibraryItem.outputToLog( "collection set created. Name = " .. parent:getName() )

                                                                                            end

                                                                                        end   

                                                                                        catalog:withWriteAccessDo( "Create Collection Set 1" , function( context )            

                                                                                             -- Create new collection set

                                                                                            collection_set = catalog:createCollectionSet( source_name , parent ) 

                                                                                            if collection_set ~= nil then

                                                                                                smart_coll_report = smart_coll_report .. "               Collection Set '"..source_name.."' created OK\n"

                                                                                            else

                                                                                                smart_coll_report = smart_coll_report .. "               Collection Set '"..source_name.."' ALREADY EXISTS!\n"

                                                                                            end

                                                                                           

                                                                                             -- create Smart Collections for ratings

                                                                                            if collection_set ~= nil then

                                                                                                local smart_collection_set_1 = catalog:createSmartCollection( "<2", {{criteria="rating",operation="<",value=2},{criteria="folder",operation="all",value=sourc e_name}}, collection_set )

                                                                                                local smart_collection_set_2 = catalog:createSmartCollection( "2+", {{criteria="rating",operation=">=",value=2},{criteria="folder",operation="all",value=sour ce_name}}, collection_set )

                                                                                                local smart_collection_set_3 = catalog:createSmartCollection( "3+", {{criteria="rating",operation=">=",value=3},{criteria="folder",operation="all",value=sour ce_name}}, collection_set )

                                                                                                local smart_collection_set_4 = catalog:createSmartCollection( "4+", {{criteria="rating",operation=">=",value=4},{criteria="folder",operation="all",value=sour ce_name}}, collection_set )

                                                                                               

                                                                                                if smart_collection_set_1 ~= nil then smart_coll_report = smart_coll_report .. "               Smart Collection '<2' created OK\n" end

                                                                                                if smart_collection_set_2 ~= nil then smart_coll_report = smart_coll_report .. "               Smart Collection '2+' created OK\n" end

                                                                                                if smart_collection_set_3 ~= nil then smart_coll_report = smart_coll_report .. "               Smart Collection '3+' created OK\n" end

                                                                                                if smart_collection_set_4 ~= nil then smart_coll_report = smart_coll_report .. "               Smart Collection '4+' created OK\n" end

                                                                                                end

                                                                                               

                                                                                        end ) -- end of catalog:withWriteAccessDo FUNCTION                   

                                                                                        -- ************************************************************************

                                                                                       

                                                                                        -- create display string

                                                                                        source_type = source_type .. i .. " Folder: " .. name_and_parent_display .. smart_coll_report .. "\n"

                                                                                       

                                                                                       

                                                                                elseif source:type() == 'LrCollectionSet'  then   

                                                                                    smart_coll_report = ""

                                                                                    source_type = source_type .. i .. " Collection Set: " .. name_and_parent_display  .. smart_coll_report .. "\n"

                                                                       

                                                                                elseif source:type() == 'LrCollection'  then

                                                                                    smart_coll_report = ""

                                                                                    source_type = source_type .. i .. " Collection: " .. name_and_parent_display .. smart_coll_report .. "\n"

                                                                     

                                                                                elseif source:type() == 'LrPublishedCollection'  then   

                                                                                    smart_coll_report = ""

                                                                                    source_type = source_type .. i .. " Published Collection: " .. name_and_parent_display .. smart_coll_report .. "\n"

                                                                     

                                                                                elseif source:type() == 'LrPublishedCollectionSet'  then   

                                                                                    smart_coll_report = ""

                                                                                    source_type = source_type .. i .. " Published Collection Set: " .. name_and_parent_display .. smart_coll_report .. "\n"

                                                                            end                       

                                                                        end

                                                                     

                                                                        display_string = source_type

                                                                           

                                                                        -- create view hierarchy for dialog box

                                                                        local f = LrView.osFactory() -- get the view factory object

                                                                        local c = f:column { -- the root node

                                                                            f:row { -- Display contents of active sources Array

                                                                                f:static_text {

                                                                                    text_color = LrColor( 0, 0, 0 ),

                                                                                    alignment = "Left",

                                                                                    -- add title with binding later

                                                                                    title = display_string                

                                                                                },

                                                                            },

                                                                        }

                                                                     

                                                                        local result = LrDialogs.presentModalDialog(

                                                                            {

                                                                            title = "Create Rating Smart Collection Sets",

                                                                            contents = c, -- the view hierarchy we defined

                                                                            }

                                                                        )

                                                                     

                                                                        end )

                                                                     

                                                                    end

                                                                     

                                                                     

                                                                     

                                                                    LrTasks.startAsyncTask(function()

                                                                        MyHWLibraryItem.showCustomDialog()

                                                                    end)

                                                                    • 31. Re: Writing a plugin to create Smart Collections
                                                                      areohbee Level 5

                                                                      Looks good, but I wrapped it in a plugin and tried it, and I can't tell what happened (couldn't find any new collections, nor was there a UI message presented (after I approved the initial prompt I mean), nor any logged messages). I'm not sure what was supposed to happen.

                                                                       

                                                                      ?

                                                                      R

                                                                      • 32. Re: Writing a plugin to create Smart Collections
                                                                        John Spacey Level 1

                                                                        Hmmm interesting. Works fine here ....

                                                                         

                                                                        What should happen is for any sources you select the routine will create an identical structure of collection sets and smart collections based upon ratings of pics in those sources as:

                                                                         

                                                                        -- create Smart Collections for ratings

                                                                                                if collection_set ~= nil then

                                                                                                    local smart_collection_set_1 = catalog:createSmartCollection( "<2", {{criteria="rating",operation="<",value=2},{criteria="folder",operati on="all",value=source_name}}, collection_set )

                                                                                                    local smart_collection_set_2 = catalog:createSmartCollection( "2+", {{criteria="rating",operation=">=",value=2},{criteria="folder",operat ion="all",value=source_name}}, collection_set )

                                                                                                    local smart_collection_set_3 = catalog:createSmartCollection( "3+", {{criteria="rating",operation=">=",value=3},{criteria="folder",operat ion="all",value=source_name}}, collection_set )

                                                                                                    local smart_collection_set_4 = catalog:createSmartCollection( "4+", {{criteria="rating",operation=">=",value=4},{criteria="folder",operat ion="all",value=source_name}}, collection_set )

                                                                         

                                                                         

                                                                        So for the red ticked slected folder source Dubau LR then the red encircled collection set/smart collection structure is created:

                                                                         

                                                                        https://fbcdn-sphotos-a.akamaihd.net/hphotos-ak-ash3/523608_426639240702713_216228329_n.jpg

                                                                        • 33. Re: Writing a plugin to create Smart Collections
                                                                          areohbee Level 5

                                                                          Thanks,

                                                                           

                                                                          I tried it using a folder source and it worked. Previous test was using a collection as source.

                                                                           

                                                                          Unfortunately, for me, the smart collection folder criteria casts too wide a net (sometimes includes photos from other folders). Same will be true for other users. This is why I changed FolderCollections to use dumb collections instead - there is no way to reliably define smart collection criteria to limit photos to those of a single corresponding folder, or at least no way that John Ellis or I could figure.

                                                                           

                                                                          Otherwise, nice job!

                                                                           

                                                                          Cheers,

                                                                          Rob

                                                                          • 34. Re: Writing a plugin to create Smart Collections
                                                                            John Spacey Level 1

                                                                            Thanks Rob.

                                                                             

                                                                             

                                                                            [i]"there is no way to reliably define smart collection criteria to limit photos to those of a single corresponding folder,"[/i]

                                                                             

                                                                            In my working catalogues ( not the test catalogue shown in the screenshots ) all my folders have unique names starting with the Date and then a 2 digit number ( for multiple shoots on the same day ). then a decription   i.e  yyyy-mm-dd_xx_description

                                                                             

                                                                            And then using smart collections which with a rule:  "Folder -> Contains All - > yyyy-mm-dd_xx_description" you always ensure you only get photos from that folder

                                                                            • 35. Re: Writing a plugin to create Smart Collections
                                                                              areohbee Level 5

                                                                              Right-o: unique folder names will do it. And, I may resort to unique folder names at some point, just for this reason (assuming Adobe does not robusten the SDK enough come Lr5). Just thought you should know, in case you plan on making this plugin available to others...

                                                                               

                                                                              Cheers,

                                                                              Rob

                                                                              • 36. Re: Writing a plugin to create Smart Collections
                                                                                John Spacey Level 1

                                                                                It would be nice if the Object ID of the folder was available to Smart Collections.   After all this would allow the user to rename a folder and without hving to rename any relevantSmart collection rules