Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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().
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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
)
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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"
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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.
(string) The name.
------------------------------------------------------------------------------------------
and mentions nothing about 'an asynchronous task started using LrTasks
.' whatever that is
Stumped
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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
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()
******************************************************************************************
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
> 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
Copy link to clipboard
Copied
Oh, and what Rob said.
-Don
Copy link to clipboard
Copied
HURRAH! You guys Rock! Thanks ever so much.
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
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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
Find more inspiration, events, and resources on the new Adobe Community
Explore Now