예제 #1
0
def load_dictionaries(context_ref, language_list):
    # The function is a bit picky about making sure we pass a clean NSArray with NSStrings
    langs = NSMutableArray.array()
    for x in language_list:
        langs.addObject_(NSString.stringWithString_(x))
    # The True argument is for whether the language string objects are already retained
    SFPWAContextLoadDictionaries(context_ref, langs, True)
예제 #2
0
def load_dictionaries(context_ref, language_list):
    # The function is a bit picky about making sure we pass a clean NSArray with NSStrings
    langs = NSMutableArray.array()
    for x in language_list:
        langs.addObject_(NSString.stringWithString_(x))
    # The True argument is for whether the language string objects are already retained
    SFPWAContextLoadDictionaries(context_ref, langs, True)
예제 #3
0
    def renderDailyEntries(self, results):
        getFirstContactMatchingURI = NSApp.delegate().contactsWindowController.getFirstContactMatchingURI
        self.dayly_entries = NSMutableArray.array()
        for result in results:
            display_name = None
            try:
                found_contact = self.contact_cache[result[2]]
            except KeyError:
                found_contact = getFirstContactMatchingURI(result[2], exact_match=True)
                self.contact_cache[result[2]] = found_contact

            if found_contact:
                display_name = found_contact.name
                remote_uri = '%s <%s>' % (display_name, result[2]) if '@' in result[2] else display_name
            else:
                try:
                    display_name = self.display_name_cache[result[2]]
                except KeyError:
                    remote_uri = result[2]
                else:
                    remote_uri = '%s <%s>' % (display_name, result[2]) if '@' in result[2] else display_name

            entry = NSMutableDictionary.dictionaryWithObjectsAndKeys_(result[1], "local_uri", remote_uri, "remote_uri", result[2], "remote_uri_sql", result[0], 'date', result[3], 'type', display_name, "display_name")
            self.dayly_entries.addObject_(entry)

        self.dayly_entries.sortUsingDescriptors_(self.indexTable.sortDescriptors())
        self.indexTable.reloadData()

        if self.search_uris and not self.dayly_entries:
            self.contactTable.deselectAll_(True)
예제 #4
0
    def refreshLibrary(self):
        if not self.history:
            return

        settings = SIPSimpleSettings()
        own_icon_path = settings.presence_state.icon
        selected_icon = None

        def md5sum(filename):
            md5 = hashlib.md5()
            with open(filename, 'rb') as f:
                for chunk in iter(lambda: f.read(128 * md5.block_size), b''):
                    md5.update(chunk)
            return md5.hexdigest()

        if os.path.exists(self.storage_folder):
            files = os.listdir(self.storage_folder)
        else:
            files = []
        array = NSMutableArray.array()
        knownFiles = set()
        for item in self.contentArrayController.arrangedObjects():
            knownFiles.add(str(item.objectForKey_("path")))

        seen_md5sum = {}
        i = 0
        for f in files:
            if not f.startswith('user_icon') and not f.startswith(
                    'photo') and f != 'default_user_icon.tiff':
                continue
            p = os.path.normpath(self.storage_folder + "/" + f)
            if p not in knownFiles:
                photos_folder = unicodedata.normalize('NFC',
                                                      self.storage_folder)
                filename = os.path.join(photos_folder, f)
                checksum = md5sum(filename)
                try:
                    seen_md5sum[filename]
                except KeyError:
                    seen_md5sum[filename] = checksum
                    image = NSImage.alloc().initWithContentsOfFile_(p)
                    if not image:
                        continue
                    item = NSDictionary.dictionaryWithObjectsAndKeys_(
                        image, "picture", p, "path")
                    array.addObject_(item)
                    if own_icon_path is not None and filename == str(
                            own_icon_path):
                        selected_icon = i
                    i += 1

        if array.count() > 0:
            self.contentArrayController.addObjects_(array)
            if selected_icon is not None:
                self.libraryCollectionView.setSelectionIndexes_(
                    NSIndexSet.indexSetWithIndex_(selected_icon))
예제 #5
0
 def getItemView(self):
     array = NSMutableArray.array()
     context = NSMutableDictionary.dictionary()
     context.setObject_forKey_(self, NSNibOwner)
     context.setObject_forKey_(array, NSNibTopLevelObjects)
     path = NSBundle.mainBundle().pathForResource_ofType_("AlertPanelView", "nib")
     if not NSBundle.loadNibFile_externalNameTable_withZone_(path, context, self.zone()):
         raise RuntimeError("Internal Error. Could not find AlertPanelView.nib")
     for obj in array:
         if isinstance(obj, NSBox):
             return obj
     else:
         raise RuntimeError("Internal Error. Could not find NSBox in AlertPanelView.nib")
예제 #6
0
    def refreshLibrary(self):
        if not self.history:
            return

        settings = SIPSimpleSettings()
        own_icon_path = settings.presence_state.icon
        selected_icon = None
        def md5sum(filename):
            md5 = hashlib.md5()
            with open(filename,'rb') as f:
                for chunk in iter(lambda: f.read(128*md5.block_size), b''):
                    md5.update(chunk)
            return md5.hexdigest()

        if os.path.exists(self.storage_folder):
          files = os.listdir(self.storage_folder)
        else:
          files = []
        array = NSMutableArray.array()
        knownFiles = set()
        for item in self.contentArrayController.arrangedObjects():
            knownFiles.add(unicode(item.objectForKey_("path")))

        seen_md5sum = {}
        i = 0
        for f in files:
            if not f.startswith('user_icon') and not f.startswith('photo') and f != 'default_user_icon.tiff':
                continue
            p = os.path.normpath(self.storage_folder + "/" + f)
            if p not in knownFiles:
                photos_folder = unicodedata.normalize('NFC', self.storage_folder)
                filename = os.path.join(photos_folder, f)
                checksum = md5sum(filename)
                try:
                    seen_md5sum[filename]
                except KeyError:
                    seen_md5sum[filename] = checksum
                    image = NSImage.alloc().initWithContentsOfFile_(p)
                    if not image:
                        continue
                    item = NSDictionary.dictionaryWithObjectsAndKeys_(image, "picture", p, "path")
                    array.addObject_(item)
                    if own_icon_path is not None and filename == unicode(own_icon_path):
                        selected_icon = i
                    i += 1

        if array.count() > 0:
            self.contentArrayController.addObjects_(array)
            if selected_icon is not None:
                self.libraryCollectionView.setSelectionIndexes_(NSIndexSet.indexSetWithIndex_(selected_icon))
예제 #7
0
    def renderDailyEntries(self, results):
        getFirstContactMatchingURI = NSApp.delegate().contactsWindowController.getFirstContactMatchingURI
        self.dayly_entries = NSMutableArray.array()
        for result in results:
            contact = getFirstContactMatchingURI(result[2], exact_match=True)
            if contact:
                remote_uri = '%s <%s>' % (contact.name, result[2])
            else:
                remote_uri = result[2]

            entry = NSDictionary.dictionaryWithObjectsAndKeys_(result[1], "local_uri", remote_uri, "remote_uri", result[2], "remote_uri_sql", result[0], 'date', result[3], 'type')
            self.dayly_entries.addObject_(entry)

        self.dayly_entries.sortUsingDescriptors_(self.indexTable.sortDescriptors())
        self.indexTable.reloadData()

        if self.search_uris and not self.dayly_entries:
            self.contactTable.deselectAll_(True)
예제 #8
0
    def saveSettings(self):
        '''
        Save the path setting to setting file
        '''
        jsonData = NSMutableDictionary.dictionaryWithDictionary_(self.data)
        paths = NSMutableArray.array()
        for directory in self.data['paths']:
            paths.addObject_(directory.directoryToDict())

        jsonData['paths'] = paths
        data = NSJSONSerialization.dataWithJSONObject_options_error_(
            jsonData, 0, None)
        if len(data) > 0 and not data[0].writeToFile_atomically_(
                self.settingPath, True):
            alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
                "Error", "Confirm", None, None, "Save setting failed.")
            alert.runModal()
        else:
            # Notify the app to reload settings
            self.callback(*self.args)
예제 #9
0
 def load(cls):
     '''
     Load the all paths from setting file
     :return An array which contain all the directory model
     '''
     settingPath = cls.settingPath()
     fm = NSFileManager.defaultManager()
     paths = NSMutableArray.array()
     settings = NSMutableDictionary.dictionary()
     if fm.fileExistsAtPath_isDirectory_(settingPath, None)[0]:
         settingFile = NSData.dataWithContentsOfFile_(settingPath)
         jsonData = NSJSONSerialization.JSONObjectWithData_options_error_(
             settingFile, 0, None)[0]
         settings['startup'] = jsonData['startup']
         settings['api_key'] = jsonData['api_key']
         for item in jsonData['paths']:
             directory = Directory.alloc().initWithDict_(item)
             paths.addObject_(directory)
         settings['paths'] = paths
     else:
         settings['startup'] = True
         settings['api_key'] = ''
         settings['paths'] = paths
     return settings
예제 #10
0
 def resetDailyEntries(self):
     self.dayly_entries = NSMutableArray.array()
     self.indexTable.reloadData()
예제 #11
0
        if args in memo:
            return memo[args]
        else:
            memo[args] = function(*args)
            return memo[args]

    return wrapper


@memoize
def C(name):
    return objc_getClass(name)


@memoize
def S(name):
    return sel_registerName(name)


def send(obj, sel, param=None):
    return objc_msgSend(obj, sel, param)


temp_array = NSMutableArray.array()
# get the raw pointer of the class object
raw_temp_array = objc.pyobjc_id(temp_array)
# Add the db_buffer pointer to the array
result = send(raw_temp_array, S(b'addObject:'), db_buffer)
# Get the object back from the other side!
ctypes_o = temp_array[0]
예제 #12
0
from Foundation import NSMutableDictionary
from Foundation import NSMutableArray
if not PLIST_APPLICATION_INFO_LOCATION:
   print '[ERROR] Cannot find plist file %(PLIST_APPLICATION_INFO_LOCATION)'
   sys.exit(1)
application_info = NSMutableDictionary.dictionaryWithContentsOfFile_(PLIST_APPLICATION_INFO_LOCATION)
PLIST_BUNDLE_IDENTIFIER = application_info.objectForKey_('CFBundleIdentifier')
if PLIST_BUNDLE_IDENTIFIER_SUFFIX != '':
   PLIST_BUNDLE_IDENTIFIER = PLIST_BUNDLE_IDENTIFIER + PLIST_BUNDLE_IDENTIFIER_SUFFIX
PLIST_BUNDLE_VERSION = application_info.objectForKey_('CFBundleVersion')
print '[DEBUG] Bundle identifier = %(PLIST_BUNDLE_IDENTIFIER)s' % vars()
print '[DEBUG] Bundle version    = %(PLIST_BUNDLE_VERSION)s' % vars()


root = NSMutableDictionary.dictionary()
items = NSMutableArray.array()
root.setObject_forKey_(items,'items')
main_item = NSMutableDictionary.dictionary()
items.addObject_(main_item)

assets = NSMutableArray.array()
main_item['assets'] = assets

asset_item = NSMutableDictionary.dictionary()

assets.addObject_(asset_item)
asset_item['kind'] = 'software-package'
asset_item['url'] = IPA_URL

metadata = NSMutableDictionary.dictionary()
main_item['metadata'] = metadata
예제 #13
0
class AddContactController(NSObject):

    window = objc.IBOutlet()
    addButton = objc.IBOutlet()
    addressText = objc.IBOutlet()
    organizationText = objc.IBOutlet()
    nameText = objc.IBOutlet()
    groupPopUp = objc.IBOutlet()
    publicKey = objc.IBOutlet()
    defaultButton = objc.IBOutlet()
    subscribePopUp = objc.IBOutlet()
    photoImage = objc.IBOutlet()
    preferredMediaPopUpButton = objc.IBOutlet()
    addressTable = objc.IBOutlet()
    addressTypesPopUpButton = objc.IBOutlet()
    addressTableDatasource = NSMutableArray.array()
    defaultPhotoImage = None
    media_tags = {'audio': 1, 'chat': 2, 'audio+chat': 3, 'video': 4}
    autoanswerCheckbox = objc.IBOutlet()

    def __new__(cls, *args, **kwargs):
        from ContactListModel import DefaultUserAvatar
        cls.defaultPhotoImage = DefaultUserAvatar().icon
        return cls.alloc().init()

    def __init__(self, uris=[], name=None, group=None):
        NSBundle.loadNibNamed_owner_("Contact", self)
        self.window.setTitle_(NSLocalizedString("Add Contact", "Window title"))
        self.dealloc_timer = None

        self.default_uri = None
        self.preferred_media = 'audio'
        self.uris = []
        for (uri, type) in uris:
            self.uris.append(
                ContactURI(uri=uri.strip(), type=format_uri_type(type)))

        self.update_default_uri()
        self.subscriptions = {
            'presence': {
                'subscribe': True,
                'policy': 'allow'
            },
            'dialog': {
                'subscribe': False,
                'policy': 'block'
            }
        }
        self.all_groups = [
            g for g in self.groupsList if g.group is not None
            and not isinstance(g.group, VirtualGroup) and g.add_contact_allowed
        ]
        self.belonging_groups = []
        if group is not None:
            self.belonging_groups.append(group)
        self.nameText.setStringValue_(name or "")
        self.photoImage.setImage_(self.defaultPhotoImage)
        self.defaultButton.setEnabled_(False)
        self.updateSubscriptionMenus()
        self.loadGroupNames()
        self.addButton.setEnabled_(True if self.uris else False)

    @property
    def model(self):
        return NSApp.delegate().contactsWindowController.model

    @property
    def groupsList(self):
        return self.model.groupsList

    def startDeallocTimer(self):
        # workaround to keep the object alive as cocoa still sends delegate tableview messages after close
        self.dealloc_timer = NSTimer.timerWithTimeInterval_target_selector_userInfo_repeats_(
            2.0, self, "deallocTimer:", None, False)
        NSRunLoop.currentRunLoop().addTimer_forMode_(self.dealloc_timer,
                                                     NSRunLoopCommonModes)
        NSRunLoop.currentRunLoop().addTimer_forMode_(
            self.dealloc_timer, NSEventTrackingRunLoopMode)

    def deallocTimer_(self, timer):
        if self.dealloc_timer:
            self.dealloc_timer.invalidate()
            self.dealloc_timer = None
        self.all_groups = None
        self.belonging_groups = None
        self.uris = None
        self.subscriptions = None
        self.defaultPhotoImage = None

    @objc.python_method
    @run_in_gui_thread
    def handle_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

    def awakeFromNib(self):
        NotificationCenter().add_observer(self, name="BlinkGroupsHaveChanged")
        self.addressTable.tableColumnWithIdentifier_(
            "0").dataCell().setPlaceholderString_(
                NSLocalizedString("Click to add a new address",
                                  "Text placeholder"))
        self.addressTable.setDraggingSourceOperationMask_forLocal_(
            NSDragOperationGeneric, True)
        self.addressTable.registerForDraggedTypes_(
            NSArray.arrayWithObject_("dragged-row"))

    @objc.python_method
    def _NH_BlinkGroupsHaveChanged(self, notification):
        self.all_groups = list(
            g for g in self.groupsList
            if g.group is not None and not isinstance(g.group, VirtualGroup)
            and g.add_contact_allowed)
        self.loadGroupNames()

    @objc.python_method
    def runModal(self):
        rc = NSApp.runModalForWindow_(self.window)
        self.window.orderOut_(self)
        if rc == NSOKButton:
            NotificationCenter().remove_observer(self,
                                                 name="BlinkGroupsHaveChanged")
            # TODO: how to handle xmmp: uris?
            #for uri in self.uris:
            #    if uri.type is not None and uri.type.lower() == 'xmpp' and ';xmpp' not in uri.uri:
            #        uri.uri = uri.uri + ';xmpp'
            i = 0
            for uri in self.uris:
                uri.position = i
                i += 1

            contact = {
                'default_uri':
                self.default_uri,
                'uris':
                self.uris,
                'auto_answer':
                True
                if self.autoanswerCheckbox.state() == NSOnState else False,
                'name':
                str(self.nameText.stringValue()),
                'organization':
                str(self.organizationText.stringValue()),
                'groups':
                self.belonging_groups,
                'icon':
                None if self.photoImage.image() == self.defaultPhotoImage else
                self.photoImage.image(),
                'preferred_media':
                self.preferred_media,
                'subscriptions':
                self.subscriptions
            }
            return contact
        return False

    @objc.python_method
    def checkURI(self, uri):
        if checkValidPhoneNumber(uri):
            return True

        if uri.startswith(('https:', 'http:')):
            url = urllib.parse.urlparse(uri)
            if url.scheme not in ('http', 'https'):
                return False
            return True

        if not uri.startswith(('sip:', 'sips:')):
            uri = "sip:%s" % uri
        try:
            SIPURI.parse(str(uri))
        except SIPCoreError:
            return False

        return True

    @objc.python_method
    def update_default_uri(self):
        if self.default_uri:
            self.addressText.setStringValue_(self.default_uri.uri)
        else:
            if self.uris:
                self.addressText.setStringValue_(self.uris[0].uri)
            else:
                self.addressText.setStringValue_('')

        self.addButton.setEnabled_(True if self.uris else False)

    def windowShouldClose_(self, sender):
        self.startDeallocTimer()
        NSApp.stopModalWithCode_(NSCancelButton)
        return True

    @objc.python_method
    def loadGroupNames(self):
        if self.belonging_groups is None:
            return

        self.groupPopUp.removeAllItems()
        nr_groups = len(self.belonging_groups)
        if nr_groups == 0:
            title = NSLocalizedString("No Selected Groups", "Menu item")
        elif nr_groups == 1:
            title = NSLocalizedString("One Selected Group", "Menu item")
        else:
            title = NSLocalizedString("%d Selected Groups",
                                      "Menu item") % nr_groups
        self.groupPopUp.addItemWithTitle_(title)
        menu_item = self.groupPopUp.lastItem()
        menu_item.setState_(NSOffState)
        self.groupPopUp.menu().addItem_(NSMenuItem.separatorItem())
        for grp in self.all_groups:
            self.groupPopUp.addItemWithTitle_(grp.name)
            item = self.groupPopUp.lastItem()
            item.setRepresentedObject_(grp)
            menu_item = self.groupPopUp.lastItem()
            if grp in self.belonging_groups:
                menu_item.setState_(NSOnState)
            else:
                menu_item.setState_(NSOffState)

        self.groupPopUp.menu().addItem_(NSMenuItem.separatorItem())
        self.groupPopUp.addItemWithTitle_(
            NSLocalizedString("Select All", "Menu item"))
        self.groupPopUp.addItemWithTitle_(
            NSLocalizedString("Deselect All", "Menu item"))
        self.groupPopUp.addItemWithTitle_(
            NSLocalizedString("Add Group...", "Menu item"))

    @objc.IBAction
    def subscribePopUpClicked_(self, sender):
        index = self.subscribePopUp.indexOfSelectedItem()
        if index == 3:
            self.subscriptions['presence'][
                'subscribe'] = not self.subscriptions['presence']['subscribe']
        elif index == 4:
            self.subscriptions['presence'][
                'policy'] = 'allow' if self.subscriptions['presence'][
                    'policy'] == 'block' else 'block'
        elif index == 7:
            self.subscriptions['dialog'][
                'subscribe'] = not self.subscriptions['dialog']['subscribe']
        elif index == 8:
            self.subscriptions['dialog'][
                'policy'] = 'allow' if self.subscriptions['dialog'][
                    'policy'] == 'block' else 'block'
        self.updateSubscriptionMenus()

    @objc.IBAction
    def preferredMediaPopUpClicked_(self, sender):
        item = self.preferredMediaPopUpButton.selectedItem()
        try:
            self.preferred_media = next(
                (media for media in list(self.media_tags.keys())
                 if self.media_tags[media] == item.tag()))
        except StopIteration:
            self.preferred_media == 'audio'

        self.updatePreferredMediaMenus()

    @objc.python_method
    def updatePreferredMediaMenus(self):
        items = self.preferredMediaPopUpButton.itemArray()
        for menu_item in items:
            if menu_item.tag() == 1:
                menu_item.setState_(NSOnState if self.preferred_media ==
                                    'audio' else NSOffState)
            elif menu_item.tag() == 2:
                menu_item.setState_(NSOnState if self.preferred_media ==
                                    'chat' else NSOffState)
            elif menu_item.tag() == 3:
                menu_item.setState_(NSOnState if self.preferred_media in (
                    'audio+chat', 'chat+audio') else NSOffState)
            elif menu_item.tag() == 4:
                menu_item.setState_(NSOnState if self.preferred_media ==
                                    'video' else NSOffState)

        try:
            tag = self.media_tags[self.preferred_media]
        except KeyError:
            tag = 1

        self.preferredMediaPopUpButton.selectItemWithTag_(tag)

    @objc.python_method
    def updateSubscriptionMenus(self):
        self.subscribePopUp.selectItemAtIndex_(0)
        menu_item = self.subscribePopUp.itemAtIndex_(0)
        menu_item.setState_(NSOffState)

        menu_item = self.subscribePopUp.itemAtIndex_(3)
        menu_item.setState_(NSOnState if self.subscriptions['presence']
                            ['subscribe'] else NSOffState)
        menu_item = self.subscribePopUp.itemAtIndex_(4)
        menu_item.setState_(NSOnState if self.subscriptions['presence']
                            ['policy'] == 'allow' else NSOffState)

        menu_item = self.subscribePopUp.itemAtIndex_(7)
        menu_item.setState_(NSOnState if self.subscriptions['dialog']
                            ['subscribe'] else NSOffState)
        menu_item = self.subscribePopUp.itemAtIndex_(8)
        menu_item.setState_(NSOnState if self.subscriptions['dialog']['policy']
                            == 'allow' else NSOffState)

    @objc.IBAction
    def groupPopUpButtonClicked_(self, sender):
        item = sender.selectedItem()
        index = self.groupPopUp.indexOfSelectedItem()
        if index < 2:
            return

        grp = item.representedObject()
        if grp:
            if grp in self.belonging_groups:
                self.belonging_groups.remove(grp)
            else:
                self.belonging_groups.append(grp)

        else:
            menu_item = self.groupPopUp.itemAtIndex_(index)
            if menu_item.title() == NSLocalizedString("Select All",
                                                      "Menu item"):
                self.belonging_groups = self.all_groups
            elif menu_item.title() == NSLocalizedString(
                    "Deselect All", "Menu item"):
                self.belonging_groups = []
            elif menu_item.title() == NSLocalizedString(
                    "Add Group...", "Menu item"):
                self.model.addGroup()

        self.loadGroupNames()

    @objc.IBAction
    def buttonClicked_(self, sender):
        if sender.tag() == 20:  # ch icon
            panel = NSOpenPanel.openPanel()
            panel.setTitle_(
                NSLocalizedString("Select Contact Icon", "Window title"))
            if panel.runModalForTypes_(
                    NSArray.arrayWithObjects_(
                        "tiff", "png", "jpeg",
                        "jpg")) == NSFileHandlingPanelOKButton:
                path = panel.filename()
                image = NSImage.alloc().initWithContentsOfFile_(path)
                self.photoImage.setImage_(image)
        elif sender.tag() == 21:  # clear icon
            self.photoImage.setImage_(self.defaultPhotoImage)
        elif sender.tag() == 10:
            self.startDeallocTimer()
            NSApp.stopModalWithCode_(NSOKButton)
        else:
            self.startDeallocTimer()
            NSApp.stopModalWithCode_(NSCancelButton)

    @objc.IBAction
    def defaultClicked_(self, sender):
        if sender.selectedSegment() == 0:
            # Set default URI
            contact_uri = self.selectedContactURI()
            self.default_uri = contact_uri
            self.update_default_uri()
        elif sender.selectedSegment() == 1:
            # Delete URI
            row = self.addressTable.selectedRow()
            del self.uris[row]
            self.update_default_uri()
            self.addressTable.reloadData()
        row = self.addressTable.selectedRow()
        self.defaultButton.setEnabled_(row < len(self.uris))

    @objc.python_method
    def selectedContactURI(self):
        row = self.addressTable.selectedRow()
        try:
            return self.uris[row]
        except IndexError:
            return None

    def numberOfRowsInTableView_(self, table):
        return len(self.uris) + 1

    def tableViewSelectionDidChange_(self, notification):
        row = self.addressTable.selectedRow()
        self.defaultButton.setEnabled_(row < len(self.uris))

    def tableView_sortDescriptorsDidChange_(self, table, odescr):
        return

    def tableView_objectValueForTableColumn_row_(self, table, column, row):
        if row >= len(self.uris):
            return ""
        cell = column.dataCell()
        column = int(column.identifier())
        contact_uri = self.uris[row]
        if column == 0:
            return contact_uri.uri
        elif column == 1:
            return cell.indexOfItemWithTitle_(contact_uri.type or 'SIP')

    def tableView_setObjectValue_forTableColumn_row_(self, table, object,
                                                     column, row):
        cell = column.dataCell()
        column = int(column.identifier())
        if not object:
            if column == 0:  # delete row
                if row < len(self.uris):
                    try:
                        del self.uris[row]
                    except IndexError:
                        pass
                    self.update_default_uri()
                    table.reloadData()
                    return
            else:
                return

        if row >= len(self.uris):
            if column == 0:
                has_empty_cell = any(value for value in self.uris if not value)
                if not has_empty_cell:
                    self.uris.append(ContactURI(uri="", type="SIP"))

        try:
            contact_uri = self.uris[row]
        except IndexError:
            pass
        else:
            if column == 0:
                uri = str(object).strip().lower().replace(" ", "")
                if not self.checkURI(uri):
                    NSRunAlertPanel(
                        NSLocalizedString("Invalid Address", "Window title"),
                        NSLocalizedString(
                            "Please enter an address containing alpha numeric characters",
                            "Label"), NSLocalizedString("OK", "Button title"),
                        None, None)
                    return
                contact_uri.uri = uri
                if uri.startswith(('https:', 'http:')):
                    contact_uri.type = 'URL'

                elif '@' in uri:
                    domain = uri.partition("@")[-1]
                    domain = domain if ':' not in domain else domain.partition(
                        ":")[0]
                    if domain in (
                            'jit.si', 'gmail.com', 'comm.unicate.me'
                    ) or 'jabb' in domain or 'xmpp' in domain or domain.endswith(
                            '.im') or domain.startswith('im.'):
                        contact_uri.type = 'XMPP'
                        if len(self.uris) == 1:
                            self.preferred_media = 'chat'
                            self.updateSubscriptionMenus()

            elif column == 1:
                contact_uri.type = str(cell.itemAtIndex_(object).title())

            self.update_default_uri()
            table.reloadData()
            row = self.addressTable.selectedRow()
            self.defaultButton.setEnabled_(row < len(self.uris))

    def tableView_validateDrop_proposedRow_proposedDropOperation_(
            self, table, info, row, oper):
        if oper == NSTableViewDropOn:
            table.setDropRow_dropOperation_(row, NSTableViewDropAbove)
        return NSDragOperationGeneric

    def tableView_acceptDrop_row_dropOperation_(self, table, info, row, oper):
        if info.draggingSource() != self.addressTable:
            return False
        pboard = info.draggingPasteboard()
        draggedRow = int(pboard.stringForType_("dragged-row"))
        if draggedRow >= len(self.uris):
            return False
        if draggedRow != row + 1 or oper != 0:
            item = self.uris[draggedRow]
            del self.uris[draggedRow]
            if draggedRow < row:
                row -= 1
            self.uris.insert(row, item)
            self.update_default_uri()
            table.reloadData()
            return True
        return False

    def tableView_writeRows_toPasteboard_(self, table, rows, pboard):
        index = rows[0]
        pboard.declareTypes_owner_(NSArray.arrayWithObject_("dragged-row"),
                                   self)
        pboard.setString_forType_(NSString.stringWithString_(str(index)),
                                  "dragged-row")
        return True
예제 #14
0
	def clearComponents(self):
		"""clear all components"""
		self._layer.setComponents_(NSMutableArray.array())
예제 #15
0
 def resetDailyEntries(self):
     self.dayly_entries = NSMutableArray.array()
     self.indexTable.reloadData()
예제 #16
0
	def clearGuides(self):
		"""clear all horizontal guides"""
		self._layer.setGuideLines_(NSMutableArray.array())
예제 #17
0
class HistoryViewer(NSWindowController):

    chatViewController = objc.IBOutlet()
    indexTable = objc.IBOutlet()
    contactTable = objc.IBOutlet()
    toolbar = objc.IBOutlet()

    entriesView = objc.IBOutlet()

    period = objc.IBOutlet()
    searchText = objc.IBOutlet()
    searchMedia = objc.IBOutlet()
    searchContactBox = objc.IBOutlet()

    paginationButton = objc.IBOutlet()
    foundMessagesLabel = objc.IBOutlet()
    queryDatabaseLabel = objc.IBOutlet()
    busyIndicator = objc.IBOutlet()

    contactMenu = objc.IBOutlet()

    # viewer sections
    contacts = []
    dayly_entries = NSMutableArray.array()
    messages = []

    # database handler
    history = None

    # search filters
    start = 0
    search_text = None
    search_uris = None
    search_local = None
    search_media = None
    after_date = None
    before_date = None
    refresh_contacts_counter = 1
    contact_cache = {}
    display_name_cache = {}
    refresh_in_progress = False

    daily_order_fields = {'date': 'DESC', 'local_uri': 'ASC', 'remote_uri': 'ASC'}
    media_type_array = {0: None, 1: ('audio', 'video'), 2: ('chat', 'sms'), 3: 'file-transfer', 4: 'audio-recording', 5: 'availability', 6: 'voicemail', 7: 'video-recording'}
    period_array = {0: None,
                    1: datetime.datetime.now()-datetime.timedelta(days=1),
                    2: datetime.datetime.now()-datetime.timedelta(days=7),
                    3: datetime.datetime.now()-datetime.timedelta(days=31),
                    4: datetime.datetime.now()-datetime.timedelta(days=90),
                    5: datetime.datetime.now()-datetime.timedelta(days=180),
                    6: datetime.datetime.now()-datetime.timedelta(days=365),
                    -1: datetime.datetime.now()-datetime.timedelta(days=1),
                    -2: datetime.datetime.now()-datetime.timedelta(days=7),
                    -3: datetime.datetime.now()-datetime.timedelta(days=31),
                    -4: datetime.datetime.now()-datetime.timedelta(days=90),
                    -5: datetime.datetime.now()-datetime.timedelta(days=180),
                    -6: datetime.datetime.now()-datetime.timedelta(days=365)
                    }

    @objc.python_method
    def format_media_type(self, media_type):
        if media_type == 'sms':
            media_type_formated = NSLocalizedString("Short Messages", "Label")
        elif media_type == 'chat':
            media_type_formated = NSLocalizedString("Chat Sessions", "Label")
        elif media_type == 'audio':
            media_type_formated = NSLocalizedString("Audio Calls", "Label")
        elif media_type == 'file-transfer':
            media_type_formated = NSLocalizedString("File Transfers", "Label")
        elif media_type == 'availability':
            media_type_formated = NSLocalizedString("Availability", "Label")
        elif media_type == 'missed-call':
            media_type_formated = NSLocalizedString("Missed Call", "Label")
        elif media_type == 'voicemail':
            media_type_formated = NSLocalizedString("Voicemail", "Label")
        else:
            media_type_formated = media_type.title()

        return media_type_formated

    def __new__(cls, *args, **kwargs):
        return cls.alloc().init()

    def __init__(self):
        if self:
            BlinkLogger().log_debug('Starting History Viewer')
            NSBundle.loadNibNamed_owner_("HistoryViewer", self)

            self.all_contacts = BlinkHistoryViewerContact('Any Address', name='All Contacts')
            self.bonjour_contact = BlinkHistoryViewerContact('bonjour.local', name='Bonjour Neighbours', icon=NSImage.imageNamed_("NSBonjour"))

            self.notification_center = NotificationCenter()
            self.notification_center.add_observer(self, name='ChatViewControllerDidDisplayMessage')
            self.notification_center.add_observer(self, name='AudioCallLoggedToHistory')
            self.notification_center.add_observer(self, name='BlinkContactsHaveChanged')
            self.notification_center.add_observer(self, name='BlinkTableViewSelectionChaged')
            self.notification_center.add_observer(self, name='BlinkConferenceContactPresenceHasChanged')
            self.notification_center.add_observer(self, name='BlinkShouldTerminate')

            self.searchText.cell().setSendsSearchStringImmediately_(True)
            self.searchText.cell().setPlaceholderString_(NSLocalizedString("Type text and press Enter", "Placeholder text"))

            self.chatViewController.setContentFile_(NSBundle.mainBundle().pathForResource_ofType_("ChatView", "html"))
            self.chatViewController.setHandleScrolling_(False)
            self.entriesView.setShouldCloseWithWindow_(False)

            for c in ('remote_uri', 'local_uri', 'date', 'type'):
                col = self.indexTable.tableColumnWithIdentifier_(c)
                descriptor = NSSortDescriptor.alloc().initWithKey_ascending_(c, True)
                col.setSortDescriptorPrototype_(descriptor)

            self.chat_history = ChatHistory()
            self.session_history = SessionHistory()
            self.setPeriod(1)

            self.selectedTableView = self.contactTable

    @objc.python_method
    def setPeriod(self, days):
        if days <= -365:
            tag = -6
        elif days <= -180:
            tag = -5
        elif days <= -90:
            tag = -4
        elif days <= -31:
            tag = -3
        elif days <= -7:
            tag = -2
        elif days <= -1:
            tag = -1
        elif days <= 1:
            tag = 1
        elif days <= 7:
            tag = 2
        elif days <= 31:
            tag = 3
        elif days <= 90:
            tag = 4
        elif days <= 180:
            tag = 5
        elif days <= 365:
            tag = 6
        else:
            tag = 0

        if tag == 0:
            self.before_date = None
            self.after_date = None
        elif tag < 0:
            try:
                date = self.period_array[tag]
            except KeyError:
                date = None

            self.before_date = date
            self.after_date = None
        else:
            try:
                date = self.period_array[tag]
            except KeyError:
                date = None

            self.after_date = date
            self.before_date = None

        self.period.selectItemWithTag_(tag)

    def awakeFromNib(self):
        NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(self, "contactSelectionChanged:", NSTableViewSelectionDidChangeNotification, self.contactTable)

        timer = NSTimer.timerWithTimeInterval_target_selector_userInfo_repeats_(1, self, "refreshContactsTimer:", None, True)
        NSRunLoop.currentRunLoop().addTimer_forMode_(timer, NSModalPanelRunLoopMode)
        NSRunLoop.currentRunLoop().addTimer_forMode_(timer, NSDefaultRunLoopMode)

        self.contactTable.setDoubleAction_("doubleClick:")

    def close_(self, sender):
        self.window().close()

    @objc.python_method
    @run_in_green_thread
    def delete_messages(self, local_uri=None, remote_uri=None, date=None, after_date=None, before_date=None, media_type=None):
        block_on(self.chat_history.delete_messages(local_uri=local_uri, remote_uri=remote_uri, date=date, after_date=after_date, before_date=before_date, media_type=media_type))
        block_on(self.session_history.delete_entries(local_uri=local_uri, remote_uri=remote_uri, after_date=after_date, before_date=before_date))
        self.search_text = None
        self.search_uris = None
        self.search_local = None
        self.refreshViewer()

    @objc.python_method
    def refreshViewer(self):
        self.refreshContacts()
        self.refreshDailyEntries()
        self.refreshMessages()

    @objc.python_method
    @run_in_green_thread
    def refreshContacts(self):
        if self.refresh_in_progress:
            return

        self.refresh_in_progress = True
        self.refresh_contacts_counter = 0
        if self.chat_history:
            self.updateBusyIndicator(True)
            remote_uri = self.search_uris if self.search_uris else None
            media_type = self.search_media if self.search_media else None
            search_text = self.search_text if self.search_text else None
            after_date = self.after_date if self.after_date else None
            before_date = self.before_date if self.before_date else None
            results = self.chat_history.get_contacts(remote_uri=remote_uri, media_type=media_type, search_text=search_text, after_date=after_date, before_date=before_date)
            self.renderContacts(results)
            self.updateBusyIndicator(False)

    @objc.python_method
    @run_in_gui_thread
    def renderContacts(self, results):
        index = 0
        found_uris = []
        uris_without_display_name = []

        for item in self.contacts:
            item.destroy()

        getFirstContactMatchingURI = NSApp.delegate().contactsWindowController.getFirstContactMatchingURI

        self.contacts = [self.all_contacts, self.bonjour_contact]

        if self.search_uris:
            for uri in self.search_uris:
                try:
                    found_contact = self.contact_cache[uri]
                except KeyError:
                    found_contact = getFirstContactMatchingURI(uri, exact_match=True)
                    self.contact_cache[uri] = found_contact

                if found_contact:
                    contact_exist = False
                    for contact_uri in found_contact.uris:
                        if contact_uri.uri in found_uris:
                            contact_exist = True
                            break
                    if contact_exist:
                        continue
                    contact = BlinkHistoryViewerContact(found_contact.uri, name=found_contact.name, icon=found_contact.icon)
                    for contact_uri in found_contact.uris:
                        found_uris.append(contact_uri.uri)
                    self.contacts.append(contact)
                    if isinstance(found_contact, BlinkPresenceContact):
                        contact.setPresenceContact_(found_contact)
                else:
                    if uri in found_uris:
                        continue
                    found_uris.append(uri)
                    contact = BlinkHistoryViewerContact(str(uri), name=str(uri))

                try:
                    index = self.contacts.index(contact)
                except ValueError:
                    pass

        if results:
            for row in results:
                try:
                    found_contact = self.contact_cache[row[0]]
                except KeyError:
                    found_contact = getFirstContactMatchingURI(row[0], exact_match=True)
                    self.contact_cache[row[0]] = found_contact
                if found_contact:
                    contact_exist = False
                    for contact_uri in found_contact.uris:
                        if contact_uri.uri in found_uris:
                            contact_exist = True
                            break
                    if contact_exist:
                        continue
                    contact = BlinkHistoryViewerContact(found_contact.uri, name=found_contact.name, icon=found_contact.icon, presence_contact=found_contact if isinstance(found_contact, BlinkPresenceContact) else None)
                    for contact_uri in found_contact.uris:
                        found_uris.append(contact_uri.uri)
                else:
                    if row[0] in found_uris:
                        continue
                    found_uris.append(row[0])
                    try:
                        display_name = self.display_name_cache[row[0]]
                    except KeyError:
                        display_name = str(row[0])
                        uris_without_display_name.append(row[0])
                    contact = BlinkHistoryViewerContact(str(row[0]), name=display_name)

                self.contacts.append(contact)
    
        self.update_display_names(uris_without_display_name)
        self.contactTable.reloadData()

        self.contactTable.selectRowIndexes_byExtendingSelection_(NSIndexSet.indexSetWithIndex_(index), False)
        self.contactTable.scrollRowToVisible_(index)

        self.updateContactsColumnHeader()
        self.refresh_in_progress = False

    @objc.python_method
    @run_in_green_thread
    def update_display_names(self, uris_without_display_name):
        results = self.session_history.get_display_names(uris_without_display_name)
        self.updateDisplayNames(results)

    @objc.python_method
    @run_in_gui_thread
    def updateDisplayNames(self, results):
        must_reload = False
        for result in results:
            self.display_name_cache[result[0]]=result[1]
            for contact in self.contacts:
                if contact.uri == result[0] and contact.name != result[1]:
                    contact.name = result[1]
                    must_reload = True
        if must_reload:
            self.contactTable.reloadData()

        must_reload = False
        for entry in self.dayly_entries:
            if entry['remote_uri_sql'] == entry['remote_uri']:
                try:
                    display_name = self.display_name_cache[entry['remote_uri_sql']]
                except KeyError:
                    pass
                else:
                    entry['display_name'] = display_name
                    entry['remote_uri'] = '%s <%s>' % (display_name, entry['remote_uri_sql']) if '@' in entry['remote_uri_sql'] else display_name
                    must_reload = True

        self.dayly_entries.sortUsingDescriptors_(self.indexTable.sortDescriptors())
        self.indexTable.reloadData()

    @objc.python_method
    @run_in_green_thread
    def refreshDailyEntries(self, order_text=None):
        if self.chat_history:
            self.resetDailyEntries()
            self.updateBusyIndicator(True)
            search_text = self.search_text if self.search_text else None
            remote_uri = self.search_uris if self.search_uris else None
            local_uri = self.search_local if self.search_local else None
            media_type = self.search_media if self.search_media else None
            after_date = self.after_date if self.after_date else None
            before_date = self.before_date if self.before_date else None
            results = self.chat_history.get_daily_entries(local_uri=local_uri, remote_uri=remote_uri, media_type=media_type, search_text=search_text, order_text=order_text, after_date=after_date, before_date=before_date)
            self.renderDailyEntries(results)
            self.updateBusyIndicator(False)

    @objc.python_method
    @run_in_gui_thread
    def resetDailyEntries(self):
        self.dayly_entries = NSMutableArray.array()
        self.indexTable.reloadData()

    @objc.python_method
    @run_in_gui_thread
    def renderDailyEntries(self, results):
        getFirstContactMatchingURI = NSApp.delegate().contactsWindowController.getFirstContactMatchingURI
        self.dayly_entries = NSMutableArray.array()
        for result in results:
            display_name = None
            try:
                found_contact = self.contact_cache[result[2]]
            except KeyError:
                found_contact = getFirstContactMatchingURI(result[2], exact_match=True)
                self.contact_cache[result[2]] = found_contact

            if found_contact:
                display_name = found_contact.name
                remote_uri = '%s <%s>' % (display_name, result[2]) if '@' in result[2] else display_name
            else:
                try:
                    display_name = self.display_name_cache[result[2]]
                except KeyError:
                    remote_uri = result[2]
                else:
                    remote_uri = '%s <%s>' % (display_name, result[2]) if '@' in result[2] else display_name

            entry = NSMutableDictionary.dictionaryWithObjectsAndKeys_(result[1], "local_uri", remote_uri, "remote_uri", result[2], "remote_uri_sql", result[0], 'date', result[3], 'type', display_name, "display_name")
            self.dayly_entries.addObject_(entry)

        self.dayly_entries.sortUsingDescriptors_(self.indexTable.sortDescriptors())
        self.indexTable.reloadData()

        if self.search_uris and not self.dayly_entries:
            self.contactTable.deselectAll_(True)

    @objc.python_method
    @run_in_green_thread
    def refreshMessages(self, count=SQL_LIMIT, remote_uri=None, local_uri=None, media_type=None, date=None, after_date=None, before_date=None):
        if self.chat_history:
            self.updateBusyIndicator(True)
            search_text = self.search_text if self.search_text else None
            if not remote_uri:
                remote_uri = self.search_uris if self.search_uris else None
            if not local_uri:
                local_uri = self.search_local if self.search_local else None
            if not media_type:
                media_type = self.search_media if self.search_media else None
            if not after_date:
                after_date = self.after_date if self.after_date else None
            if not before_date:
                before_date = self.before_date if self.before_date else None
            results = self.chat_history.get_messages(count=count, local_uri=local_uri, remote_uri=remote_uri, media_type=media_type, date=date, search_text=search_text, after_date=after_date, before_date=before_date)
            self.renderMessages(results)
            self.updateBusyIndicator(False)

    @objc.python_method
    @run_in_gui_thread
    def renderMessages(self, messages=None):
        self.chatViewController.clear()
        self.chatViewController.resetRenderedMessages()
        self.chatViewController.last_sender = None

        if messages is not None:
            # new message list. cache for pagination and reset pagination to the last page
            self.messages = list(reversed(messages))
            message_count = len(messages)
            start = message_count // MAX_MESSAGES_PER_PAGE * MAX_MESSAGES_PER_PAGE
            end = message_count
        else:
            message_count = len(self.messages)
            start = self.start
            end = min(start + MAX_MESSAGES_PER_PAGE, message_count)

        for row in self.messages[start:end]:
            self.renderMessage(row)

        self.paginationButton.setEnabled_forSegment_(start > MAX_MESSAGES_PER_PAGE, 0)
        self.paginationButton.setEnabled_forSegment_(start > 0, 1)
        self.paginationButton.setEnabled_forSegment_(start + MAX_MESSAGES_PER_PAGE + 1 < message_count, 2)
        self.paginationButton.setEnabled_forSegment_(start + MAX_MESSAGES_PER_PAGE * 2 < message_count, 3)

        if message_count == 0:
            text = NSLocalizedString("No entry found", "Label")
        elif message_count == 1:
            text = NSLocalizedString("Displaying 1 entry", "Label")
        elif message_count < MAX_MESSAGES_PER_PAGE:
            text = NSLocalizedString("Displaying {} entries".format(end), "Label")
        else:
            text = NSLocalizedString("Displaying {} to {} out of {} entries", "Label").format(start+1, end, message_count)

        self.foundMessagesLabel.setStringValue_(text)

    @objc.python_method
    @run_in_gui_thread
    def renderMessage(self, message):
        if message.direction == 'outgoing':
            icon = NSApp.delegate().contactsWindowController.iconPathForSelf()
        else:
            sender_uri = sipuri_components_from_string(message.cpim_from)[0]
            # TODO: How to render the icons from Address Book? Especially in sandbox mode we do not have access to other folders
            icon = NSApp.delegate().contactsWindowController.iconPathForURI(sender_uri)
        try:
            timestamp=ISOTimestamp(message.cpim_timestamp)
        except Exception:
            pass
        else:
            is_html = False if message.content_type == 'text' else True
            private = True if message.private == "1" else False
            self.chatViewController.showMessage(message.sip_callid, message.msgid, message.direction, message.cpim_from, icon, message.body, timestamp, is_private=private, recipient=message.cpim_to, state=message.status, is_html=is_html, history_entry=True, media_type=message.media_type, encryption=message.encryption if message.media_type == 'chat' else None)

    @objc.IBAction
    def paginateResults_(self, sender):
        if sender.selectedSegment() == 0:
           self.start = 0
        elif sender.selectedSegment() == 1:
           next_start = self.start - MAX_MESSAGES_PER_PAGE
           self.start = next_start if next_start >= 0 else self.start
        elif sender.selectedSegment() == 2:
           next_start = self.start + MAX_MESSAGES_PER_PAGE
           self.start = next_start if next_start < len(self.messages)-1 else self.start
        elif sender.selectedSegment() == 3:
           self.start = len(self.messages) - len(self.messages)%MAX_MESSAGES_PER_PAGE if len(self.messages) > MAX_MESSAGES_PER_PAGE else 0
        self.renderMessages()

    def tableView_deleteRow_(self, table, row):
        pass

    def tableView_sortDescriptorsDidChange_(self, table, odescr):
        self.dayly_entries.sortUsingDescriptors_(self.indexTable.sortDescriptors())
        self.indexTable.reloadData()

    @objc.IBAction
    def printDocument_(self, sender):
        printInfo = NSPrintInfo.sharedPrintInfo()
        printInfo.setTopMargin_(30)
        printInfo.setBottomMargin_(30)
        printInfo.setLeftMargin_(10)
        printInfo.setRightMargin_(10)
        printInfo.setOrientation_(NSPortraitOrientation)
        printInfo.setHorizontallyCentered_(True)
        printInfo.setVerticallyCentered_(False)
        printInfo.setHorizontalPagination_(NSFitPagination)
        printInfo.setVerticalPagination_(NSFitPagination)
        NSPrintInfo.setSharedPrintInfo_(printInfo)

        # print the content of the web view
        self.entriesView.mainFrame().frameView().documentView().print_(self)

    @objc.IBAction
    def search_(self, sender):
        if self.chat_history:
            self.search_text = str(sender.stringValue()).lower()
            self.refreshContacts()
            row = self.indexTable.selectedRow()
            if row > 0:
                self.refreshDailyEntries()
                self.refreshMessages(local_uri=self.dayly_entries[row].objectForKey_("local_uri"), date=self.dayly_entries[row].objectForKey_("date"), media_type=self.dayly_entries[row].objectForKey_("type"))
            else:
                row = self.contactTable.selectedRow()
                if row > 0:
                    self.refreshMessages()
                    self.refreshDailyEntries()
                else:
                    self.refreshDailyEntries()
                    self.refreshMessages()

    @objc.IBAction
    def searchContacts_(self, sender):
        text = str(self.searchContactBox.stringValue().strip())
        contacts = [contact for contact in self.contacts[2:] if text in contact] if text else self.contacts[2:]
        self.contacts = [self.all_contacts, self.bonjour_contact] + contacts
        self.contactTable.reloadData()
        self.contactTable.selectRowIndexes_byExtendingSelection_(NSIndexSet.indexSetWithIndex_(0), False)
        self.contactTable.scrollRowToVisible_(0)
        self.updateContactsColumnHeader()

        if not text:
            self.refreshContacts()

    @objc.python_method
    def updateContactsColumnHeader(self):
        found_contacts = len(self.contacts)-2
        if found_contacts == 1:
            title = NSLocalizedString("1 contact found", "Label")
        elif found_contacts > 1:
            title = NSLocalizedString("%d contacts found", "Label") % found_contacts
        else:
            title = NSLocalizedString("Contacts", "Label")

        self.contactTable.tableColumnWithIdentifier_('contacts').headerCell().setStringValue_(title)

    def tableViewSelectionDidChange_(self, notification):
        if self.chat_history:
            if notification.object() == self.contactTable:
                row = self.contactTable.selectedRow()
                if row < 0:
                    return
                elif row == 0:
                    self.search_local = None
                    self.search_uris = None
                    self.searchContactBox.setStringValue_('')
                    self.refreshContacts()
                elif row == 1:
                    self.search_local = 'bonjour.local'
                    self.search_uris = None
                elif row > 1:
                    self.search_local = None
                    if self.contacts[row].presence_contact is not None:
                        self.search_uris = list(str(contact_uri.uri) for contact_uri in self.contacts[row].presence_contact.uris)
                        self.chatViewController.expandSmileys = not self.contacts[row].presence_contact.contact.disable_smileys
                        self.chatViewController.toggleSmileys(self.chatViewController.expandSmileys)
                        try:
                            item = next((item for item in self.toolbar.visibleItems() if item.itemIdentifier() == 'smileys'))
                        except StopIteration:
                            pass
                        else:
                            item.setImage_(NSImage.imageNamed_("smiley_on" if self.chatViewController.expandSmileys else "smiley_off"))
                    else:
                        self.search_uris = (self.contacts[row].uri,)
                self.refreshDailyEntries()
                self.refreshMessages()
            else:
                row = self.indexTable.selectedRow()
                if row >= 0:
                    self.refreshMessages(remote_uri=(self.dayly_entries[row].objectForKey_("remote_uri_sql"),), local_uri=self.dayly_entries[row].objectForKey_("local_uri"), date=self.dayly_entries[row].objectForKey_("date"), media_type=self.dayly_entries[row].objectForKey_("type"))

    def numberOfRowsInTableView_(self, table):
        if table == self.indexTable:
            return self.dayly_entries.count()
        elif table == self.contactTable:
            return len(self.contacts)
        return 0

    def tableView_objectValueForTableColumn_row_(self, table, column, row):
        if table == self.indexTable:
            ident = column.identifier()
            if ident == 'type':
                return self.format_media_type(self.dayly_entries[row].objectForKey_(ident))

            try:
                return str(self.dayly_entries[row].objectForKey_(ident))
            except IndexError:
                return None
        elif table == self.contactTable:
            try:
                if type(self.contacts[row]) in (str, str):
                    return self.contacts[row]
                else:
                    return self.contacts[row].name
            except IndexError:
                return None
        return None

    def tableView_willDisplayCell_forTableColumn_row_(self, table, cell, tableColumn, row):
        if table == self.contactTable:
            try:
                if row < len(self.contacts):
                    if type(self.contacts[row]) in (str, str):
                        cell.setContact_(None)
                    else:
                        cell.setContact_(self.contacts[row])
            except:
                pass

    def showWindow_(self, sender):
        self.window().makeKeyAndOrderFront_(None)

    @objc.python_method
    @run_in_gui_thread
    def filterByURIs(self, uris=(), media_type=None):

        self.search_text = None
        self.search_local = None
        if media_type != self.search_media:
            for tag in list(self.media_type_array.keys()):
                if self.media_type_array[tag] == media_type:
                    self.searchMedia.selectItemAtIndex_(tag)

        self.search_media = media_type
        self.search_uris = uris
        self.refreshContacts()
        self.refreshDailyEntries()
        self.refreshMessages()

    @objc.IBAction
    def filterByMediaChanged_(self, sender):
        tag = sender.selectedItem().tag()
        self.search_media = self.media_type_array[tag]
        self.refreshContacts()
        self.refreshDailyEntries()
        self.refreshMessages()

    @objc.IBAction
    def filterByPeriodChanged_(self, sender):
        tag = sender.selectedItem().tag()

        if tag == 0:
            self.before_date = None
            self.after_date = None
        elif tag < 0:
            try:
                date = self.period_array[tag]
            except KeyError:
                date = None

            self.before_date = date
            self.after_date = None
        else:
            try:
                date = self.period_array[tag]
            except KeyError:
                date = None

            self.after_date = date
            self.before_date = None

        self.refreshContacts()
        self.refreshDailyEntries()
        self.refreshMessages()

    def validateToolbarItem_(self, item):
        if item.itemIdentifier() == NSToolbarPrintItemIdentifier and not self.messages:
            return False
        return True

    def toolbarWillAddItem_(self, notification):
        item = notification.userInfo()["item"]
        if item.itemIdentifier() == NSToolbarPrintItemIdentifier:
            item.setToolTip_("Print Current Entries")
            item.setTarget_(self)
            item.setAutovalidates_(True)

    @objc.IBAction
    def userClickedToolbarItem_(self, sender):
        if sender.itemIdentifier() == 'smileys':
            self.chatViewController.expandSmileys = not self.chatViewController.expandSmileys
            sender.setImage_(NSImage.imageNamed_("smiley_on" if self.chatViewController.expandSmileys else "smiley_off"))
            self.chatViewController.toggleSmileys(self.chatViewController.expandSmileys)

            row = self.contactTable.selectedRow()
            if row and row > 1 and self.contacts[row].presence_contact is not None:
                self.contacts[row].presence_contact.contact.disable_smileys = not self.contacts[row].presence_contact.contact.disable_smileys
                self.contacts[row].presence_contact.contact.save()

        elif sender.itemIdentifier() == 'delete':
            if self.selectedTableView == self.contactTable:
                try:
                    row = self.contactTable.selectedRow()
                    self.showDeleteConfirmationDialog(row)
                except IndexError:
                    pass

            elif self.selectedTableView == self.indexTable:
                try:
                    row = self.indexTable.selectedRow()
                    local_uri = self.dayly_entries[row].objectForKey_("local_uri")
                    remote_uri = self.dayly_entries[row].objectForKey_("remote_uri")
                    remote_uri_sql = self.dayly_entries[row].objectForKey_("remote_uri_sql")
                    date = self.dayly_entries[row].objectForKey_("date")
                    media_type = self.dayly_entries[row].objectForKey_("type")

                    label = NSLocalizedString("Please confirm the deletion of %s history entries", "Label") % media_type + NSLocalizedString(" from %s", "SIP Address label") % remote_uri + NSLocalizedString(" on %s. ", "Date label") % date + NSLocalizedString("This operation cannot be undone. ", "Label")
                    ret = NSRunAlertPanel(NSLocalizedString("Purge History Entries", "Window title"), label, NSLocalizedString("Confirm", "Button title"), NSLocalizedString("Cancel", "Button title"), None)
                    if ret == NSAlertDefaultReturn:
                        self.delete_messages(local_uri=local_uri, remote_uri=remote_uri_sql, media_type=media_type, date=date)
                except IndexError:
                    pass

    @objc.python_method
    def showDeleteConfirmationDialog(self, row):
        media_print = self.search_media or NSLocalizedString("all", "Label")
        tag = self.period.selectedItem().tag()

        period = '%s %s' % (NSLocalizedString(" newer than", "Date label") if tag < 4 else NSLocalizedString(" older than", "Date label"), self.period_array[tag].strftime("%Y-%m-%d")) if tag else ''

        if row == 0:
            label = NSLocalizedString("Please confirm the deletion of %s history entries", "Label") % media_print + period + ". "+ NSLocalizedString("This operation cannot be undone. ", "Label")
            ret = NSRunAlertPanel(NSLocalizedString("Purge History Entries", "Window title"), label, NSLocalizedString("Confirm", "Button title"), NSLocalizedString("Cancel", "Button title"), None)
            if ret == NSAlertDefaultReturn:
                self.delete_messages(media_type=self.search_media, after_date=self.after_date, before_date=self.before_date)
        elif row == 1:
            remote_uri=self.contacts[row].uri
            label = NSLocalizedString("Please confirm the deletion of %s Bonjour history entries", "Label") % media_print + period + ". "+ NSLocalizedString("This operation cannot be undone. ", "Label")
            ret = NSRunAlertPanel(NSLocalizedString("Purge History Entries", "Window title"), label, NSLocalizedString("Confirm", "Button title"), NSLocalizedString("Cancel", "Button title"), None)
            if ret == NSAlertDefaultReturn:
                self.delete_messages(local_uri='bonjour.local', media_type=self.search_media, after_date=self.after_date, before_date=self.before_date)
        else:
            contact = self.contacts[row]
            if contact.presence_contact is not None:
                remote_uri = list(str(contact.uri) for contact in contact.presence_contact.uris)
            else:
                remote_uri = contact.uri
            label = NSLocalizedString("Please confirm the deletion of %s history entries", "Label") % media_print + NSLocalizedString(" from ", "Label") + contact.name + period + ". "+ NSLocalizedString("This operation cannot be undone. ", "Label")
            ret = NSRunAlertPanel(NSLocalizedString("Purge History Entries", "Window title"), label, NSLocalizedString("Confirm", "Button title"), NSLocalizedString("Cancel", "Button title"), None)
            if ret == NSAlertDefaultReturn:
                self.delete_messages(remote_uri=remote_uri, media_type=self.search_media, after_date=self.after_date, before_date=self.before_date)

    @objc.python_method
    @run_in_gui_thread
    def updateBusyIndicator(self, busy=False):
        if busy:
            self.queryDatabaseLabel.setHidden_(False)
            self.busyIndicator.setHidden_(False)
            self.busyIndicator.setIndeterminate_(True)
            self.busyIndicator.setStyle_(NSProgressIndicatorSpinningStyle)
            self.busyIndicator.startAnimation_(None)
        else:
            self.busyIndicator.stopAnimation_(None)
            self.busyIndicator.setHidden_(True)
            self.queryDatabaseLabel.setHidden_(True)

    @objc.python_method
    @run_in_gui_thread
    def handle_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

    @objc.python_method
    def _NH_BlinkShouldTerminate(self, notification):
        if self.window():
            self.window().orderOut_(self)

    @objc.python_method
    def _NH_ChatViewControllerDidDisplayMessage(self, notification):
        if notification.data.local_party != 'bonjour.local':
            exists = any(contact for contact in self.contacts if notification.data.remote_party == contact.uri)
            if not exists:
                self.refreshContacts()

    @objc.python_method
    def _NH_AudioCallLoggedToHistory(self, notification):
        if notification.data.local_party != 'bonjour.local':
            exists = any(contact for contact in self.contacts if notification.data.remote_party == contact.uri)
            if not exists:
                self.refreshContacts()

    @objc.python_method
    def _NH_BlinkContactsHaveChanged(self, notification):
        self.refresh_contacts_counter += 1

    def refreshContactsTimer_(self, timer):
        if self.refresh_contacts_counter:
            self.refreshContacts()
            self.toolbar.validateVisibleItems()

    @objc.python_method
    def _NH_BlinkTableViewSelectionChaged(self, notification):
        self.selectedTableView = notification.sender
        self.toolbar.validateVisibleItems()

    @objc.python_method
    def _NH_BlinkConferenceContactPresenceHasChanged(self, notification):
        try:
            contact = next((contact for contact in self.contacts[2:] if contact == notification.sender))
        except StopIteration:
            return
        else:
            try:
                idx = self.contacts.index(contact)
                self.contactTable.reloadDataForRowIndexes_columnIndexes_(NSIndexSet.indexSetWithIndex_(idx), NSIndexSet.indexSetWithIndex_(0))
            except ValueError:
                pass

    def contactSelectionChanged_(self, notification):
        pass

    def menuWillOpen_(self, menu):
        if menu == self.contactMenu:
            self.contactMenu.itemWithTag_(2).setEnabled_(False)
            self.contactMenu.itemWithTag_(3).setEnabled_(False)
            self.contactMenu.itemWithTag_(4).setEnabled_(False)
            try:
                row = self.contactTable.selectedRow()
            except:
                return

            if row < 2:
                return

            try:
                contact = self.contacts[row]
            except IndexError:
                return

            contact_exists = bool(contact.presence_contact is not None)
            if '@' in contact.uri:
                self.contactMenu.itemWithTag_(2).setEnabled_(not is_anonymous(contact.uri))
                self.contactMenu.itemWithTag_(3).setEnabled_(not contact_exists and not is_anonymous(contact.uri))
                self.contactMenu.itemWithTag_(4).setEnabled_(contact_exists)
            else:
                bonjour_contact = NSApp.delegate().contactsWindowController.model.getBonjourContactMatchingDeviceId(contact.uri)
                self.contactMenu.itemWithTag_(2).setEnabled_(bool(bonjour_contact))
                self.contactMenu.itemWithTag_(3).setEnabled_(False)
                self.contactMenu.itemWithTag_(4).setEnabled_(False)


    @objc.IBAction
    def doubleClick_(self, sender):
        row = self.contactTable.selectedRow()

        if row < 2:
            return

        try:
            contact = self.contacts[row]
        except IndexError:
            return

        if '@' in contact.uri:
            NSApp.delegate().contactsWindowController.startSessionWithTarget(contact.uri)
        else:
            bonjour_contact = NSApp.delegate().contactsWindowController.model.getBonjourContactMatchingDeviceId(contact.uri)
            if not bonjour_contact:
                BlinkLogger().log_info("Bonjour neighbour %s was not found on this network" % contact.name)
                message = NSLocalizedString("Bonjour neighbour %s was not found on this network. ", "label") % contact.name
                NSRunAlertPanel(NSLocalizedString("Error", "Window title"), message, NSLocalizedString("OK", "Button title"), None, None)
                return
            NSApp.delegate().contactsWindowController.startSessionWithTarget(bonjour_contact.uri)

    @objc.IBAction
    def userClickedContactMenu_(self, sender):
        row = self.contactTable.selectedRow()

        try:
            contact = self.contacts[row]
        except IndexError:
            return

        tag = sender.tag()

        if tag == 1:
            self.showDeleteConfirmationDialog(row)
        elif tag == 2:
            NSApp.delegate().contactsWindowController.searchBox.setStringValue_(contact.uri)
            NSApp.delegate().contactsWindowController.searchContacts()
            NSApp.delegate().contactsWindowController.window().makeFirstResponder_(NSApp.delegate().contactsWindowController.searchBox)
            NSApp.delegate().contactsWindowController.window().deminiaturize_(sender)
            NSApp.delegate().contactsWindowController.window().makeKeyWindow()
        elif tag == 3:
            NSApp.delegate().contactsWindowController.addContact(uris=[(contact.uri, 'sip')], name=contact.name)
        elif tag == 4 and contact.presence_contact is not None:
            NSApp.delegate().contactsWindowController.model.editContact(contact.presence_contact)

    @objc.IBAction
    def userClickedActionsButton_(self, sender):
        point = sender.window().convertScreenToBase_(NSEvent.mouseLocation())
        event = NSEvent.mouseEventWithType_location_modifierFlags_timestamp_windowNumber_context_eventNumber_clickCount_pressure_(
                    NSLeftMouseUp, point, 0, NSDate.timeIntervalSinceReferenceDate(), sender.window().windowNumber(),
                    sender.window().graphicsContext(), 0, 1, 0)
        NSMenu.popUpContextMenu_withEvent_forView_(self.contactMenu, event, sender)
예제 #18
0
 def clearComponents(self):
     """clear all components"""
     self._layer.setComponents_(NSMutableArray.array())
예제 #19
0
 def clearGuides(self):
     """clear all horizontal guides"""
     self._layer.setGuideLines_(NSMutableArray.array())