aboutsummaryrefslogtreecommitdiffstats
path: root/libical/src/python/Component.py
diff options
context:
space:
mode:
Diffstat (limited to 'libical/src/python/Component.py')
-rw-r--r--libical/src/python/Component.py287
1 files changed, 208 insertions, 79 deletions
diff --git a/libical/src/python/Component.py b/libical/src/python/Component.py
index f4399f6c20..41ef7419db 100644
--- a/libical/src/python/Component.py
+++ b/libical/src/python/Component.py
@@ -26,29 +26,39 @@
#======================================================================
from LibicalWrap import *
-from types import *
-from Property import *
+from types import DictType, StringType, IntType
+from Property import Property
from Collection import *
+from Attendee import Attendee, Organizer
+from Time import Time
+from Duration import Duration
+from Period import Period
+import string
+
+WrapperNULL = None
class Component:
- def __init__(self,str=None, component_kind="ANY", ref=None):
+ def __init__(self,ref=None,kind=None):
- if ref != None:
+ if ref != None:
self._ref = ref
+ elif kind != None:
+ self._ref = icalcomponent_new(
+ icalcomponent_string_to_kind("VCALENDAR"))
+ _kind = icalcomponent_string_to_kind(kind)
+ inner = icalcomponent_new(_kind)
+
+ icalcomponent_add_component(self._ref,inner);
+
else:
- self._ref = None
- if str != None:
- self._ref = icalparser_parse_string(str)
- else:
- kind = icalenum_string_to_component_kind(component_kind)
- self._ref = icalcomponent_new(kind)
-
+ raise "Could not construct component of kind" + kind
+
self.cached_props = {}
+ self.cached_comps = {}
def __del__(self):
- if self._ref != None and \
- icalcomponent_get_parent(self._ref) != None:
+ if self._ref != None and icalcomponent_get_parent(self._ref) != WrapperNULL:
for k in self.cached_props.keys():
del self.cached_props[k]
@@ -58,10 +68,19 @@ class Component:
def _prop_from_ref(self,p):
- d_string = icallangbind_property_eval_string(p,":")
- d = eval(d_string)
+ if(p == None or p== WrapperNULL):
+ return None;
+
+ d = {}
+ d['value'] = icalproperty_get_value_as_string(p)
+ d['name'] = icalproperty_get_name(p)
+
+ propkind = icalproperty_string_to_kind(d['name'])
+ kind = icalproperty_kind_to_value_kind(propkind)
+ d['value_type'] = icalvalue_kind_to_string(kind)
d['ref'] = p
-
+
+
if not self.cached_props.has_key(p):
if d['value_type'] == 'DATE-TIME' or d['value_type'] == 'DATE':
@@ -85,7 +104,7 @@ class Component:
p = icallangbind_get_first_property(self._ref,type)
- if p !='NULL':
+ if p !=WrapperNULL:
self._prop_from_ref(p)
prop = self.cached_props[p]
return prop
@@ -102,8 +121,9 @@ class Component:
p = icallangbind_get_first_property(self._ref,type)
- while p !='NULL':
- self._prop_from_ref(p)
+ while p !=WrapperNULL and p != None:
+
+ self._prop_from_ref(p) # Puts property in self.cached_props
prop = self.cached_props[p]
props.append(prop)
p = icallangbind_get_next_property(self._ref,type)
@@ -122,12 +142,12 @@ class Component:
s = str(prop)
prop_p = icalproperty_new_from_string(s)
- if prop_p == 'NULL':
+ if prop_p == WrapperNULL:
raise "Bad property string: " + s
prop.ref(prop_p)
- if icalproperty_get_parent(prop_p)=='NULL':
+ if icalproperty_get_parent(prop_p)==WrapperNULL:
icalcomponent_add_property(self._ref, prop_p)
elif icalproperty_get_parent(prop_p) != self._ref:
raise "Property is already a child of another component"
@@ -143,16 +163,48 @@ class Component:
def components(self,type='ANY'):
comps = []
+ kind = icalcomponent_string_to_kind(type)
+ c = icalcomponent_get_first_component(self._ref,kind);
+
+ while c != WrapperNULL and c != None:
+
+ if not self.cached_comps.has_key(c):
+
+ self.cached_comps[c] = Component(c)
+
+ comp = self.cached_comps[c]
+ comps.append(comp)
+ c = icalcomponent_get_next_component(self._ref,kind);
+
return comps
- def add_component(self, componentObj):
- "Adds a child component."
- pass
+ def inner_component(self):
+ inner = icalcomponent_get_inner(self._ref)
+
+ if inner == WrapperNULL and inner != None:
+ return None
- def remove_component(self, component):
+ return NewComponent(inner)
+
+ def add_component(self, comp):
+ "Adds a child component."
+
+ if not isinstance(comp,Component):
+ raise ValueError("Expected a Component")
+
+ if icalcomponent_get_parent(comp._ref) != WrapperNULL:
+ raise "Failed to add child component. Child already has a parent";
+
+ icalcomponent_add_component(self._ref,comp._ref)
+
+ def remove_component(self, comp):
"Removes a child component"
- pass
+
+ if not isinstance(comp,Component):
+ raise ValueError("Expected a Component")
+
+ icalcomponent_remove_component(self._ref,comp._ref)
def as_ical_string(self):
return self.__str__()
@@ -161,32 +213,72 @@ class Component:
return icalcomponent_as_ical_string(self._ref)
+ def ref(self):
+ """ Return the internal reference to the libical icalproperty """
+ return self._ref
+
+def CloneComponent(c):
+ "Clones a string or C icalcomponent into the right component object."
+
+ wasStr=0 # Were we passed a string or an icalcomponent?
+
+ if isinstance(c, Component):
+ comp = icalparser_parse_string(c.as_ical_string())
+ elif isinstance (c, StringType) and string.find(c,"icalcomponent") == -1:
+ comp = icalparser_parse_string(c)
+ else:
+ comp = c
+
+ if comp == None or comp == WrapperNULL:
+ raise ValueError("Expected a libical reference or an iCal string")
+
+ kind = icalcomponent_isa(comp)
+ kindStr = icalcomponent_kind_to_string(kind)
+
+ if kindStr == 'VCALENDAR':
+ inner = icalcomponent_get_inner(comp)
+ kind = icalcomponent_isa(inner)
+ kindStr = icalcomponent_kind_to_string(kind)
+
+ if kindStr == 'VEVENT':
+ newComp = Event(comp)
+ elif kindStr == 'VTODO':
+ newComp = Todo(comp)
+ elif kindStr == 'VJOURNAL':
+ newComp = Journal(comp)
+ else:
+ newComp = Component(comp)
+
+ # I don't think I need to free the component created when passed a string,
+ # as it wasn't created with a _new function.
+
+ return newComp
-def NewComponent(comp):
+def NewComponent(c):
"Converts a string or C icalcomponent into the right component object."
wasStr=0 # Were we passed a string or an icalcomponent?
- if isinstance (comp, StringType):
- compStr = comp
- comp = icalparser_parse_string(comp)
- wasStr=1
+ if isinstance (c, StringType) and string.find(c,"icalcomponent") == -1:
+ comp = icalparser_parse_string(c)
else:
- compStr = icalcomponent_as_ical_string(comp)
+ comp = c
+
+ if comp == None or comp == WrapperNULL:
+ raise ValueError("Expected a libical reference or an iCal string")
kind = icalcomponent_isa(comp)
- kindStr = icalenum_component_kind_to_string(kind)
- # Do I need to free kind? (I think not).
+ kindStr = icalcomponent_kind_to_string(kind)
if kindStr == 'VEVENT':
- newComp = Event(compStr)
+ newComp = Event(comp)
elif kindStr == 'VTODO':
- newComp = Todo(compStr)
+ newComp = Todo(comp)
elif kindStr == 'VJOURNAL':
- newComp = Journal(compstr)
+ newComp = Journal(comp)
else:
- newComp = Component(compStr)
+ newComp = Component(comp)
# I don't think I need to free the component created when passed a string,
# as it wasn't created with a _new function.
@@ -196,9 +288,16 @@ def NewComponent(comp):
class GenericComponent(Component):
- def __init__(self):
-
- # Component.__init__(self, str) # Call from subclasses
+ def __init__(self,ref=None,kind=None):
+
+ if ref != None:
+ Component.__init__(self, ref=ref) # Call from subclasses
+ elif type != None:
+ Component.__init__(self, kind=kind) # Call from subclasses
+ else:
+ raise ValueError("Expected either a icalcomponent reference or a kind string")
+
+
self._recurrence_set=None
def _singular_property(self, name, value_type, value=None,
@@ -208,14 +307,23 @@ class GenericComponent(Component):
This is a constructor method for properties without a strictly defined
object."""
- curr_properties = self.properties(name)
+ # Depending on the property name, this routine will either
+ # operate on the VCALENDAR container or on the inner VEVENT,
+ # VTODO, or VJOURNAL
+
+ if name in ['METHOD','PRODID','CALSCALE','VERSION']:
+ comp = self
+ else:
+ comp = self.inner_component()
+
+ curr_properties = comp.properties(name)
# Get the value
if value==None:
if len(curr_properties) == 0:
return None
elif len(curr_properties) == 1:
- return curr_properties[0].value()
+ return curr_properties[0]
else:
raise ValueError, "too many properties of type %s" % propType
@@ -223,7 +331,7 @@ class GenericComponent(Component):
else:
# Check if value is in enumerated_values
if enumerated_values:
- value = upper(value)
+ value = string.upper(value)
if value not in enumerated_values:
raise ValueError, "%s is not one of %s" \
% (value, enumerated_values)
@@ -235,6 +343,8 @@ class GenericComponent(Component):
if property_obj == Time:
p = Time(value, name)
## p.value_type(value_type)
+ elif property_obj == Duration:
+ p = Duration(value)
else:
p = property_obj()
## p.value_type(value_type)
@@ -248,12 +358,15 @@ class GenericComponent(Component):
p.value(value)
if len(curr_properties) == 1:
- self.remove_property(curr_properties[0])
+ comp.remove_property(curr_properties[0])
elif len(curr_properties) > 1:
raise ValueError, "too many properties of type %s" % propType
- self.add_property(p)
-
+ comp.add_property(p)
+
+ # METHOD, PRODID, CALSCALE and VERSION are properties of the
+ # VCALENDAR, not the inner component
+
def method(self, v=None):
"Sets or returns the value of the METHOD property."
return self._singular_property("METHOD", "TEXT", v)
@@ -266,10 +379,20 @@ class GenericComponent(Component):
"Sets or returns the value of the CALSCALE property."
return self._singular_property("CALSCALE", "TEXT", v)
+ def version(self, v=None):
+ "Sets or returns the value of the Version property."
+ return self._singular_property("VERSION", "TEXT", v)
+
+ # The remaining properties are all in the inner component
+
+ def clone(self):
+ "Returns a copy of the object."
+ return CloneComponent(self)
+
def class_prop(self, v=None): # Class is a reserved word
"Sets or returns the value of the CLASS property."
if v!=None:
- v = upper(v)
+ v = string.upper(v)
return self._singular_property('CLASS', 'TEXT', v)
def created(self, v=None):
@@ -313,10 +436,10 @@ class GenericComponent(Component):
"""Sets or returns the value of the LAST-MODIFIED property.
Usage:
- lastmodified(time_obj) # Set the value using a Time object
- lastmodified('19970101T123000Z')# Set using an iCalendar string
- lastmodified(982362522) # Set using seconds
- lastmodified() # Return an iCalendar string
+ last_modified(time_obj) # Set the value using a Time object
+ last_modified('19970101T123000Z')# Set using an iCalendar string
+ last_modified(982362522) # Set using seconds
+ last_modified() # Return an iCalendar string
"""
return self._singular_property("LAST-MODIFIED", "DATE-TIME", v, Time)
@@ -389,7 +512,7 @@ class GenericComponent(Component):
"""
if values!=None:
for alarm in values:
- self.addComponent(alarm)
+ self.add_component(alarm)
else:
return ComponentCollection(self, self.components('VALARM'))
@@ -401,6 +524,8 @@ class GenericComponent(Component):
property_obj=None):
"Processes set/get for Properties that can have multiple instances."
+ comp = self.inner_component()
+
# Set value
if values!=None:
if not isinstance(values, TupleType) \
@@ -408,8 +533,8 @@ class GenericComponent(Component):
raise TypeError, "%s is not a tuple or list."
# Delete old properties
- for p in self.properties(name):
- self.remove_property(p)
+ for p in comp.properties(name):
+ comp.remove_property(p)
for v in values:
if property_obj: # Specialized properties
@@ -419,16 +544,15 @@ class GenericComponent(Component):
else: # Use existing object
new_prop = v
else: # Generic properties
- new_prop= Property()
- new_prop.name(name)
+ new_prop=Property(name)
# new_prop.value_type(value_type)
new_prop.value(v)
- self.add_property(new_prop)
+ comp.add_property(new_prop)
# Get value
else:
- return Collection(self, self.properties(name))
+ return Collection(self, comp.properties(name))
def attachments(self, values=None):
"""Sets or returns a Collection of Attach properties.
@@ -490,25 +614,26 @@ class GenericComponent(Component):
return self._multiple_properties('CONTACT', 'TEXT', value)
def related_tos(self, value=None):
- "Sets or returns a Collectoin of RELATED-TO properties."
+ "Sets or returns a Collection of RELATED-TO properties."
return self._multiple_properties('RELATED-TO', 'TEXT', value)
+ def x_properties(self, name, value=None):
+ "Sets or returns a Collection of X- properties."
+ return self._multiple_properties(name, 'TEXT', value)
class Event(GenericComponent):
"The iCalendar Event object."
- def __init__(self, str=None):
- Component.__init__(self, str, "VEVENT")
- GenericComponent.__init__(self)
+ def __init__(self,ref=None):
+ if ref != None:
+ GenericComponent.__init__(self, ref=ref)
+ else:
+ GenericComponent.__init__(self, kind='VEVENT')
def component_type(self):
"Returns the type of component for the object."
return "VEVENT"
- def clone(self):
- "Returns a copy of the object."
- return Event(self.asIcalString())
-
def dtend(self, v=None):
"""Sets or returns the value of the DTEND property.
@@ -541,7 +666,7 @@ class Event(GenericComponent):
"""
if v != None:
- dtend = self.properites('DTEND')
+ dtend = self.properties('DTEND')
for d in dtend:
self.remove_property(d) # Clear DTEND properties
return self._singular_property("DURATION", "DURATION", v, Duration)
@@ -601,14 +726,17 @@ class Event(GenericComponent):
class Todo(GenericComponent):
"The iCalendar TODO component."
+ def __init__(self,ref=None):
+ if ref != None:
+ GenericComponent.__init__(self, ref=ref)
+ else:
+ GenericComponent.__init__(self, kind='VTODO')
+
+
def component_type(self):
"Returns the type of component for the object."
return "VTODO"
- def clone(self):
- "Returns a copy of the object."
- return Todo(self.asIcalString())
-
def completed(self, value=None):
return self._singular_property('COMPLETED', 'DATE-TIME', value, Time)
@@ -627,7 +755,7 @@ class Todo(GenericComponent):
def status(self, value=None):
if value!=None:
- value=upper(value)
+ value=string.upper(value)
ok_values = ('NEEDS-ACTION', 'COMPLETED', 'IN-PROCESS', 'CANCELLED')
return self._singular_property('STATUS', 'TEXT', value,
enumerated_values=ok_values)
@@ -648,22 +776,23 @@ class Todo(GenericComponent):
def resources():
pass
-
class Journal(GenericComponent):
"The iCalendar JOURNAL component."
+ def __init__(self):
+ if ref != None:
+ GenericComponent.__init__(self, ref=ref)
+ else:
+ GenericComponent.__init__(self, kind='VJOURNAL')
+
def component_type(self):
"Returns the type of component for the object."
return "VJOURNAL"
- def clone(self):
- "Returns a copy of the object."
- return Journal(self.asIcalString())
-
def status(self, v=None):
if v!=None:
- v = upper(v)
+ v = string.upper(v)
ok_values=('DRAFT', 'FINAL', 'CANCELLED')
return self._singular_property('STATUS', 'TEXT', v,
enumerated_values=ok_values)