1# -*- coding: utf-8 -*-
2#
3# (c) Copyright 2003-2015 HP Development Company, L.P.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18#
19# Author: Don Welch
20#
21
22# Std Lib
23import sys
24import os
25import os.path
26
27# Local
28from base.g import *
29from base import utils
30from base.sixext import  to_unicode
31from .ui_utils import load_pixmap
32
33try:
34    from fax import fax
35except ImportError:
36    # This can fail on Python < 2.3 due to the datetime module
37    log.error("Fax address book disabled - Python 2.3+ required.")
38    sys.exit(1)
39
40# Qt
41from qt import *
42from .faxaddrbookform_base import FaxAddrBookForm_base
43from .faxaddrbookeditform_base import FaxAddrBookEditForm_base
44from .faxaddrbookgroupsform_base import FaxAddrBookGroupsForm_base
45from .faxaddrbookgroupeditform_base import FaxAddrBookGroupEditForm_base
46
47# globals
48db = None
49
50# ****************************************************************************
51
52class AddressBookItem2(QListViewItem):
53
54    def __init__(self, parent, entry):
55        QListViewItem.__init__(self, parent)
56        self.entry = entry
57        self.setText(0, entry['name'])
58        self.setText(1, entry['title'])
59        self.setText(2, entry['firstname'])
60        self.setText(3, entry['lastname'])
61        self.setText(4, entry['fax'])
62        self.setText(5, ', '.join(entry['groups']))
63        self.setText(6, entry['notes'])
64
65class GroupValidator(QValidator):
66    def __init__(self, parent=None, name=None):
67        QValidator.__init__(self, parent, name)
68
69    def validate(self, input, pos):
70        input = to_unicode(input)
71        if input.find(',') > 0:
72            return QValidator.Invalid, pos
73        elif len(input) > 50:
74            return QValidator.Invalid, pos
75        else:
76            return QValidator.Acceptable, pos
77
78
79class PhoneNumValidator(QValidator):
80    def __init__(self, parent=None, name=None):
81        QValidator.__init__(self, parent, name)
82
83    def validate(self, input, pos):
84        input = to_unicode(input)
85        if not input:
86            return QValidator.Acceptable, pos
87        elif input[pos-1] not in '0123456789-(+) *#':
88            return QValidator.Invalid, pos
89        elif len(input) > 50:
90            return QValidator.Invalid, pos
91        else:
92            return QValidator.Acceptable, pos
93
94
95# **************************************************************************** #
96
97class FaxAddrBookGroupEditForm(FaxAddrBookGroupEditForm_base):
98    """
99        Called when clicking New... or Edit... from the Group Dialog
100    """
101    def __init__(self,parent = None,name = None,modal = 0,fl = 0):
102        FaxAddrBookGroupEditForm_base.__init__(self,parent,name,modal,fl)
103        self.edit_mode = False
104        self.okButton.setEnabled(True)
105        self.all_groups = db.get_all_groups()
106        self.groupnameEdit.setValidator(GroupValidator(self.groupnameEdit))
107
108    def setDlgData(self, group_name):
109        self.edit_mode = True
110        self.groupnameEdit.setText(group_name)
111        self.groupnameEdit.setReadOnly(True)
112        self.setEntries(group_name)
113
114    def setEntries(self, group_name=''):
115        self.entriesListView.clear()
116        all_entries = db.get_all_records()
117
118        for e, v in list(all_entries.items()):
119            i = QCheckListItem(self.entriesListView, e, QCheckListItem.CheckBox)
120
121            if group_name and group_name in v['groups']:
122                i.setState(QCheckListItem.On)
123
124        self.CheckOKButton()
125
126
127    def getDlgData(self):
128        group_name = to_unicode(self.groupnameEdit.text())
129        entries = []
130
131        i = self.entriesListView.firstChild()
132
133        while i is not None:
134            if i.isOn():
135                entries.append(to_unicode(i.text()))
136
137            i = i.itemBelow()
138
139        return group_name, entries
140
141    def groupnameEdit_textChanged(self,a0):
142        self.CheckOKButton()
143
144    def entriesListView_clicked(self,a0):
145        self.CheckOKButton()
146
147    def CheckOKButton(self):
148        group_name = to_unicode(self.groupnameEdit.text())
149
150        if not group_name or \
151            (not self.edit_mode and group_name in self.all_groups):
152
153            self.okButton.setEnabled(False)
154            return
155
156        i = self.entriesListView.firstChild()
157
158        while i is not None:
159            if i.isOn():
160                break
161
162            i = i.itemBelow()
163
164        else:
165            self.okButton.setEnabled(False)
166            return
167
168        self.okButton.setEnabled(True)
169
170    def __tr(self,s,c = None):
171        return qApp.translate("FaxAddrBookGroupEditForm",s,c)
172
173
174# **************************************************************************** #
175
176class FaxAddrBookGroupsForm(FaxAddrBookGroupsForm_base):
177
178    def __init__(self,parent = None,name = None,modal = 0,fl = 0):
179        FaxAddrBookGroupsForm_base.__init__(self,parent,name,modal,fl)
180        self.current = None
181        QTimer.singleShot(0, self.InitialUpdate)
182
183    def InitialUpdate(self):
184        self.UpdateList()
185
186    def UpdateList(self):
187        self.groupListView.clear()
188        first_rec = None
189        all_groups = db.get_all_groups()
190        if all_groups:
191
192            for group in all_groups:
193                i = QListViewItem(self.groupListView, group,
194                                  ', '.join(db.group_members(group)))
195
196                if first_rec is None:
197                    first_rec = i
198
199            self.groupListView.setCurrentItem(i)
200            self.current = i
201
202            self.editButton.setEnabled(True)
203            self.deleteButton.setEnabled(True)
204
205        else:
206            self.editButton.setEnabled(False)
207            self.deleteButton.setEnabled(False)
208
209    def newButton_clicked(self):
210        dlg = FaxAddrBookGroupEditForm(self)
211        dlg.setEntries()
212        if dlg.exec_loop() == QDialog.Accepted:
213            group_name, entries = dlg.getDlgData()
214            db.update_groups(group_name, entries)
215            self.UpdateList()
216
217    def editButton_clicked(self):
218        dlg = FaxAddrBookGroupEditForm(self)
219        group_name = to_unicode(self.current.text(0))
220        dlg.setDlgData(group_name)
221        if dlg.exec_loop() == QDialog.Accepted:
222            group_name, entries = dlg.getDlgData()
223            db.update_groups(group_name, entries)
224            self.UpdateList()
225
226
227    def deleteButton_clicked(self):
228        x = QMessageBox.critical(self,
229                                 self.caption(),
230                                 self.__tr("<b>Annoying Confirmation: Are you sure you want to delete this group?</b>"),
231                                  QMessageBox.Yes,
232                                  QMessageBox.No | QMessageBox.Default,
233                                  QMessageBox.NoButton)
234        if x == QMessageBox.Yes:
235            db.delete_group(to_unicode(self.current.text(0)))
236            self.UpdateList()
237
238    def groupListView_currentChanged(self, a0):
239        self.current = a0
240
241    def groupListView_doubleClicked(self, a0):
242        self.editButton_clicked()
243
244    def groupListView_rightButtonClicked(self, item, pos, a2):
245        popup = QPopupMenu(self)
246
247        popup.insertItem(self.__tr("New..."), self.newButton_clicked)
248
249        if item is not None:
250            popup.insertItem(self.__tr("Edit..."), self.editButton_clicked)
251            popup.insertItem(self.__tr("Delete..."), self.deleteButton_clicked)
252
253        popup.insertSeparator()
254        popup.insertItem(self.__tr("Refresh List"), self.UpdateList)
255        popup.popup(pos)
256
257    def __tr(self,s,c = None):
258        return qApp.translate("FaxAddrBookGroupsForm",s,c)
259
260
261# **************************************************************************** #
262
263
264class FaxAddrBookEditForm(FaxAddrBookEditForm_base):
265    def __init__(self, editing=True, parent = None,name = None,modal = 0,fl = 0):
266        FaxAddrBookEditForm_base.__init__(self,parent,name,modal,fl)
267        self.editing = editing
268        self.faxEdit.setValidator(PhoneNumValidator(self.faxEdit))
269        self.initial_nickname = ''
270        self.OKButton.setEnabled(self.editing)
271
272    def setDlgData(self, name, title, firstname, lastname, fax, group_list, notes):
273        self.initial_nickname = name
274        self.name = name
275        self.titleEdit.setText(title)
276        self.firstnameEdit.setText(firstname)
277        self.lastnameEdit.setText(lastname)
278        self.faxEdit.setText(fax)
279        self.notesEdit.setText(notes)
280        self.nicknameEdit.setText(name)
281        self.setGroups(group_list)
282
283    def setGroups(self, entry_groups=[]):
284        self.groupListView.clear()
285        for g in db.get_all_groups():
286            i = QCheckListItem(self.groupListView, g, QCheckListItem.CheckBox)
287
288            if g in entry_groups:
289                i.setState(QCheckListItem.On)
290
291    def getDlgData(self):
292        in_groups = []
293        i = self.groupListView.firstChild()
294
295        while i is not None:
296            if i.isOn():
297                in_groups.append(to_unicode(i.text()))
298            i = i.itemBelow()
299
300        return {'name': to_unicode(self.nicknameEdit.text()),
301                'title': to_unicode(self.titleEdit.text()),
302                'firstname': to_unicode(self.firstnameEdit.text()),
303                'lastname': to_unicode(self.lastnameEdit.text()),
304                'fax': to_unicode(self.faxEdit.text()),
305                'groups': in_groups,
306                'notes': to_unicode(self.notesEdit.text())}
307
308    def firstnameEdit_textChanged(self,a0):
309        pass
310
311    def lastnameEdit_textChanged(self,a0):
312        pass
313
314    def nicknameEdit_textChanged(self, nickname):
315        self.CheckOKButton(nickname, None)
316
317    def faxEdit_textChanged(self, fax):
318        self.CheckOKButton(None, fax)
319
320    def CheckOKButton(self, nickname=None, fax=None):
321        if nickname is None:
322            nickname = to_unicode(self.nicknameEdit.text())
323
324        if fax is None:
325            fax = to_unicode(self.faxEdit.text())
326
327        ok = bool(len(nickname) and len(fax))
328
329        if nickname:
330            all_entries = db.get_all_records()
331            for e, v in list(all_entries.items()):
332                if nickname == e and nickname != self.initial_nickname:
333                    ok = False
334
335        self.OKButton.setEnabled(ok)
336
337    def __tr(self,s,c = None):
338        return qApp.translate("FaxAddrBookEditForm",s,c)
339
340# **************************************************************************** #
341
342class FaxAddrBookForm(FaxAddrBookForm_base):
343    def __init__(self,parent = None,name = None,modal = 0,fl = 0):
344        FaxAddrBookForm_base.__init__(self,parent,name,modal,fl)
345
346        self.setIcon(load_pixmap('hp_logo', '128x128'))
347
348        global db
349        db =  fax.FaxAddressBook()
350        self.init_problem = False
351
352        QTimer.singleShot(0, self.InitialUpdate)
353
354
355    def InitialUpdate(self):
356        if self.init_problem:
357            self.close()
358            return
359
360        self.UpdateList()
361
362    def UpdateList(self):
363        self.addressListView.clear()
364        first_rec = None
365        all_entries = db.get_all_records()
366        log.debug("Number of records is: %d" % len(all_entries))
367
368        if all_entries:
369            for e, v in list(all_entries.items()):
370
371                if v['name'].startswith('__'):
372                    continue
373
374                i = AddressBookItem2(self.addressListView, v)
375
376                if first_rec is None:
377                    first_rec = i
378
379            self.addressListView.setCurrentItem(i)
380            self.current = i
381
382            self.editButton.setEnabled(True)
383            self.deleteButton.setEnabled(True)
384
385        else:
386            self.editButton.setEnabled(False)
387            self.deleteButton.setEnabled(False)
388
389    def groupButton_clicked(self):
390        FaxAddrBookGroupsForm(self).exec_loop()
391        self.sendUpdateEvent()
392        self.UpdateList()
393
394    def newButton_clicked(self):
395        dlg = FaxAddrBookEditForm(False, self)
396        dlg.setGroups()
397        if dlg.exec_loop() == QDialog.Accepted:
398            d = dlg.getDlgData()
399            db.set(**d)
400            self.sendUpdateEvent()
401            self.UpdateList()
402
403    def editButton_clicked(self):
404        dlg = FaxAddrBookEditForm(True, self)
405        c = self.current.entry
406        dlg.setDlgData(c['name'], c['title'], c['firstname'],
407            c['lastname'], c['fax'], c['groups'], c['notes'])
408        prev_name = c['name']
409        if dlg.exec_loop() == QDialog.Accepted:
410            d = dlg.getDlgData()
411
412            if prev_name != d['name']:
413                db.delete(prev_name)
414
415            db.set(**d)
416            self.sendUpdateEvent()
417            self.UpdateList()
418
419
420    def deleteButton_clicked(self):
421        if QMessageBox.critical(self,
422             self.caption(),
423             self.__tr("<b>Annoying Confirmation: Are you sure you want to delete this address book entry?</b>"),
424              QMessageBox.Yes,
425              QMessageBox.No | QMessageBox.Default,
426              QMessageBox.NoButton) == QMessageBox.Yes:
427            db.delete(self.current.entry['name'])
428            self.UpdateList()
429            self.sendUpdateEvent()
430
431
432    def addressListView_rightButtonClicked(self, item, pos, a2):
433        popup = QPopupMenu(self)
434        popup.insertItem(self.__tr("New..."), self.newButton_clicked)
435        if item is not None:
436            popup.insertItem(self.__tr("Edit..."), self.editButton_clicked)
437            popup.insertItem(self.__tr("Delete..."), self.deleteButton_clicked)
438
439        popup.insertSeparator()
440        popup.insertItem(self.__tr("Refresh List"), self.UpdateList)
441        popup.popup(pos)
442
443    def addressListView_doubleClicked(self,a0):
444        self.editButton_clicked()
445
446    def addressListView_currentChanged(self,item):
447        self.current = item
448
449    def FailureUI(self, error_text):
450        log.error(to_unicode(error_text).replace("<b>", "").replace("</b>", "").replace("<p>", " "))
451        QMessageBox.critical(self,
452                             self.caption(),
453                             QString(error_text),
454                              QMessageBox.Ok,
455                              QMessageBox.NoButton,
456                              QMessageBox.NoButton)
457
458    def __tr(self,s,c = None):
459        return qApp.translate("FaxAddrBookForm",s,c)
460
461    def accept(self):
462        self.sendUpdateEvent()
463
464        FaxAddrBookForm_base.accept(self)
465
466    def sendUpdateEvent(self):
467        pass # TODO:
468
469    def importPushButton_clicked(self):
470        dlg = QFileDialog(user_conf.workingDirectory(), "LDIF (*.ldif *.ldi);;vCard (*.vcf)", None, None, True)
471
472        dlg.setCaption("openfile")
473        dlg.setMode(QFileDialog.ExistingFile)
474        dlg.show()
475
476        if dlg.exec_loop() == QDialog.Accepted:
477                result = str(dlg.selectedFile())
478                working_directory = to_unicode(dlg.dir().absPath())
479                log.debug("result: %s" % result)
480                user_conf.setWorkingDirectory(working_directory)
481
482                if result:
483                    if result.endswith('.vcf'):
484                        ok, error_str = db.import_vcard(result)
485                    else:
486                        ok, error_str = db.import_ldif(result)
487
488                    if not ok:
489                        self.FailureUI(error_str)
490
491                    else:
492                        self.UpdateList()
493
494