G’day
This first script executes quite fast, 7 seconds for 212 items, but the full script is extraordinarily slow. Anyone see why? The problem is in the ‘Select keepSelection’ line. It seems to lock up and time out.
Select any window with lots of icons, select all the icons, and run the full script to see the delay.
Any thoughts appreciated.
Regards
Santa
tell application "Finder"
set pta to path to applications folder
open pta
select every item of pta
set x to current date
set ptw to container of item 1 of pta
set keepSelection to selection as alias list
close ptw
open ptw
select keepSelection
say (current date) - x as text
end tell
-- ****************************
-- * Not Copyright, Brian Christmas *
-- * *
-- * From the Sunny Land of Oz *
-- * Version 2.0 *
-- * 21 Jan 11 *
-- * *
-- * OzSanta@gmail.com *
-- ****************************
-- AID OR Automatic Icon Distributor
-- Qsort routine from MacScripter
-- http://bbs.applescript.net/viewtopic.php?id=17340
-- Thanks to Yvan Koenig for the routine that traps
-- the Window of the Desktop that holds selected icons
-- This script works best if some approximate
-- organizing is done first, otherwise extra columns
-- may be added, especially on horizontal single lines,
-- or columns left empty if you've left vertical gaps.
-- Also note that if insufficient side margins are not allowed for when arranging a windows icons,
-- the Finder may 'shake' the window from side to side, thereby altering the icon placement.
-- It's particularly important to have a wide margin on the left when arranging,
-- otherwise the left column may not get arranged correctly, & need a second pass.
-- Feedback appreciated, especially suggestions to speed this up.
-- *******************************
-- **** Set this as minimum amount ****
-- **** allowed between columns ****
-- *******************************
property seedValue : 100
-- *******************************
-- **** Set this as minimum amount ****
-- **** of icons to offer ****
-- **** alphabet sorting ****
-- *******************************
property AlphabetMin : 20
-- *******************************
-- **** Set this to true to vertically ****
-- **** stagger labels that are closer ****
-- **** than seedvalue + 40 pixles ****
-- *******************************
property staggered : false -- set to true or false
property StaggeredCount : 0
property we_are_on_desktop : false
property IconList : {}
property IconPositions : {}
property overlapFlag : false
property FoundDisk : true
property thelist : {}
property KeepSelection : {}
property templist : {}
property currX : 0
property SmallestY : 0
property iconspacing : 0
property XYlist : {}
property theWindow : {}
on run
tell application "Finder"
set KeepDate to current date
set currX to 0
set LargestY to 0
set SmallestY to 0
set SmallestX to 0
set LargestX to 0
set overlapFlag to 0
set Xdifflist to {}
set ydiffList to {}
set columnCount to {}
set XYlist to {}
set we_are_on_desktop to false
--try
try
set tt to 0
set ttt to 0
set theWindow to window 1 as alias
tell application "System Events" to tell process "Finder"
set t to value of static text 1 of theWindow
if word 4 of t = "selected" then
set tt to word 1 of t as number
set ttt to word 3 of t as number
end if
end tell
end try
if tt > 300 and tt < 351 then
display dialog "There are " & tt & " items selected, out of " & ttt & ", and 'cause the Finder is very, very slow with large numbers of icons in windows, I'm giving you the chance to Cancel." buttons {"Continue anyway", "Cancel"}
if the button returned of the result = "Cancel" then return
end if
if tt > 350 then
display dialog "There are too many items, (" & ttt & "), 'cause the Finder is very, very slow with large numbers of icons in windows." & return & return & "So, I'm quitting!"
return
end if
set KeepSelection to the selection as alias list
set ListLength to count of KeepSelection
if ListLength = 0 then
display dialog "There are no icons selected." & return & return & "Try selecting some, and running the script again." buttons {"OK"}
return
end if
if ListLength = 1 then
display dialog "There is only one icon selected." & return & return & "Try selecting more, and running the script again." buttons {"OK"}
return
end if
set FoundDisk to false
set xx to ListLength
repeat with x from 1 to ListLength
if kind of item x of KeepSelection as text ≠"Volume" then
set xx to x
if FoundDisk then exit repeat
else
set FoundDisk to true
set KeepDisk to item x of KeepSelection
if xx < ListLength then exit repeat
end if
end repeat
set ThisItem to item xx of KeepSelection
set ptw to container of (ThisItem)
if (count of windows) > 0 then
try
if name of window 1 = "Desktop" then
tell application "Finder"
activate
set windName to get localized string "N5"
end tell
tell application "System Events" to tell application process "Finder" to tell menu bar 1 to tell menu bar item 7 to tell menu 1
set noemi to (name of every menu item)
if (noemi contains windName) then
set windStatus to false
repeat with i from 1 to count of noemi
try (* to get rid of "missing value" *)
if (name of menu item i is windName) and (value of attribute "AXMenuItemMarkChar" of menu item i is not "") then
set windStatus to true
exit repeat
end if
end try
end repeat
else
set windStatus to false
end if
end tell
if windStatus then
tell application "Finder"
try
set EnclosingFolder to container of ThisItem as string
close window "Desktop"
end try
display dialog "A Window belonging to the Desktop was frontmost, and you have selected Icons in it, and tried to organize them." & return & return & "Doing so may seriously disrupt your actual Desktop Icon arrangement." & return & return & "If you wish to organize any Desktop icons, please select them on the Desktop itself." buttons {"So, I've stopped it."}
try
open EnclosingFolder
end try
end tell
return
end if
end if
end try
end if
--- ARE WE ON THE DESKTOP?
try
set we_are_on_desktop to ((container of ThisItem as alias) is (path to desktop folder))
on error
set we_are_on_desktop to (kind of ThisItem as text = "Volume") --< only Volume icons selected
end try
if FoundDisk then --< there is at least one disk in the mix, so restart Finder
quit
delay 0.2
try
activate
end try
select disk KeepDisk
close window 1
end if
-- make array of positions
if we_are_on_desktop then
repeat with ThisItem from 1 to ListLength
set temp to desktop position of item ThisItem of KeepSelection
set {end of XYlist, end of Xdifflist, end of ydiffList} to {temp, item 1 of temp, item 2 of temp}
end repeat
else
repeat with ThisItem from 1 to ListLength
set temp to position of item ThisItem of KeepSelection
set {end of XYlist, end of Xdifflist, end of ydiffList} to {temp, item 1 of temp, item 2 of temp}
end repeat
end if
--say (current date) - KeepDate as text
set IconPositions to XYlist
set AlphaFlag to false
-- Heaps of icons? then ask!
if ListLength > (AlphabetMin - 1) then
display dialog " there are " & ListLength & " icons selected." & return & return & "Do you want to sort them alphabetically or normally?" & return & return & "(it takes a while with large numbers)" buttons {"Alphabetically please", "Normally thanks", "Cancel"}
set AlphaFlag to (the button returned of the result is "Alphabetically please")
end if
if we_are_on_desktop then
set theTotal to count of items of desktop
set IconSize to icon size of icon view options of window of desktop
set ArrangementValue to arrangement of icon view options of window of desktop
else
set TheCurrentView to current view of window 1
if TheCurrentView ≠icon view then
set the current view of window 1 to icon view
display dialog "I have reset the view of the window to 'icon view'. Do you wish to proceed?" buttons {"No", "Proceed"}
if the button returned of the result = "No" then
set the current view of window 1 to TheCurrentView
return
end if
end if
set theTotal to count of items of window 1
set IconSize to icon size of icon view options of window 1
set ArrangementValue to (arrangement of (icon view options of window 1))
end if
if ArrangementValue = not arranged then set ArrangementValue2 to "not arranged"
if ArrangementValue = snap to grid then set ArrangementValue2 to "snap to grid"
if ArrangementValue = arranged by name then set ArrangementValue2 to "arranged by name"
if ArrangementValue = arranged by modification date then set ArrangementValue2 to "arranged by modification date"
if ArrangementValue = arranged by creation date then set ArrangementValue2 to "arranged by creation date"
if ArrangementValue = arranged by size then set ArrangementValue2 to "arranged by size"
if ArrangementValue = arranged by kind then set ArrangementValue2 to "arranged by kind"
if ArrangementValue = arranged by label then set ArrangementValue2 to "arranged by label"
set AddendumText to ""
if ListLength < theTotal then set AddendumText to "You have only selected " & ListLength & " of " & theTotal & " items. The new arrangement mightn't look good because the extra icons may end up all over the place." & return & return
if ArrangementValue2 ≠"not arranged" then
display dialog "The window of the selection has a current arrangement of '" & ArrangementValue2 & "'. " & return & return & "Setting the window to 'not arranged' may have unexpected consequences for the icon arrangement." & AddendumText & "Do you want to proceed?" & return & return & "(You will be given a 'restore' option)." buttons {"Proceed", "No thanks"}
if button returned of the result = "No thanks" then return
end if
if ArrangementValue2 ≠"not arranged" then
if we_are_on_desktop then
set arrangement of icon view options of window of desktop to not arranged
else
try
set (arrangement of icon view options of window 1) to not arranged
on error errmsg
display dialog errmsg
end try
end if
end if
my Qsort(Xdifflist, 1, (length of Xdifflist))
my Qsort(ydiffList, 1, length of ydiffList)
set LargestX to last item of Xdifflist
set SmallestX to first item of Xdifflist
set LargestY to last item of ydiffList
set SmallestY to first item of ydiffList
--say (current date) - KeepDate as text
if we_are_on_desktop then
set seedValueadd to ((label position of icon view options of window of desktop) = right)
else
set seedValueadd to ((label position of icon view options of window 1) = right)
end if
-- If text is on right, double the minimum spacing
if seedValueadd = true then
set seedValue to seedValue * 2
set staggered to false --<-- no need to stagger them
end if
-- Now the guessing part, what to ListLength as column spacing?
if IconSize > seedValue then set seedValue to IconSize
set setX to seedValue
repeat with x from ((length of Xdifflist) - 1) to 1 by -1
set diff to ((item (x + 1) of Xdifflist) - (item x of Xdifflist))
if (diff > seedValue - 1) then set setX to diff
end repeat
--Now, set width between columns
-- SPECIAL CASE : Roughly all on one horizontal line, then spread 'em evenly, else
if LargestY - SmallestY < 60 and length of Xdifflist > 1 then
set columnSpaces to (LargestX - SmallestX) div (((LargestX - SmallestX) div ((length of Xdifflist) - 1)))
else
set columnSpaces to ((LargestX - SmallestX + (setX / 2)) div setX)
end if
--Only 1 column? then set columnSpace to seedvalue
if columnSpaces = 0 then
set ColumnWidth to seedValue
set columnSpaces to 1
else
if columnSpaces = 1 and (LargestX - SmallestX) < seedValue * 2 then
set ColumnWidth to (LargestX - SmallestX)
else
set ColumnWidth to (LargestX - SmallestX) / columnSpaces
if ColumnWidth < seedValue then set ColumnWidth to seedValue
-- Roughly all on one horizontal line, then spread 'em evenly
if LargestY - SmallestY < 60 then set ColumnWidth to (LargestX - SmallestX) / columnSpaces
end if
end if
if staggered and columnSpaces > 0 then set staggered to ColumnWidth < (seedValue + 40)
if staggered and columnSpaces > 1 then set LargestY to LargestY - 20
set columnCount to columnSpaces + 1
set columnCountStore to 0
set columnXstore to {0, 0}
repeat with x from 1 to columnSpaces
set end of columnXstore to {0, 0}
set columnCountStore to columnCountStore & 0
end repeat
repeat with x from 1 to columnCount
set minX to SmallestX + ((x - 1) * ColumnWidth) - (ColumnWidth / 2)
set MaxX to SmallestX + ((x - 1) * ColumnWidth) + (ColumnWidth / 2)
set item x of columnXstore to {minX, MaxX}
end repeat
repeat with ThisItem in KeepSelection
if we_are_on_desktop then
set temp to desktop position of ThisItem
else
set temp to position of ThisItem
end if
repeat with x from 1 to columnCount
set minX to item 1 of item x of columnXstore
set MaxX to item 2 of item x of columnXstore
set tempX to item 1 of temp
-- if icon falls in the range of column, add it up
if ((tempX = minX) or (tempX > minX)) and (tempX < MaxX) then
set item x of columnCountStore to ((item x of columnCountStore) + 1)
end if
end repeat
end repeat
--say (current date) - KeepDate as text
if AlphaFlag then --> Alphabet arrange set
set iconspacing to (LargestY - SmallestY) / ((ListLength / columnCount) div 1)
else
-- Now find Column with largest number of icons
set maxCount to 2 ---> to avoid division by zero if only one row
repeat with x from 1 to number of items in columnCountStore
if item x of columnCountStore > maxCount then
set maxCount to item x of columnCountStore
end if
end repeat
set iconspacing to ((LargestY - SmallestY) / (maxCount - 1))
end if
--say (current date) - KeepDate as text
if AlphaFlag then
my SortbyAlphabet(SmallestX, LargestX, SmallestY, ColumnWidth, iconspacing)
else
-- Now place Icons
-- Loop ColumnCount times....
repeat with MoveColumns from 1 to columnCount
set minX to SmallestX + ((MoveColumns - 1) * ColumnWidth) - (ColumnWidth / 2)
set MaxX to SmallestX + ((MoveColumns - 1) * ColumnWidth) + (ColumnWidth / 2)
set templist to {}
repeat with ThisItem from 1 to number of items in XYlist
set temp to item ThisItem of XYlist
set tempX to item 1 of temp
if (((tempX = minX) or (tempX > minX)) and ((tempX < MaxX) or (tempX = MaxX))) then
--Build list of icon XY positions in column
set end of templist to tempX
set end of templist to item 2 of temp
end if
end repeat
-- This is the X value of the column
set columnX to SmallestX + ((MoveColumns - 1) * ColumnWidth)
--
-- Now go and shift a column of the little bastards around!
--
my ArrangeColumn(templist, columnX, SmallestY, iconspacing, XYlist)
end repeat
end if
if FoundDisk then --< there is at least one disk in the mix, so restart Finder
quit
delay 0.2
try
activate
end try
select disk KeepDisk
close window 1
end if
if not we_are_on_desktop then
close ptw
open ptw
end if
end tell
--say (current date) - KeepDate as text
tell application "Finder"
if we_are_on_desktop then
repeat with SelectDisk in KeepSelection
tell application "System Events" to tell process "Finder"
try
select image (name of SelectDisk) of group 1 of scroll area 1
end try
end tell
end repeat
else
with timeout of 600 seconds
select KeepSelection -- <<<<<<<<<<<<<<<<<<<<<<<<<<< The problem is here!
end timeout
end if
--say (current date) - KeepDate as text
display dialog "Restore?" & return & return & "Is this arrangement satisfactory?" buttons {"Yes", "No"}
if button returned of the result = "No" then
if we_are_on_desktop then
repeat with x from 1 to ListLength
set desktop position of item x of KeepSelection to item x of IconPositions
end repeat
if FoundDisk then --< there is at least one disk in the mix, so restart Finder
quit
delay 0.2
try
activate
end try
select disk KeepDisk
close window 1
end if
if ArrangementValue2 ≠"not arranged" then set arrangement of icon view options of window of desktop to ArrangementValue
else
if ArrangementValue2 ≠"not arranged" then
set (arrangement of icon view options of window 1) to ArrangementValue
else
repeat with x from 1 to ListLength
set position of item x of KeepSelection to item x of IconPositions
end repeat
end if
end if
if not we_are_on_desktop then
close ptw
open ptw
end if
end if
(*on error errmsg
display dialog errmsg
end try*)
say "finished"
end tell
end run
-- =============================================================
on ArrangeColumn(templist, currX, SmallestY, iconspacing, XYlist)
tell application "Finder"
try
-- Start with a Y seed position, to overcome
-- problem with 1 entry not seen as an item
set ylist to {0}
--
-- Now make list of Y positions
repeat with Cycle from 1 to number of items in XYlist
set temp to item Cycle of XYlist
set ThisItem to item Cycle of KeepSelection
if temp is in templist then
set ylist to ylist & item 2 of temp
end if
end repeat --
-- Sort Y positions
my Qsort(ylist, 1, length of ylist)
--
-- Now position each
--display dialog number of items in XYlist as text
repeat with Cycle from 1 to number of items in XYlist
set thisItemTwo to item Cycle in KeepSelection
set temp to item Cycle of XYlist
if we_are_on_desktop then
if temp is in templist then
set tempY to item 2 of temp
repeat with countdown from 2 to (number of items in ylist)
if item countdown of ylist = tempY then
set currY to SmallestY + ((countdown - 2) * iconspacing)
set item countdown of ylist to "Done"
exit repeat
end if
end repeat
set desktop position of thisItemTwo to {currX, currY + StaggeredCount}
end if
else
if temp is in templist then
set tempY to item 2 of temp
repeat with countdown from 2 to (number of items in ylist)
if item countdown of ylist = tempY then
set currY to SmallestY + ((countdown - 2) * iconspacing)
set item countdown of ylist to "Done"
exit repeat
end if
end repeat
set position of thisItemTwo to {currX, currY + StaggeredCount}
end if
end if
end repeat
if staggered then
if StaggeredCount = 0 then
set StaggeredCount to 20
else
set StaggeredCount to 0
end if
end if
on error errmsg
display dialog errmsg
end try
end tell
end ArrangeColumn
on SortbyAlphabet(SmallestX, LargestX, SmallestY, ColumnWidth, iconspacing)
tell application "Finder"
try
set templist to {}
-- First, sort list of icons alphabetically
set xx to length of KeepSelection
repeat with x from 1 to xx
set end of templist to name of item x of KeepSelection
end repeat
my Qsort(templist, 1, xx)
set iconPos to 1
set Xwidth to LargestX - SmallestX + ColumnWidth
if staggered then set staggered to ColumnWidth < (seedValue + 40)
repeat with ThisItem in KeepSelection
set tempName to name of ThisItem
repeat with mainCount from 1 to xx
if tempName = item mainCount of templist then
set farRightX to ((mainCount - 1) * ColumnWidth)
set numberofRows to ((farRightX) / (Xwidth)) div 1
set Xposition to SmallestX + (farRightX - (numberofRows * Xwidth))
set yposition to SmallestY + ((numberofRows) * iconspacing)
set columntemp to (((Xposition - SmallestX) / ColumnWidth) + 0.5) div 1
if staggered then
set StaggeredCount to 0
if (columntemp mod 2) = 1 then set StaggeredCount to 20
end if
if we_are_on_desktop then
set desktop position of ThisItem to {Xposition, yposition + StaggeredCount}
else
set position of ThisItem to {Xposition, yposition + StaggeredCount}
end if
exit repeat
end if
end repeat
end repeat
end try
end tell
end SortbyAlphabet
to Qsort(array, leftEnd, rightEnd) -- Hoare's QuickSort Algorithm
script A
property L : array
end script
set {i, j} to {leftEnd, rightEnd}
set v to item ((leftEnd + rightEnd) div 2) of A's L -- pivot in the middle
repeat while (j > i)
repeat while (item i of A's L < v)
set i to i + 1
end repeat
repeat while (item j of A's L > v)
set j to j - 1
end repeat
if (not i > j) then
tell A's L to set {item i, item j} to {item j, item i} -- swap
set {i, j} to {i + 1, j - 1}
end if
end repeat
if (leftEnd < j) then Qsort(A's L, leftEnd, j)
if (rightEnd > i) then Qsort(A's L, i, rightEnd)
end Qsort
Model: 27" iMac
Browser: Safari 533.19.4
Operating System: Mac OS X (10.6)