Synchronize events between a Numbers 3 table, and Calendar

Hi,

I know how to create an event with Applescript :


set myCal to "TEST" -- calendar name

set mDate to date ("9 mai 2014")
set mEnd to date ("14 mai 2014")

tell application "Calendar"
	set myNewEvent to make new event at the end of events of calendar myCal with properties {start date:mDate, end date:mEnd, summary:"Essai1", description:"essai essai essai", allday event:true}
end tell

I’ve found here how to create events from a Number table :
https://discussions.apple.com/message/11273570#11273570
I’ve try it, but I get an error (see this topic https://discussions.apple.com/thread/6214679)

But I’m now looking for a script (or part of script) to synchronize events between a Numbers 3 table, and Calendar following those rules :

  • if events doesn’t exist in Calendar, but exist in Number, it create it in Calendar
  • if events already exist in Calendar and are exactly the same, it does nothing
  • if events already exist in Calendar and are difference, it updates from Number to Calendar
  • if events exist in Calendar but no in Number, it deletes event in Calendar

Do you have any help or link ?

:slight_smile:

What’s a Numbers 3 table? Is it in Apple’s Number’s program or something?

Yes Apple Numbers 3.2.

Here is an updated version of my old script.

--{code}
--[SCRIPT create_ical_events_from_Numbers'14]
(*
Enregistrer le script en tant que Script : create_ical_events_from_Numbers'09.scpt
déplacer le fichier ainsi créé dans le dossier
<VolumeDeDémarrage>:Users:<votreCompte>:Library:Scripts:Applications:Numbers:
Il vous faudra peut-être créer le dossier Numbers et peut-être même le dossier Applications.

Sélectionner les cellules d'une table de Numbers qui décrivent des 'events'
La table est censée contenir:
une colonne avec le résumé des événements
une colonne avec les date_heures de début
une colonne avec les date_heures de fin
Éditer la property 'leCalendrier' en fonction du nom du calendrier à alimenter.

Aller au menu Scripts , choisir Numbers puis choisir create_ical_events_from_Numbers'14

Le script crée les évènements dans iCal



--=====

L'aide du Finder explique:
L'Utilitaire AppleScript permet d'activer le Menu des scripts :
Ouvrez l'Utilitaire AppleScript situé dans le dossier Applications/AppleScript.
Cochez la case "Afficher le menu des scripts dans la barre de menus".
Sous 10.6.x,
aller dans le panneau "Général" du dialogue Préférences de l'Éditeur Applescript
puis cocher la case "Afficher le menu des scripts dans la barre des menus".

--=====

Save the script as a Script: create_ical_events_from_Numbers'14.scpt

Move the newly created file into the folder:
<startup Volume>:Users:<yourAccount>:Library:Scripts:Applications:Numbers:
Maybe you would have to create the folder Numbers and even the folder Applications by yourself.

In a table from Numbers '14,
select cells describing 'events'.
This table is supposed to embed : 
a column storing events summaries
a column storing start datetime
a column storing end datetime.

Edit the instruction defining the calendar name to fit your needs.

Go to menu Scripts, choose Numbers, then choose create_ical_events_from_Numbers'09

The script will create new events in iCal.

--=====

The Finder's Help explains:
To make the Script menu appear:
Open the AppleScript utility located in Applications/AppleScript.
Select the "Show Script Menu in menu bar" checkbox.
Under 10.6.x,
go to the General panel of AppleScript Editor's Preferences dialog box
and check the "Show Script menu in menu bar" option.

--=====

example:
event #1 18 avr. 2010 05:35 19 avr. 2010 15:35
event #2 19 avr. 2010 05:35 20 avr. 2010 15:35
event #3 20 avr. 2010 05:35 21 avr. 2010 15:35
event #4 21 avr. 2010 05:35 22 avr. 2010 15:35

--=====

Yvan KOENIG (VALLAURIS, France)
2010/03/25
2011/09/30 cosmetic changes.
2012/09/03 edited for Mountain Lion.
2014/04/14 edited for Numbers '14
*)
--=====

property leCalendrier : "Personnel"
property |nbrPropriétésParÉvènement| : 3

--=====

on run
	local leDocument, laFeuille, laTable, numLigne1, numColonne1, numLigne2, numColonne2, |lesPropriétés|, c
	set {leDocument, laFeuille, laTable, numLigne1, numColonne1, numLigne2, numColonne2} to my get_SelParams()
	set numColonne2 to numColonne1 + |nbrPropriétésParÉvènement| - 1
	tell application "Numbers" to tell document leDocument to tell sheet laFeuille to tell table laTable
		repeat with r from numLigne1 to numLigne2
			set |lesPropriétés| to {}
			repeat with c from numColonne1 to numColonne2
				copy (value of cell r of column c) to end of |lesPropriétés|
			end repeat -- with column
			(*
Now, |lesPropriétés|  contains 
- the event description
- the start date_time
- the end date_time
*)
			my makeEvent(|lesPropriétés|)
		end repeat
	end tell -- Numbers
end run

--=====

on makeEvent({|résumé|, |début|, fin})
	tell application "Calendar"
		set nbc to count (every calendar whose name = leCalendrier)
		try
			repeat with n from 1 to nbc
				make new event at the end of events of (calendar n whose name is leCalendrier) with properties {summary:|résumé|, start date:|début|, end date:fin} #, allday event:false}
			end repeat
		end try
	end tell
	(*
	tell application "Calendar"
		try
		make new event at the end of events of (first calendar  whose name is leCalendrier) with properties {summary:|résumé| , start date:|début| , end date:fin} # , allday event:false}
		end try
	end tell
	*)
end makeEvent

--=====
(*
set { leDocument, laFeuille, laTable,  numLigne1, numColonne1, numLigne2, numColonne2} to my get_SelParams()
tell application "Numbers" to tell document leDocument to tell sheet laFeuille to tell table laTable

Edited to match Numbers '14 features.
*)
on get_SelParams()
	local le_Document, la_Feuille, i, la_Table, haut_gauche, bas_droite
	local num_Ligne1, num_Colonne1, num_Ligne2, num_Colonne2
	tell application "Numbers" to tell document 1
		set le_Document to its name
		set la_Feuille to name of active sheet
		
		tell sheet la_Feuille
			set selectionAvailable to false
			repeat with i from 1 to count table
				if selection range of table i is not missing value then
					set selectionAvailable to true
					exit repeat
				end if
			end repeat
			if not selectionAvailable then
				if my parleAnglais() then
					error "No sheet has a selected table embedding at least one selected cell !"
				else
					error "Aucune feuille ne contient une table ayant au moins une cellule sélectionnée !"
				end if
			end if
			set la_Table to name of table i
			tell table la_Table
				tell selection range
					set {haut_gauche, bas_droite} to {name of first cell, name of last cell}
				end tell
				
				tell cell haut_gauche to set {num_Ligne1, num_Colonne1} to {address of its row, address of its column}
				if haut_gauche is bas_droite then
					set {num_Ligne2, num_Colonne2} to {num_Ligne1, num_Colonne1}
				else
					tell cell bas_droite to set {num_Ligne2, num_Colonne2} to {address of its row, address of its column}
				end if
			end tell -- table.
		end tell -- sheet.
		return {le_Document, la_Feuille, la_Table, num_Ligne1, num_Colonne1, num_Ligne2, num_Colonne2}
	end tell -- Numbers
end get_SelParams

--=====

on decoupe(t, d)
	local oTIDs, l
	set oTIDs to AppleScript's text item delimiters
	set AppleScript's text item delimiters to d
	set l to text items of t
	set AppleScript's text item delimiters to oTIDs
	return l
end decoupe

--=====

on parleAnglais()
	local z
	try
		set z to localized string "Cancel" from table "Numbers" in bundle path to application "Numbers"
	on error
		set z to "Cancel"
	end try
	return (z is not "Annuler")
end parleAnglais

--=====
--[/SCRIPT]
--{code}

It’s the get_SelParams() handler which required an important change because during my tests it appeared that the instructions using a filter :

tell sheet i to set maybe to the count of (tables whose selection range is not missing value)
and
tell sheet s_Name to tell (first table where selection range is not missing value)
no longer work.
Happily, the first one is no longer required thanks to the new function « active sheet ».
Would be fine if the developers may add the function « active table »

Yvan KOENIG (VALLAURIS, France) mercredi 14 mai 2014 21:13:14

On an Apple Discussion Forum somebody has posted a better get_SelParams handler.
Here it is :

on get_SelParams()
          try
                    tell application "Numbers"
                              set t to front document's active sheet's first table whose selection range's class is range
                              tell t's selection range
                                        tell first cell to set {firstRowNum, firstColNum} to {its row'saddress, its column's address}
                                        tell last cell to set {lastRowNum, lastColNum} to {its row'saddress, its column's address}
                              end tell
                              return {front document's name, t's parent's name, t's name,firstRowNum, firstColNum, lastRowNum, lastColNum}
                    end tell
          on error
                    display dialog "Problem getting values. Did you select cells?" buttons "Cancel"
          end try
end get_SelParams

Yvan KOENIG (VALLAURIS, France) jeudi 15 mai 2014 14:32:37