class FilteredCollection(SingleSourceWrapperCollection): """ A ContentCollection which is the result of applying a boolean predicate to every item of another ContentCollection. The C{source} attribute contains the ContentCollection instance to be filtered. The C{filterExpression} attribute is a string containing a Python expression. If the expression returns C{True} for an item in the C{source} it will be in the FilteredCollection. The C{filterAttributes} attribute is a list of attribute names (Strings), which are accessed by the C{filterExpression}. Failure to provide this list will result in missing notifications. """ filterExpression = schema.One(schema.Text) filterMethod = schema.One(schema.Tuple) filterAttributes = schema.Sequence(schema.Importable, initialValue=[]) def _sourcesChanged_(self, op): source = self.source if source is None: s = EmptySet() else: attrs = tuple(set(self.filterAttributes)) if hasattr(self, 'filterExpression'): s = ExpressionFilteredSet(source, self.filterExpression, attrs) else: s = MethodFilteredSet(source, self.filterMethod, attrs) setattr(self, self.__collection__, s) return s
class CalendarPrefs(Preferences): """ Calendar preferences - there should be a single global instance of this object accessible at:: prefs = schema.ns('osaf.framework.blocks.calendar', view).calendarPrefs """ hourHeightMode = schema.One(CalendarHourMode, defaultValue="visibleHours", doc="Chooses which mode to use when setting " "the hour height.\n" "'visibleHours' means to show exactly the " "number of hours in self.visibleHours\n" "'pixelSize' means it should be exactly the " "pixel size in self.hourPixelSize\n" "'auto' means to base it on the size of the " "font used for drawing") visibleHours = schema.One(schema.Integer, defaultValue=10, doc="Number of hours visible vertically " "when hourHeightMode is 'visibleHours'") hourPixelSize = schema.One(schema.Integer, defaultValue=40, doc="An exact number of pixels for the hour") def getHourHeight(self, windowHeight, fontHeight): if self.hourHeightMode == "visibleHours": return windowHeight / self.visibleHours elif self.hourHeightMode == "pixelSize": return self.hourPixelSize else: return (fontHeight + 8) * 2
class BaseConduit(Conduit): sharePath = schema.One( schema.Text, initialValue=u"", doc="The parent 'directory' of the share", ) shareName = schema.One( schema.Text, initialValue=u"", doc="The 'directory' name of the share, relative to 'sharePath'", ) schema.initialValues(shareName=lambda self: unicode(UUID()), ) # TODO: see if this is used anymore: def isAttributeModifiable(self, item, attribute): share = self.share if utility.isSharedByMe(share) or share.mode in ('put', 'both'): return True # In old style shares, an attribute isn't modifiable if it's one # of the attributes shared for this item in this share for attr in item.getBasedAttributes(attribute): if attr in share.getSharedAttributes(item.itsKind): return False return True
class GDataAccount(sharing.SharingAccount): accountProtocol = schema.One(initialValue='GData') accountType = schema.One(initialValue='SHARING_GDATA') def subscribe(self, url): share = sharing.Share(itsView=self.itsView) conduit = GDataConduit(itsParent=share, account=self, url=url, translator=sharing.SharingTranslator) share.conduit = conduit share.get() return share.contents def publish(self, collection, activity=None, filters=None, overwrite=False): # Not implemented raise sharing.SharingError("Publishing to Google not yet supported") def getCalendars(self): service = getService(self.username, waitForDeferred(self.password.decryptPassword())) feed = service.GetCalendarListFeed() for entry in feed.entry: yield (entry.title.text, entry.GetAlternateLink().href, entry.access_level.value, entry.color.value)
class Resource(schema.Item): """ The web resource Kind. Resources are a twisted.web concept (see "Resource Objects" within this page: http://www.twistedmatrix.com/documents/current/howto/using-twistedweb ). A resource is a python class which handles HTTP requests and returns an HTML string. For example, if you want your web server to send all HTTP requests for the location /xyzzy to be handled by a custom resource, define a resource item, set its location attribute to "/xyzzy", its resourceClass to "yourpackage.yourmodule. yourresource", and assign the server attribute to the desired server. """ location = schema.One(schema.String, displayName="Location") server = schema.One(Server, displayName="Server", initialValue=None, inverse=Server.resources) resourceClass = schema.One(schema.Class, displayName="Resource Class", initialValue=None) def getResource(self): return self.resourceClass()
class Resource(schema.Item): """ The web resource Kind. Resources are a twisted.web concept (see "Resource Objects" within this page: http://www.twistedmatrix.com/documents/current/howto/using-twistedweb ). A resource is a python class which handles HTTP requests and returns an HTML string. For example, if you want your web server to send all HTTP requests for the location /xyzzy to be handled by a custom resource, define a resource item, set its location attribute to "/xyzzy", its resourceClass to "yourpackage.yourmodule. yourresource", and assign the server attribute to the desired server. """ location = schema.One(schema.Text) server = schema.One(Server, initialValue=None, inverse=Server.resources) autoView = schema.One( schema.Boolean, initialValue=True, doc="Resouce should automatically create a private view, refresh() " "before rendering, and commit() afterwards") resourceClass = schema.One(schema.Class, initialValue=None) def getResource(self): return self.resourceClass()
class Directory(schema.Item): """ The web directory Kind. Defining instances of Directory, and associating them with a server is a way to "graft" a different file system directory into the server's document tree. For example if you want HTTP requests for the /images/ location to not be served from the server's docroot/images directory, but rather from some other directory, you can define a Directory item with location of "/images" and path of relativepath/to/your/images/ and set its server attribute to a web server item. """ location = schema.One(schema.Text) path = schema.One(schema.Text, ) module = schema.One( schema.Text, doc="In order to find the filesystem directory to associate with " "this Directory resource, we need to know the python module " "(dotted name) the resource came from. Set it in this attribute. " "The filesystem directory the module lives in will be determined " "and then the 'path' attribute is relative to that directory.") server = schema.One(Server, initialValue=None, inverse=Server.directories)
class ModifyContentsEvent(BlockEvent): items = schema.Sequence(schema.Item, initialValue=[]) operation = schema.One(operationType, initialValue='add') copyItems = schema.One(schema.Boolean, initialValue=True) selectFirstItem = schema.One(schema.Boolean, initialValue=False) disambiguateItemNames = schema.One(schema.Boolean, initialValue=False) schema.addClouds(copying=schema.Cloud(byRef=[items]))
class PendingReminderEntry(schema.Item): """ A C{PendingReminderEntry} represents a reminder that has fired for some item, but has not yet been dismissed by the user. (In other words, for user-visible reminders, this what would be shown in some kind of dialog). This class is also used to implement "snooze": when the user snoozes a reminder, the 'when' of the corresponding PendingReminderEntry is updated to the new 'wakeup' time; it's up to client code to avoid displaying the entry till that time rolls around. """ item = schema.One( schema.Item, doc="The Item this reminder entry pertains to", ) when = schema.One( schema.DateTimeTZ, doc="When the reminder should fire for this Item", ) reminder = schema.One() snoozed = schema.One( schema.Boolean, doc="Has this item ever been snoooooozed?", defaultValue=False, )
class Note(items.ContentItem): ## ## Attribute declarations ## # ensure that the displayName carries over schema.kindInfo(displayName="Note") # temporarily make this a real attribute instead of a redirection, # because we want don't want to redirect this anywhere who = schema.One(schema.String, initialValue="") # redirections about = schema.One(redirectTo="displayName") date = schema.One(redirectTo="createdOn") def InitOutgoingAttributes(self): """ Init any attributes on ourself that are appropriate for a new outgoing item. """ try: super(Note, self).InitOutgoingAttributes() except AttributeError: pass self.processingStatus = 'processing' def getAnyAbout(self): """ Get any non-empty definition for the "about" attribute. """ return self.displayName def getAnyDate(self): """ Get any non-empty definition for the "date" attribute. """ return self.createdOn def getAnyWho(self): """ Get any non-empty definition for the "who" attribute. """ raise AttributeError def getAnyWhoFrom(self): """ Get any non-empty definition for the "whoFrom" attribute. """ return self.creator def ExportItemData(self, clipboardHandler): # Create data for this kind of item in the clipboard handler # The data is used for Drag and Drop or Cut and Paste super(Note, self).ExportItemData(clipboardHandler) # Let the clipboard handler know we've got a Note to export clipboardHandler.ExportItemFormat(self, 'Note')
class MenuItem(BaseItem): menuItemKind = schema.One(menuItemKindEnumType, defaultValue='Normal') accel = schema.One(LocalizableString) icon = schema.One(schema.Text) toggleTitle = schema.One(LocalizableString) def instantiateWidget(self): kind = { "Normal": wx.ITEM_NORMAL, "Separator": wx.ID_SEPARATOR, "Check": wx.ITEM_CHECK, "Radio": wx.ITEM_RADIO }[self.menuItemKind] # Linux doesn't support checked icon menus if (wx.Platform == '__WXGTK__' and hasattr(self, "icon") and kind == wx.ITEM_CHECK): kind = wx.ITEM_NORMAL if kind == wx.ID_SEPARATOR: id = wx.ID_SEPARATOR else: id = self.getWidgetID() # if we don't give the MenuItem a label, i.e. test = " " widgets will use # the assume the id is for a stock menuItem and will fail return wxMenuItem(None, id=id, text=" ", kind=kind)
class ToolBar(Block.RectangularChild): colorStyle = schema.One(ColorStyle, defaultValue=None) toolSize = schema.One(SizeType) separatorWidth = schema.One(schema.Integer, defaultValue=5) buttons3D = schema.One(schema.Boolean, defaultValue=False) buttonsLabeled = schema.One(schema.Boolean, defaultValue=False) schema.addClouds(copying=schema.Cloud(byRef=[colorStyle])) def instantiateWidget(self): style = wx.TB_HORIZONTAL | wx.TB_MAC_NATIVE_SELECT if self.buttons3D: style |= wx.TB_3DBUTTONS else: style |= wx.TB_FLAT if self.buttonsLabeled: style |= wx.TB_TEXT return wxToolBar(self.parentBlock.widget, self.getWidgetID(), style=style) def pressed(self, itemName): toolBarItem = self.findBlockByName(itemName).widget return self.widget.GetToolState(toolBarItem.GetId()) def press(self, itemName): toolBarItem = self.findBlockByName(itemName) return self.post(toolBarItem.event, {}, toolBarItem)
class DialogPref(Preferences): """ A preference class to use for pop-up dialogs if response is not defined, then the response will be 'None' """ response = schema.One(schema.Boolean) askNextTime = schema.One(schema.Boolean, defaultValue=True)
class ContactName(items.ContentItem): "A very simple (and incomplete) representation of a person's name" firstName = schema.One(schema.String, initialValue="") lastName = schema.One(schema.String, initialValue="") contact = schema.One("Contact", inverse="contactName") schema.addClouds(sharing=schema.Cloud(firstName, lastName))
class Startup(schema.Item): """Subclass this & create parcel.xml instances for startup notifications""" invoke = schema.One( schema.String, doc="Full name of a class or function to import and run at startup") active = schema.One( schema.Boolean, doc="Set to False to disable invocation of this item at startup", initialValue=True, ) requires = schema.Sequence("Startup", doc="Startups that must run before this one", initialValue=[]) requiredBy = schema.Sequence(inverse=requires) def getTarget(self): """Import the object named by ``invoke`` and return it""" return schema.importString(self.invoke) def invokeTarget(self, target): """Run the specified startup target in the current thread""" target(self) def onStart(self): """Override this method in a subclass to receive the notification Note: you should *not* create or modify items in this method or code called from this method. If you want to do that, you probably don't want to be using a Startup item. Also note that you should not call invoke this method via super() unless you want the default behavior (i.e., importing and running the ``invoke`` attribute) to occur. """ self.invokeTarget(self.getTarget()) def _start(self, attempted, started): """Handle inter-startup ordering and invoke onStart()""" if self in started: return True elif not self.active or self in attempted: return False attempted.add(self) # prevent multiple attempts to start this item canStart = True for item in self.requires: canStart = canStart and item._start(attempted, started) if canStart: self.onStart() started.add(self) return True return False
class Share(shares.Share): repoId = schema.One(schema.UUID) remoteVersion = schema.One(schema.Long, initialValue=0L) localVersion = schema.One(schema.Long) ackPending = schema.One(schema.Boolean, initialValue=False) def sync(self, modeOverride=None, activity=None, forceUpdate=None): return self.conduit.account.sync(self)
class AutoRestorePrefs(preferences.Preferences): """ When and whether data should be restored from backup to empty the repository. """ enabled = schema.One(schema.Boolean, defaultValue=True) uptodateBackup = schema.One(schema.Boolean, defaultValue=False) nextRestore = schema.One(schema.DateTime)
class ColumnHeader(RectangularChild): """This class defines a generic ColumnHeader kind.""" # -- Attributes for ColumnHeader -- # columnHeadings = schema.Sequence(schema.Text, required=True) columnWidths = schema.Sequence(schema.Integer) proportionalResizing = schema.One(schema.Boolean) visibleSelection = schema.One(schema.Boolean) genericRenderer = schema.One(schema.Boolean) # add selection attribute? def ResizeHeader(self): for (i, width) in enumerate(self.columnWidths): if hasattr(self, "widget"): self.widget.SetItemSize(i, (width, 0)) def defaultOnSize(self, event): self.ResizeHeader() event.Skip() def instantiateWidget(self): # create widget instance as a child of the parent block's widget. wxColHeaderInstance = colheader.ColumnHeader(self.parentBlock.widget) # FYI: currently, calendar needs proportional resizing off (false), because sizing needs to be exact wxColHeaderInstance.SetAttribute( colheader.CH_ATTR_ProportionalResizing, self.proportionalResizing) # set attributes if hasattr(self, "visibleSelection"): wxColHeaderInstance.SetAttribute( colheader.CH_ATTR_VisibleSelection, self.visibleSelection) if hasattr(self, "proportionalResizing "): wxColHeaderInstance.SetAttribute( colheader.CH_ATTR_ProportionalResizing, self.proportionalResizing) if hasattr(self, "genericRenderer"): wxColHeaderInstance.SetAttribute(colheader.CH_ATTR_GenericRenderer, self.genericRenderer) # add columns. for header in self.columnHeadings: wxColHeaderInstance.AppendItem(header, wx.ALIGN_CENTER, 20, bSortEnabled=False) # set a default size-event handler (this may need to be removed) wxColHeaderInstance.Bind(wx.EVT_SIZE, self.defaultOnSize) wxColHeaderInstance.Layout() return wxColHeaderInstance
class MyKind1(pim.ContentItem): """An example content kind""" attr1 = schema.One(schema.Text) attr2 = schema.One(schema.Text) # Typical clouds include a "copying" cloud, and a "sharing" cloud schema.addClouds(sharing=schema.Cloud( literal=[attr1, attr2], byValue=[attr3], byCloud=[attr4]))
class String(schema.Item): schema.kindInfo(displayName="Container for string attribute tests") uString = schema.One(schema.UString) bString = schema.One(schema.BString) localizableString = schema.One(schema.LocalizableString) text = schema.One(schema.Text)
class ContactName(items.ContentItem): "A very simple (and incomplete) representation of a person's name" firstName = schema.One(schema.Text, initialValue=u"", indexed=True) lastName = schema.One(schema.Text, initialValue=u"", indexed=True) contact = schema.One() schema.addClouds( sharing = schema.Cloud( literal = [firstName, lastName] ) )
class TaskEventExtraMixin(items.ContentItem): """ Task Event Extra Mixin is the bag of attributes that appears when you have an Item that is both a Task and a CalendarEvent. We only instantiate these Items when we "unstamp" an Item, to save the attributes for later "restamping". """ schema.kindInfo( displayName = "Task Event Extra Mixin Kind", description = "The attributes specific to an item that is both a task and an " "event. This is additional 'due by' information. " ) dueByDate = schema.One( schema.DateTime, displayName = 'Due by Date', doc = 'The date when a Task Event is due.', ) dueByRecurrence = schema.Sequence( 'osaf.pim.calendar.Calendar.RecurrencePattern', displayName = 'Due by Recurrence', doc = 'Recurrence information for a Task Event.', ) dueByTickler = schema.One( schema.DateTime, displayName = 'Due by Tickler', doc = 'The reminder information for a Task Event.', ) def InitOutgoingAttributes (self): """ Init any attributes on ourself that are appropriate for a new outgoing item. """ try: super(TaskEventExtraMixin, self).InitOutgoingAttributes () except AttributeError: pass TaskEventExtraMixin._initMixin (self) # call our init, not the method of a subclass def _initMixin (self): """ Init only the attributes specific to this mixin. Called when stamping adds these attributes, and from __init__ above. """ # default the dueByDate to the task's dueDate try: self.dueByDate = self.dueDate except AttributeError: pass
class PhotoCollection(pim.ListCollection): """ A ListCollection of FlickrPhotos """ userName = schema.One(schema.Text, initialValue=u'') tag = schema.One(Tag, initialValue=None) fillInBackground = schema.One(schema.Boolean, defaultValue=False) def fillCollectionFromFlickr(self, view, n=16, apiKey=None): """ Fills the collection with photos from the flickr website. """ if apiKey: flickr.setLicense(apiKey) if self.userName: flickrUserName = flickr.people_findByUsername( self.userName.encode('utf8')) flickrPhotos = flickr.people_getPublicPhotos(flickrUserName.id, n) elif self.tag: flickrPhotos = flickr.photos_search(tags=self.tag, per_page=n, sort="date-posted-desc") else: assert (False, "we should have either a userName or tag") # flickrPhotosCollection is a collection of all FlickrPhotos. It has # an index named flickerIDIndex which indexes all the photos by # their flickrID which makes it easy to quickly lookup any photo by # index. flickrPhotosCollection = schema.ns('flickr', view).flickrPhotosCollection for flickrPhoto in flickrPhotos: """ If we've already downloaded a photo with this id use it instead. """ photoUUID = flickrPhotosCollection.findInIndex( 'flickrIDIndex', # name of Index 'exact', # require an exact match # compare function lambda uuid: cmp(flickrPhoto.id, view.findValue(uuid, 'flickrID'))) if photoUUID is None: photoItem = FlickrPhoto(photo=flickrPhoto, itsView=view) else: photoItem = view[photoUUID] self.add(photoItem) view.commit()
class MenuItem (Block.Block, DynamicChild): menuItemKind = schema.One(menuItemKindEnumType, initialValue = 'Normal') accel = schema.One(schema.String, initialValue = '') event = schema.One(Block.BlockEvent) schema.addClouds( copying = schema.Cloud(byCloud = [event]) ) def instantiateWidget (self): # We'll need a dynamicParent's widget in order to instantiate try: if isinstance(self.dynamicParent.widget, wxMenu): return wxMenuItem(style=wxMenuItem.CalculateWXStyle(self)) except AttributeError: return None
class Project(ContentItem): schema.kindInfo( displayName="Project", examples=[ 'my "Housewarming Party" project', "my department's \"Move to new building\" project", "my company's \"Open Seattle Store\" project", ], description= "Users can create projects to help organize their work. Users can " "take content items (like tasks and mail messages) and assign " "them to different projects.") parentProject = schema.One( 'Project', displayName='Parent Project', doc= 'Projects can be organized into hierarchies. Each project can have one parent.', inverse='subProjects', ) subProjects = schema.Sequence( 'Project', displayName='Sub Projects', doc= 'Projects can be organized into hierarchies. Each project can have many sub-projects.', inverse='parentProject', )
class MiniCalendar(Block.RectangularChild): doSelectWeek = schema.One(schema.Boolean, initialValue=True) def __init__(self, *arguments, **keywords): super(MiniCalendar, self).__init__(*arguments, **keywords) def instantiateWidget(self): if '__WXMAC__' in wx.PlatformInfo: style = wx.BORDER_SIMPLE else: style = wx.BORDER_STATIC return wxMiniCalendar(self.parentBlock.widget, Block.Block.getWidgetID(self), style=style) def onSelectedDateChangedEvent(self, event): self.widget.setSelectedDate(event.arguments['start']) def onSelectWeekEvent(self, event): self.doSelectWeek = event.arguments['doSelectWeek'] self.widget.wxSynchronizeWidget() self.widget.Refresh() def onSelectItemEvent(self, event): self.widget.wxSynchronizeWidget() self.widget.Refresh()
class EventLoggingDispatchHook(DispatchHook): """ Class to handle event dispatches """ logging = schema.One(schema.Boolean, initialValue=False) def dispatchEvent(self, event, depth): """ Actual handler which instantiates the logger and 'logs' the event """ if not event.arguments.has_key('UpdateUI') and depth == 1: logger = getattr(self, "logger", None) if logger is None: ## cache the logger for future use self.logger = self.createLogger() self.logEvent(event) def onToggleLoggingEvent(self, event): self.logging = not self.logging hooksListItem = schema.ns('osaf.framework.blocks', self.itsView).BlockDispatchHookList dispatchHook = schema.ns(__name__, self.itsView).EventLoggingHook if self.logging: hooksListItem.hooks.insertItem(dispatchHook, None) else: hooksListItem.hooks.remove(dispatchHook) def onToggleLoggingEventUpdateUI(self, event): event.arguments['Check'] = self.logging def createLogger(self): if not os.path.isdir(logDir): os.mkdir(logDir) handler = logging.handlers.TimedRotatingFileHandler( logFile, 'midnight', 1, logFileMaxCount) handler.setFormatter(logging.Formatter('%(asctime)s %(message)s')) logger = logging.getLogger('eventLogger') logger.addHandler(handler) logger.setLevel(logging.DEBUG) return logger def logEvent(self, event): items = event.arguments.get('items', None) if items is not None and len(items) > 0: item_name = items[0].displayName else: item_name = "" collection = event.arguments.get('collection', None) if collection is not None and len(collection) > 0: collection_name = collection.displayName else: collection_name = "" self.logger.debug( "%s - %s - %s - %s" % (event.blockName, event.arguments, item_name, collection_name))
class AmazonCollection(ItemCollection): schema.kindInfo(displayName="Amazon Collection Kind") keywords = schema.One(schema.String, displayName='Keywords') myKindID = None myKindPath = "//parcels/osaf/examples/amazon/schema/AmazonCollection" def __init__(self, keywords=None, email=None, name=None, parent=None, kind=None, view=None): super(AmazonCollection, self).__init__(name, parent, kind, view) if keywords: bags = amazon.searchByKeyword(keywords) self.displayName = 'Amzn: ' + keywords elif email: results = amazon.searchWishListByEmail(email) customerName = results[0] bags = results[1] self.displayName = 'Amzn: ' + customerName else: bags = {} for aBag in bags: self.add(AmazonItem(aBag, view=view))
class ClientIdentifier(pim.ContentItem): clientID = schema.One( schema.Bytes, doc='Used to identify different running instances of Chandler') schema.initialValues( clientID=lambda self: hashlib.sha256(self.itsUUID.str16()).hexdigest())
class ApplicationPrefs(preferences.Preferences): isOnline = schema.One(schema.Boolean, defaultValue=True) backupOnQuit = schema.One( schema.Boolean, doc= 'Should we backup (export collections and settings) on quit to automate migration?' ) showTip = schema.One(schema.Boolean, initialValue=False, doc='Should we show tip of the day on launch?') tipIndex = schema.One(schema.Integer, initialValue=0, doc='Index of tip of the day to show.')