MyWindowController.py :  » Development » PyObjC » trunk » pyobjc » pyobjc-framework-Cocoa » Examples » AppKit » PredicateEditorSample » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » PyObjC 
PyObjC » trunk » pyobjc » pyobjc framework Cocoa » Examples » AppKit » PredicateEditorSample » MyWindowController.py
from Cocoa import *

import math

searchIndex = 0

class MyWindowController (NSWindowController):
    query = objc.ivar()
    previousRowCount = objc.ivar(objc._C_INT) 
  
    myTableView = objc.IBOutlet()
    mySearchResults = objc.IBOutlet()
    predicateEditor = objc.IBOutlet()
    progressView = objc.IBOutlet()    # the progress search view
    progressSearch = objc.IBOutlet()    # spinning gear
    progressSearchLabel = objc.IBOutlet() # search result #

    
    def dealloc(self):
  NSNotificationCenter.defaultCenter().removeObserver_(self)

    def awakeFromNib(self):
        # no vertical scrolling, we always want to show all rows
        self.predicateEditor.enclosingScrollView().setHasVerticalScroller_(False)
        
        self.previousRowCount = 3
        self.predicateEditor.addRow_(self)
        
        # put the focus in the first text field
        displayValue = self.predicateEditor.displayValuesForRow_(1).lastObject()
        if isinstance(displayValue,  NSControl):
            self.window().makeFirstResponder_(displayValue)

        # create and initalize our query
        self.query = NSMetadataQuery.alloc().init()
                                                        
        # setup our Spotlight notifications 
        nf = NSNotificationCenter.defaultCenter()
        nf.addObserver_selector_name_object_(self, 'queryNotification:', None, self.query)

        # initialize our Spotlight query, sort by contact name

        # XXX: this framework isn't wrapped yet!
        self.query.setSortDescriptors_([NSSortDescriptor.alloc().initWithKey_ascending_(
            'kMDItemContactKeywords', True)])
        self.query.setDelegate_(self)
        
        # start with our progress search label empty
        self.progressSearchLabel.setStringValue_("")
        
        return 

    def applicationShouldTerminateAfterLastWindowClosed_(self, sender):
        return True 

    def loadResultsFromQuery_(self, notif):
        results = notif.object().results()
        
        NSLog("search count = %d", len(results))
        foundResultsStr = "Results found: %d"%(len(results),)
        self.progressSearchLabel.setStringValue_(foundResultsStr)
        
        # iterate through the array of results, and match to the existing stores
        for item in results:
            cityStr = item.valueForAttribute_('kMDItemCity')
            nameStr = item.valueForAttribute_('kMDItemDisplayName')
            stateStr = item.valueForAttribute_('kMDItemStateOrProvince')
            phoneNumbers = item.valueForAttribute_('kMDItemPhoneNumbers')
            phoneStr = None
            if phoneNumbers:
                phoneStr = phoneNumbers[0]

            storePath = item.valueForAttribute_('kMDItemPath').stringByResolvingSymlinksInPath()

            # create a dictionary entry to be added to our search results array
            emptyStr = ""
            dict = {
                    'name': nameStr or "",
                    'phone': phoneStr or "",
                    'city': cityStr or "",
                    'state': stateStr or "",
                    'url': NSURL.fileURLWithPath_(storePath),
            }
            self.mySearchResults.append(dict)

    def queryNotification_(self, note):
        # the NSMetadataQuery will send back a note when updates are happening.
        # By looking at the [note name], we can tell what is happening
        if note.name() == NSMetadataQueryDidStartGatheringNotification:
            # the query has just started
            NSLog("search: started gathering")
                    
            self.progressSearch.setHidden_(False)
            self.progressSearch.startAnimation_(self)
            self.progressSearch.animate_(self)
            self.progressSearchLabel.setStringValue_("Searching...")

        elif note.name() == NSMetadataQueryDidFinishGatheringNotification:
            # at this point, the query will be done. You may recieve an update 
            # later on.
            NSLog("search: finished gathering");
                    
            self.progressSearch.setHidden_(True)
            self.progressSearch.stopAnimation_(self)
    
            self.loadResultsFromQuery_(note)

        elif note.name() == NSMetadataQueryGatheringProgressNotification:
            # the query is still gathering results...
            NSLog("search: progressing...")
                    
            self.progressSearch.animate_(self)

        elif note.name() == NSMetadataQueryDidUpdateNotification:
            # an update will happen when Spotlight notices that a file as 
            # added, removed, or modified that affected the search results.
            NSLog("search: an update happened.")
    
    # -------------------------------------------------------------------------
    #  inspect:selectedObjects
    #
    #  This method obtains the selected object (in our case for single selection,
    #  it's the first item), and opens its URL.
    # -------------------------------------------------------------------------
    def inspect_(self, selectedObjects):
        objectDict = selectedObjects[0]
        if objectDict is not None:
            url = objectDict['url']
            NSWorkspace.sharedWorkspace().openURL_(url)

    # ------------------------------------------------------------------------
    #  spotlightFriendlyPredicate:predicate
    #
    #  This method will "clean up" an NSPredicate to make it ready for Spotlight, or return nil if the predicate can't be cleaned.
    #
    #  Foundation's Spotlight support in NSMetdataQuery places the following requirements on an NSPredicate:
    #    - Value-type (always YES or NO) predicates are not allowed
    #    - Any compound predicate (other than NOT) must have at least two subpredicates
    # -------------------------------------------------------------------------
    def spotlightFriendlyPredicate_(self, predicate):
        if predicate == NSPredicate.predicateWithValue_(True) or predicate == NSPredicate.predicateWithValue_(False):
            return False

        elif isinstance(predicate, NSCompoundPredicate):

            type = predicate.compoundPredicateType()
            cleanSubpredicates = []
            for dirtySubpredicate in predicate.subpredicates():
                cleanSubpredicate = self.spotlightFriendlyPredicate_(
                    dirtySubpredicate)
                if cleanSubpredicate:
                    cleanSubpredicates.append(cleanSubpredicate)
                    
            if len(cleanSubpredicates) == 0:
                return None

            else:
                if len(cleanSubpredicates) == 1 and type != NSNotPredicateType:
                    return cleanSubpredicates[0]

                else:
                    return NSCompoundPredicate.alloc().initWithType_subpredicates_(type, cleanSubpredicates)

        else:
            return predicate

    # -------------------------------------------------------------------------
    #  createNewSearchForPredicate:predicate:withTitle
    #
    # -------------------------------------------------------------------------
    def createNewSearchForPredicate_withTitle_(self, predicate, title):
        if predicate is not None:
            self.mySearchResults.removeObjects_(
                self.mySearchResults.arrangedObjects());  # remove the old search results
                    
            # always search for items in the Address Book
            addrBookPredicate = NSPredicate.predicateWithFormat_(
                "(kMDItemKind = 'Address Book Person Data')")
            predicate = NSCompoundPredicate.andPredicateWithSubpredicates_(
                [addrBookPredicate, predicate])
               
            self.query.setPredicate_(predicate)
            self.query.startQuery()

    # --------------------------------------------------------------------------
    #  predicateEditorChanged:sender
    #
    #  This method gets called whenever the predicate editor changes.
    #  It is the action of our predicate editor and the single plate for all our updates.
    #  
    #  We need to do potentially three things:
    #    1) Fire off a search if the user hits enter.
    #    2) Add some rows if the user deleted all of them, so the user isn't left without any rows.
    #    3) Resize the window if the number of rows changed (the user hit + or -).
    # --------------------------------------------------------------------------
    @objc.IBAction
    def predicateEditorChanged_(self, sender):
        # check NSApp currentEvent for the return key
        event = NSApp.currentEvent()
        if event is None:
            return

        if event.type() == NSKeyDown:
            characters = event.characters()
            if len(characters) > 0 and characters[0] == u'\r':
                # get the predicat, which is the object value of our view
                predicate = self.predicateEditor.objectValue()
                    
                # make it Spotlight friendly
                predicate = self.spotlightFriendlyPredicate_(predicate)
                if predicate is not None:
                    global searchIndex
                    title = NSLocalizedString("Search #%ld", "Search title");
                    self.createNewSearchForPredicate_withTitle_(
                            predicate, title % searchIndex)
                    searchIndex += 1
        
        # if the user deleted the first row, then add it again - no sense leaving the user with no rows
        if self.predicateEditor.numberOfRows() == 0:
            self.predicateEditor.addRow_(self)
        
        # resize the window vertically to accomodate our views:
            
        # get the new number of rows, which tells us the needed change in height,
        # note that we can't just get the view frame, because it's currently animating - this method is called before the animation is finished.
        newRowCount = self.predicateEditor.numberOfRows()
        
        # if there's no change in row count, there's no need to resize anything
        if newRowCount == self.previousRowCount:
            return

        # The autoresizing masks, by default, allows the NSTableView to grow and keeps the predicate editor fixed.
        # We need to temporarily grow the predicate editor, and keep the NSTableView fixed, so we have to change the autoresizing masks.
        # Save off the old ones; we'll restore them after changing the window frame.
        tableScrollView = self.myTableView.enclosingScrollView()
        oldOutlineViewMask = tableScrollView.autoresizingMask()
        
        predicateEditorScrollView = self.predicateEditor.enclosingScrollView()
        oldPredicateEditorViewMask = predicateEditorScrollView.autoresizingMask()
        
        tableScrollView.setAutoresizingMask_(
                NSViewWidthSizable | NSViewMaxYMargin)
        predicateEditorScrollView.setAutoresizingMask_(
                NSViewWidthSizable | NSViewHeightSizable)
            
        # determine if we need to grow or shrink the window
        growing = (newRowCount > self.previousRowCount)
        
        # if growing, figure out by how much.  Sizes must contain nonnegative values, which is why we avoid negative floats here.
        heightDifference = abs(self.predicateEditor.rowHeight() * (newRowCount - self.previousRowCount))
        
        # convert the size to window coordinates -
        # if we didn't do this, we would break under scale factors other than 1.
        # We don't care about the horizontal dimension, so leave that as 0.
        #
        sizeChange = self.predicateEditor.convertSize_toView_(
                NSMakeSize(0, heightDifference), None)
        
        # offset our status view
        frame = self.progressView.frame()
        self.progressView.setFrameOrigin_(NSMakePoint(
            frame.origin.x, 
            frame.origin.y - self.predicateEditor.rowHeight() * (newRowCount - self.previousRowCount)))
            
        # change the window frame size:
        # - if we're growing, the height goes up and the origin goes down (corresponding to growing down).
        # - if we're shrinking, the height goes down and the origin goes up.
        windowFrame = self.window().frame()
        if growing:
            windowFrame.size.height += sizeChange.height 
            windowFrame.origin.y -= sizeChange.height
        else:
            windowFrame.size.height -= sizeChange.height 
            windowFrame.origin.y += sizeChange.height

        self.window().setFrame_display_animate_(windowFrame, True, True)
        
        # restore the autoresizing mask
        tableScrollView.setAutoresizingMask_(oldOutlineViewMask)
        predicateEditorScrollView.setAutoresizingMask_(oldPredicateEditorViewMask)

        self.previousRowCount = newRowCount  # save our new row count
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.