Exemple #1
0
class SelectTagsDialog(QDialog):
    def __init__(self,
                 parent,
                 modal=True,
                 flags=Qt.WindowFlags(),
                 caption="Select Tags",
                 ok_button="Select"):
        QDialog.__init__(self, parent, flags)
        self.setModal(modal)
        self.setWindowTitle(caption)
        lo = QVBoxLayout(self)
        lo.setMargin(10)
        lo.setSpacing(5)
        # tag selector
        self.wtagsel = QListWidget(self)
        lo.addWidget(self.wtagsel)
        #    self.wtagsel.setColumnMode(QListBox.FitToWidth)
        self.wtagsel.setSelectionMode(QListWidget.MultiSelection)
        QObject.connect(self.wtagsel, SIGNAL("itemSelectionChanged()"),
                        self._check_tag)
        # buttons
        lo.addSpacing(10)
        lo2 = QHBoxLayout()
        lo.addLayout(lo2)
        lo2.setContentsMargins(0, 0, 0, 0)
        lo2.setMargin(5)
        self.wokbtn = QPushButton(ok_button, self)
        self.wokbtn.setMinimumWidth(128)
        QObject.connect(self.wokbtn, SIGNAL("clicked()"), self.accept)
        self.wokbtn.setEnabled(False)
        cancelbtn = QPushButton("Cancel", self)
        cancelbtn.setMinimumWidth(128)
        QObject.connect(cancelbtn, SIGNAL("clicked()"), self.reject)
        lo2.addWidget(self.wokbtn)
        lo2.addStretch(1)
        lo2.addWidget(cancelbtn)
        self.setMinimumWidth(384)
        self._tagnames = []

    def setTags(self, tagnames):
        self._tagnames = tagnames
        self.wtagsel.clear()
        self.wtagsel.insertItems(0, list(tagnames))

    def _check_tag(self):
        for i in range(len(self._tagnames)):
            if self.wtagsel.item(i).isSelected():
                self.wokbtn.setEnabled(True)
                return
        else:
            self.wokbtn.setEnabled(False)

    def getSelectedTags(self):
        return [
            tag for i, tag in enumerate(self._tagnames)
            if self.wtagsel.item(i).isSelected()
        ]
Exemple #2
0
class PrefsViewerDialog(SizePersistedDialog):
    def __init__(self, gui, namespace):
        SizePersistedDialog.__init__(self, gui, 'Prefs Viewer dialog')
        self.setWindowTitle('Preferences for: ' + namespace)

        self.db = gui.current_db
        self.namespace = namespace
        self._init_controls()
        self.resize_dialog()

        self._populate_settings()

        if self.keys_list.count():
            self.keys_list.setCurrentRow(0)

    def _init_controls(self):
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        ml = QHBoxLayout()
        layout.addLayout(ml, 1)

        self.keys_list = QListWidget(self)
        self.keys_list.setSelectionMode(QAbstractItemView.SingleSelection)
        self.keys_list.setFixedWidth(150)
        self.keys_list.setAlternatingRowColors(True)
        ml.addWidget(self.keys_list)
        self.value_text = QTextEdit(self)
        self.value_text.setTabStopWidth(24)
        self.value_text.setReadOnly(True)
        ml.addWidget(self.value_text, 1)

        button_box = QDialogButtonBox(QDialogButtonBox.Ok)
        button_box.accepted.connect(self.accept)
        button_box.setCenterButtons(True)
        layout.addWidget(button_box)

    def _populate_settings(self):
        self.keys_list.clear()
        ns_prefix = 'namespaced:%s:' % self.namespace
        keys = sorted([
            k[len(ns_prefix):] for k in self.db.prefs.iterkeys()
            if k.startswith(ns_prefix)
        ])
        for key in keys:
            self.keys_list.addItem(key)
        self.keys_list.setMinimumWidth(self.keys_list.sizeHintForColumn(0))
        self.keys_list.currentRowChanged[int].connect(
            self._current_row_changed)

    def _current_row_changed(self, new_row):
        if new_row < 0:
            self.value_text.clear()
            return
        key = unicode(self.keys_list.currentItem().text())
        val = self.db.prefs.get_namespaced(self.namespace, key, '')
        self.value_text.setPlainText(self.db.prefs.to_raw(val))
Exemple #3
0
class AddBookDialog(SizePersistedDialog):

    def __init__(self, parent=None, mm=None, mi = None):
        SizePersistedDialog.__init__(self, parent, 'casanova plugin:add book dialog')
        self.setWindowTitle('Add text to Casanova:')
        self.gui = parent
        self.mm = mm
        self.mi = mi
        self.one_line_description = ''

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.one_liner_label = QLabel('Enter a short description (255 chars max) before pressing OK')
        layout.addWidget(self.one_liner_label)
        self.one_liner_str = QLineEdit(self)
        self.one_liner_str.setText('')
        layout.addWidget(self.one_liner_str)
        self.one_liner_label.setBuddy(self.one_liner_str)

        self.values_label = QLabel('Below are potential matches of texts that already exist - please make sure you are adding something new')
        layout.addWidget(self.values_label)
        self.values_list = QListWidget(self)
        self.values_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        layout.addWidget(self.values_list)
        
        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.button_box.accepted.connect(self._accept_clicked)
        self.button_box.rejected.connect(self.reject)
        layout.addWidget(self.button_box)

        self._display_choices()

        # Cause our dialog size to be restored from prefs or created on first usage
        self.resize_dialog()

    def _display_choices(self):
        self.values_list.clear()
        choices = self.mm.search(self.mi.title)
        if choices is None or len(choices)==0:
            item = QListWidgetItem(get_icon('images/books.png'), _('there seem to be no matches'), self.values_list)
            self.values_list.addItem(item)
        for id, name in choices.items():
            item = QListWidgetItem(get_icon('images/books.png'), name, self.values_list)
            item.setData(1, (id,))
            self.values_list.addItem(item)

    def _accept_clicked(self):
        #self._save_preferences()
        one_liner = unicode(self.one_liner_str.text())
        if one_liner=='':
            self.values_list.clear()
            item = QListWidgetItem(get_icon('images/books.png'), _('you need to enter a short description'), self.values_list)
            self.values_list.addItem(item)
        else:
            self.one_line_description = one_liner
        self.accept()  
class PrefsViewerDialog(SizePersistedDialog):
    
    def __init__(self, gui, namespace):
        SizePersistedDialog.__init__(self, gui, 'Prefs Viewer dialog')
        self.setWindowTitle('Preferences for: '+namespace)

        self.db = gui.current_db
        self.namespace = namespace
        self._init_controls()
        self.resize_dialog()
        
        self._populate_settings()
        
        if self.keys_list.count():
            self.keys_list.setCurrentRow(0)
        
    def _init_controls(self):
        layout = QVBoxLayout(self)
        self.setLayout(layout)
        
        ml = QHBoxLayout()
        layout.addLayout(ml, 1)
        
        self.keys_list = QListWidget(self)
        self.keys_list.setSelectionMode(QAbstractItemView.SingleSelection)
        self.keys_list.setFixedWidth(150)
        self.keys_list.setAlternatingRowColors(True)
        ml.addWidget(self.keys_list)
        self.value_text = QTextEdit(self)
        self.value_text.setTabStopWidth(24)
        self.value_text.setReadOnly(True)
        ml.addWidget(self.value_text, 1)
 
        button_box = QDialogButtonBox(QDialogButtonBox.Ok)
        button_box.accepted.connect(self.accept)
        button_box.setCenterButtons(True)
        layout.addWidget(button_box)
        
    def _populate_settings(self):
        self.keys_list.clear()
        ns_prefix = 'namespaced:%s:'% self.namespace 
        keys = sorted([k[len(ns_prefix):] for k in self.db.prefs.iterkeys() 
                       if k.startswith(ns_prefix)])
        for key in keys:
            self.keys_list.addItem(key)
        self.keys_list.setMinimumWidth(self.keys_list.sizeHintForColumn(0)) 
        self.keys_list.currentRowChanged[int].connect(self._current_row_changed)

    def _current_row_changed(self, new_row):
        if new_row < 0:
            self.value_text.clear()
            return
        key = unicode(self.keys_list.currentItem().text())
        val = self.db.prefs.get_namespaced(self.namespace, key, '')
        self.value_text.setPlainText(self.db.prefs.to_raw(val))
        
Exemple #5
0
class SearchDialog(SizePersistedDialog):
    def __init__(self, parent=None, mm=None):
        SizePersistedDialog.__init__(self, parent,
                                     'casanova plugin:search dialog')
        self.setWindowTitle('Search Casanova:')
        self.gui = parent
        self.mm = mm

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.search_label = QLabel('Search for:')
        layout.addWidget(self.search_label)
        self.search_str = QLineEdit(self)
        self.search_str.setText('')
        layout.addWidget(self.search_str)
        self.search_label.setBuddy(self.search_str)

        self.find_button = QPushButton("&Find")
        self.search_button_box = QDialogButtonBox(Qt.Horizontal)
        self.search_button_box.addButton(self.find_button,
                                         QDialogButtonBox.ActionRole)
        self.search_button_box.clicked.connect(self._find_clicked)
        layout.addWidget(self.search_button_box)

        self.values_list = QListWidget(self)
        self.values_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        layout.addWidget(self.values_list)

        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                           | QDialogButtonBox.Cancel)
        self.button_box.accepted.connect(self._accept_clicked)
        self.button_box.rejected.connect(self.reject)
        layout.addWidget(self.button_box)

        # Cause our dialog size to be restored from prefs or created on first usage
        self.resize_dialog()

    def _display_choices(self, choices):
        self.values_list.clear()
        for id, name in choices.items():
            item = QListWidgetItem(get_icon('images/books.png'), name,
                                   self.values_list)
            item.setData(1, (id, ))
            self.values_list.addItem(item)

    def _find_clicked(self):
        query = unicode(self.search_str.text())
        self._display_choices(self.mm.search(query))

    def _accept_clicked(self):
        #self._save_preferences()
        self.selected_texts = []
        for item in self.values_list.selectedItems():
            self.selected_texts.append(item.data(1).toPyObject()[0])
        self.accept()
Exemple #6
0
class SearchDialog(SizePersistedDialog):

    def __init__(self, parent=None, func=None, title="Search"):
        SizePersistedDialog.__init__(self, parent, 'arg plugin:search dialog')
        self.setWindowTitle(title)
        self.gui = parent
        self.func = func
        
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.search_label = QLabel(title)
        layout.addWidget(self.search_label)
        self.search_str = QLineEdit(self)
        self.search_str.setText('')
        layout.addWidget(self.search_str)
        self.search_label.setBuddy(self.search_str)

        self.find_button = QPushButton("&Find")
        self.search_button_box = QDialogButtonBox(Qt.Horizontal)
        self.search_button_box.addButton(self.find_button, QDialogButtonBox.ActionRole)
        self.search_button_box.clicked.connect(self._find_clicked)
        layout.addWidget(self.search_button_box)        

        self.values_list = QListWidget(self)
        # for multiple selection
        #self.values_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        layout.addWidget(self.values_list)
        
        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.button_box.accepted.connect(self._accept_clicked)
        self.button_box.rejected.connect(self.reject)
        layout.addWidget(self.button_box)

        # Cause our dialog size to be restored from prefs or created on first usage
        self.resize_dialog()

    def _display_choices(self, choices):
        self.values_list.clear()
        for id, name in choices.items():
            item = QListWidgetItem(get_icon('images/books.png'), name, self.values_list)
            item.setData(1, (id,))
            self.values_list.addItem(item)

    def _find_clicked(self):
        query = unicode(self.search_str.text())
        self._display_choices(self.func(query))

    def _accept_clicked(self):
        #self._save_preferences()
        self.selected_result = None
        if self.values_list.currentItem():
            i = self.values_list.currentItem()
            self.selected_result = (i.data(1)[0], i.text())
        self.accept() 
Exemple #7
0
class ChooseFormatToDownloadDialog(SizePersistedDialog):
    def __init__(self, parent=None, dm=None, casanova_id=None):
        SizePersistedDialog.__init__(self, parent,
                                     'casanova plugin:format download dialog')
        self.setWindowTitle('Select format to download:')
        self.gui = parent
        self.dm = dm
        self.casanova_id = casanova_id

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.values_list = QListWidget(self)
        self.values_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        layout.addWidget(self.values_list)

        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                           | QDialogButtonBox.Cancel)
        self.button_box.accepted.connect(self._accept_clicked)
        self.button_box.rejected.connect(self.reject)
        layout.addWidget(self.button_box)

        self._display_formats()

        # Cause our dialog size to be restored from prefs or created on first usage
        self.resize_dialog()

    def _display_formats(self):
        self.values_list.clear()
        formats = self.dm.get_download_info(self.casanova_id)
        if isinstance(formats, list):
            for format in formats:
                item = QListWidgetItem(get_icon('images/books.png'),
                                       format['type'], self.values_list)
                item.setData(1, (format, ))
                self.values_list.addItem(item)
        else:
            return error_dialog(self.gui,
                                'Casanova message',
                                unicode(formats),
                                show=True)

    def _accept_clicked(self):
        #self._save_preferences()
        self.selected_format = None
        for item in self.values_list.selectedItems():
            self.selected_format = item.data(1).toPyObject()[0]
        self.accept()
Exemple #8
0
class SelectTagsDialog(QDialog):
    def __init__(self, parent, modal=True, flags=Qt.WindowFlags(), caption="Select Tags", ok_button="Select"):
        QDialog.__init__(self, parent, flags)
        self.setModal(modal)
        self.setWindowTitle(caption)
        lo = QVBoxLayout(self)
        lo.setMargin(10)
        lo.setSpacing(5)
        # tag selector
        self.wtagsel = QListWidget(self)
        lo.addWidget(self.wtagsel)
        #    self.wtagsel.setColumnMode(QListBox.FitToWidth)
        self.wtagsel.setSelectionMode(QListWidget.MultiSelection)
        QObject.connect(self.wtagsel, SIGNAL("itemSelectionChanged()"), self._check_tag)
        # buttons
        lo.addSpacing(10)
        lo2 = QHBoxLayout()
        lo.addLayout(lo2)
        lo2.setContentsMargins(0, 0, 0, 0)
        lo2.setMargin(5)
        self.wokbtn = QPushButton(ok_button, self)
        self.wokbtn.setMinimumWidth(128)
        QObject.connect(self.wokbtn, SIGNAL("clicked()"), self.accept)
        self.wokbtn.setEnabled(False)
        cancelbtn = QPushButton("Cancel", self)
        cancelbtn.setMinimumWidth(128)
        QObject.connect(cancelbtn, SIGNAL("clicked()"), self.reject)
        lo2.addWidget(self.wokbtn)
        lo2.addStretch(1)
        lo2.addWidget(cancelbtn)
        self.setMinimumWidth(384)
        self._tagnames = []

    def setTags(self, tagnames):
        self._tagnames = tagnames
        self.wtagsel.clear()
        self.wtagsel.insertItems(0, list(tagnames))

    def _check_tag(self):
        for i in range(len(self._tagnames)):
            if self.wtagsel.item(i).isSelected():
                self.wokbtn.setEnabled(True)
                return
        else:
            self.wokbtn.setEnabled(False)

    def getSelectedTags(self):
        return [tag for i, tag in enumerate(self._tagnames) if self.wtagsel.item(i).isSelected()]
Exemple #9
0
class ChooseFormatToDownloadDialog(SizePersistedDialog):

    def __init__(self, parent=None, dm=None, casanova_id=None):
        SizePersistedDialog.__init__(self, parent, 'casanova plugin:format download dialog')
        self.setWindowTitle('Select format to download:')
        self.gui = parent
        self.dm = dm
        self.casanova_id = casanova_id

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.values_list = QListWidget(self)
        self.values_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        layout.addWidget(self.values_list)
        
        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.button_box.accepted.connect(self._accept_clicked)
        self.button_box.rejected.connect(self.reject)
        layout.addWidget(self.button_box)

        self._display_formats()

        # Cause our dialog size to be restored from prefs or created on first usage
        self.resize_dialog()

    def _display_formats(self):
        self.values_list.clear()
        formats = self.dm.get_download_info(self.casanova_id)
        if isinstance(formats, list):
            for format in formats:
                item = QListWidgetItem(get_icon('images/books.png'), format['type'], self.values_list)
                item.setData(1, (format,))
                self.values_list.addItem(item)
        else:
            return error_dialog(self.gui, 'Casanova message', unicode(formats), show=True) 
        

    def _accept_clicked(self):
        #self._save_preferences()
        self.selected_format = None
        for item in self.values_list.selectedItems():
            self.selected_format = item.data(1).toPyObject()[0]
        self.accept()
Exemple #10
0
class ChooseIssuesToUpdateDialog(SizePersistedDialog):
    def __init__(self, parent=None, mm=None):
        SizePersistedDialog.__init__(self, parent,
                                     'casanova plugin:issues update dialog')
        self.setWindowTitle('Select issues to update:')
        self.gui = parent
        self.mm = mm

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.values_list = QListWidget(self)
        self.values_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        layout.addWidget(self.values_list)

        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                           | QDialogButtonBox.Cancel)
        self.button_box.accepted.connect(self._accept_clicked)
        self.button_box.rejected.connect(self.reject)
        layout.addWidget(self.button_box)

        self._display_issues()

        # Cause our dialog size to be restored from prefs or created on first usage
        self.resize_dialog()

    def _display_issues(self):
        self.values_list.clear()
        issues = self.mm.get_all_issues(True)
        for id, issue in issues:
            item = QListWidgetItem(get_icon('images/books.png'), issue,
                                   self.values_list)
            item.setData(1, (id, ))
            self.values_list.addItem(item)

    def _accept_clicked(self):
        #self._save_preferences()
        self.selected_issues = []
        for item in self.values_list.selectedItems():
            self.selected_issues.append(item.data(1).toPyObject()[0])
        self.accept()
Exemple #11
0
class ChooseIssuesToUpdateDialog(SizePersistedDialog):

    def __init__(self, parent=None, mm=None):
        SizePersistedDialog.__init__(self, parent, 'casanova plugin:issues update dialog')
        self.setWindowTitle('Select issues to update:')
        self.gui = parent
        self.mm = mm

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.values_list = QListWidget(self)
        self.values_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        layout.addWidget(self.values_list)
        
        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.button_box.accepted.connect(self._accept_clicked)
        self.button_box.rejected.connect(self.reject)
        layout.addWidget(self.button_box)

        self._display_issues()

        # Cause our dialog size to be restored from prefs or created on first usage
        self.resize_dialog()

    def _display_issues(self):
        self.values_list.clear()
        issues = self.mm.get_all_issues(True)
        for id, issue in issues:
            item = QListWidgetItem(get_icon('images/books.png'), issue, self.values_list)
            item.setData(1, (id,))
            self.values_list.addItem(item)

    def _accept_clicked(self):
        #self._save_preferences()
        self.selected_issues = []
        for item in self.values_list.selectedItems():
        	self.selected_issues.append(item.data(1).toPyObject()[0])
        self.accept()
class PrefsViewerDialog(SizePersistedDialog):

    def __init__(self, gui, namespace):
        SizePersistedDialog.__init__(self, gui, 'Prefs Viewer dialog')
        self.setWindowTitle('Preferences for: '+namespace)

        self.gui = gui
        self.db = gui.current_db
        self.namespace = namespace
        self._init_controls()
        self.resize_dialog()

        self._populate_settings()

        if self.keys_list.count():
            self.keys_list.setCurrentRow(0)

    def _init_controls(self):
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        ml = QHBoxLayout()
        layout.addLayout(ml, 1)

        self.keys_list = QListWidget(self)
        self.keys_list.setSelectionMode(QAbstractItemView.SingleSelection)
        self.keys_list.setFixedWidth(150)
        self.keys_list.setAlternatingRowColors(True)
        ml.addWidget(self.keys_list)
        self.value_text = QTextEdit(self)
        self.value_text.setTabStopWidth(24)
        self.value_text.setReadOnly(True)
        ml.addWidget(self.value_text, 1)

        button_box = QDialogButtonBox(QDialogButtonBox.Ok)
        button_box.accepted.connect(self.accept)
        self.clear_button = button_box.addButton('Clear', QDialogButtonBox.ResetRole)
        self.clear_button.setIcon(get_icon('trash.png'))
        self.clear_button.setToolTip('Clear all settings for this plugin')
        self.clear_button.clicked.connect(self._clear_settings)
        layout.addWidget(button_box)

    def _populate_settings(self):
        self.keys_list.clear()
        ns_prefix = self._get_ns_prefix()
        keys = sorted([k[len(ns_prefix):] for k in self.db.prefs.iterkeys()
                       if k.startswith(ns_prefix)])
        for key in keys:
            self.keys_list.addItem(key)
        self.keys_list.setMinimumWidth(self.keys_list.sizeHintForColumn(0))
        self.keys_list.currentRowChanged[int].connect(self._current_row_changed)

    def _current_row_changed(self, new_row):
        if new_row < 0:
            self.value_text.clear()
            return
        key = unicode(self.keys_list.currentItem().text())
        val = self.db.prefs.get_namespaced(self.namespace, key, '')
        self.value_text.setPlainText(self.db.prefs.to_raw(val))

    def _get_ns_prefix(self):
        return 'namespaced:%s:'% self.namespace

    def _clear_settings(self):
        from calibre.gui2.dialogs.confirm_delete import confirm
        message = '<p>Are you sure you want to clear your settings in this library for this plugin?</p>' \
                  '<p>Any settings in other libraries or stored in a JSON file in your calibre plugins ' \
                  'folder will not be touched.</p>' \
                  '<p>You must restart calibre afterwards.</p>'
        if not confirm(message, self.namespace+'_clear_settings', self):
            return
        ns_prefix = self._get_ns_prefix()
        keys = [k for k in self.db.prefs.iterkeys() if k.startswith(ns_prefix)]
        for k in keys:
            del self.db.prefs[k]
        self._populate_settings()
        d = info_dialog(self, 'Settings deleted',
                    '<p>All settings for this plugin in this library have been cleared.</p>'
                    '<p>Please restart calibre now.</p>',
                    show_copy_button=False)
        b = d.bb.addButton(_('Restart calibre now'), d.bb.AcceptRole)
        b.setIcon(QIcon(I('lt.png')))
        d.do_restart = False
        def rf():
            d.do_restart = True
        b.clicked.connect(rf)
        d.set_details('')
        d.exec_()
        b.clicked.disconnect()
        self.close()
        if d.do_restart:
            self.gui.quit(restart=True)
Exemple #13
0
class PrefsViewerDialog(SizePersistedDialog):
    def __init__(self, gui, namespace):
        SizePersistedDialog.__init__(self, gui, 'Prefs Viewer dialog')
        self.setWindowTitle('Preferences for: ' + namespace)

        self.gui = gui
        self.db = gui.current_db
        self.namespace = namespace
        self._init_controls()
        self.resize_dialog()

        self._populate_settings()

        if self.keys_list.count():
            self.keys_list.setCurrentRow(0)

    def _init_controls(self):
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        ml = QHBoxLayout()
        layout.addLayout(ml, 1)

        self.keys_list = QListWidget(self)
        self.keys_list.setSelectionMode(QAbstractItemView.SingleSelection)
        self.keys_list.setFixedWidth(150)
        self.keys_list.setAlternatingRowColors(True)
        ml.addWidget(self.keys_list)
        self.value_text = QTextEdit(self)
        self.value_text.setTabStopWidth(24)
        self.value_text.setReadOnly(False)
        ml.addWidget(self.value_text, 1)

        button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                      | QDialogButtonBox.Cancel)
        button_box.accepted.connect(self._apply_changes)
        button_box.rejected.connect(self.reject)
        self.clear_button = button_box.addButton('Clear',
                                                 QDialogButtonBox.ResetRole)
        self.clear_button.setIcon(get_icon('trash.png'))
        self.clear_button.setToolTip('Clear all settings for this plugin')
        self.clear_button.clicked.connect(self._clear_settings)
        layout.addWidget(button_box)

    def _populate_settings(self):
        self.keys_list.clear()
        ns_prefix = self._get_ns_prefix()
        keys = sorted([
            k[len(ns_prefix):] for k in self.db.prefs.iterkeys()
            if k.startswith(ns_prefix)
        ])
        for key in keys:
            self.keys_list.addItem(key)
        self.keys_list.setMinimumWidth(self.keys_list.sizeHintForColumn(0))
        self.keys_list.currentRowChanged[int].connect(
            self._current_row_changed)

    def _current_row_changed(self, new_row):
        if new_row < 0:
            self.value_text.clear()
            return
        key = unicode(self.keys_list.currentItem().text())
        val = self.db.prefs.get_namespaced(self.namespace, key, '')
        self.value_text.setPlainText(self.db.prefs.to_raw(val))

    def _get_ns_prefix(self):
        return 'namespaced:%s:' % self.namespace

    def _apply_changes(self):
        from calibre.gui2.dialogs.confirm_delete import confirm
        message = '<p>Are you sure you want to change your settings in this library for this plugin?</p>' \
                  '<p>Any settings in other libraries or stored in a JSON file in your calibre plugins ' \
                  'folder will not be touched.</p>' \
                  '<p>You must restart calibre afterwards.</p>'
        if not confirm(message, self.namespace + '_clear_settings', self):
            return

        val = self.db.prefs.raw_to_object(
            unicode(self.value_text.toPlainText()))
        key = unicode(self.keys_list.currentItem().text())
        self.db.prefs.set_namespaced(self.namespace, key, val)

        restart = prompt_for_restart(
            self, 'Settings changed',
            '<p>Settings for this plugin in this library have been changed.</p>'
            '<p>Please restart calibre now.</p>')
        self.close()
        if restart:
            self.gui.quit(restart=True)

    def _clear_settings(self):
        from calibre.gui2.dialogs.confirm_delete import confirm
        message = '<p>Are you sure you want to clear your settings in this library for this plugin?</p>' \
                  '<p>Any settings in other libraries or stored in a JSON file in your calibre plugins ' \
                  'folder will not be touched.</p>' \
                  '<p>You must restart calibre afterwards.</p>'
        if not confirm(message, self.namespace + '_clear_settings', self):
            return

        ns_prefix = self._get_ns_prefix()
        keys = [k for k in self.db.prefs.iterkeys() if k.startswith(ns_prefix)]
        for k in keys:
            del self.db.prefs[k]
        self._populate_settings()
        restart = prompt_for_restart(
            self, 'Settings deleted',
            '<p>All settings for this plugin in this library have been cleared.</p>'
            '<p>Please restart calibre now.</p>')
        self.close()
        if restart:
            self.gui.quit(restart=True)
Exemple #14
0
class ManageKeysDialog(QDialog):
    def __init__(self, parent, key_type_name, plugin_keys, create_key, keyfile_ext = u""):
        QDialog.__init__(self,parent)
        self.parent = parent
        self.key_type_name = key_type_name
        self.plugin_keys = plugin_keys
        self.create_key = create_key
        self.keyfile_ext = keyfile_ext
        self.import_key = (keyfile_ext != u"")
        self.binary_file = (key_type_name == u"Adobe Digital Editions Key")
        self.json_file = (key_type_name == u"Kindle for Mac and PC Key")

        self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name))

        # Start Qt Gui dialog layout
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        help_layout = QHBoxLayout()
        layout.addLayout(help_layout)
        # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked.
        help_label = QLabel('<a href="http://www.foo.com/">Help</a>', self)
        help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard)
        help_label.setAlignment(Qt.AlignRight)
        help_label.linkActivated.connect(self.help_link_activated)
        help_layout.addWidget(help_label)

        keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self)
        layout.addWidget(keys_group_box)
        keys_group_box_layout = QHBoxLayout()
        keys_group_box.setLayout(keys_group_box_layout)

        self.listy = QListWidget(self)
        self.listy.setToolTip(u"{0}s that will be used to decrypt ebooks".format(self.key_type_name))
        self.listy.setSelectionMode(QAbstractItemView.SingleSelection)
        self.populate_list()
        keys_group_box_layout.addWidget(self.listy)

        button_layout = QVBoxLayout()
        keys_group_box_layout.addLayout(button_layout)
        self._add_key_button = QtGui.QToolButton(self)
        self._add_key_button.setToolTip(u"Create new {0}".format(self.key_type_name))
        self._add_key_button.setIcon(QIcon(I('plus.png')))
        self._add_key_button.clicked.connect(self.add_key)
        button_layout.addWidget(self._add_key_button)

        self._delete_key_button = QtGui.QToolButton(self)
        self._delete_key_button.setToolTip(_(u"Delete highlighted key"))
        self._delete_key_button.setIcon(QIcon(I('list_remove.png')))
        self._delete_key_button.clicked.connect(self.delete_key)
        button_layout.addWidget(self._delete_key_button)

        if type(self.plugin_keys) == dict:
            self._rename_key_button = QtGui.QToolButton(self)
            self._rename_key_button.setToolTip(_(u"Rename highlighted key"))
            self._rename_key_button.setIcon(QIcon(I('edit-select-all.png')))
            self._rename_key_button.clicked.connect(self.rename_key)
            button_layout.addWidget(self._rename_key_button)

            self.export_key_button = QtGui.QToolButton(self)
            self.export_key_button.setToolTip(u"Save highlighted key to a .{0} file".format(self.keyfile_ext))
            self.export_key_button.setIcon(QIcon(I('save.png')))
            self.export_key_button.clicked.connect(self.export_key)
            button_layout.addWidget(self.export_key_button)
        spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
        button_layout.addItem(spacerItem)

        layout.addSpacing(5)
        migrate_layout = QHBoxLayout()
        layout.addLayout(migrate_layout)
        if self.import_key:
            migrate_layout.setAlignment(Qt.AlignJustify)
            self.migrate_btn = QPushButton(u"Import Existing Keyfiles", self)
            self.migrate_btn.setToolTip(u"Import *.{0} files (created using other tools).".format(self.keyfile_ext))
            self.migrate_btn.clicked.connect(self.migrate_wrapper)
            migrate_layout.addWidget(self.migrate_btn)
        migrate_layout.addStretch()
        self.button_box = QDialogButtonBox(QDialogButtonBox.Close)
        self.button_box.rejected.connect(self.close)
        migrate_layout.addWidget(self.button_box)

        self.resize(self.sizeHint())

    def populate_list(self):
        if type(self.plugin_keys) == dict:
            for key in self.plugin_keys.keys():
                self.listy.addItem(QListWidgetItem(key))
        else:
            for key in self.plugin_keys:
                self.listy.addItem(QListWidgetItem(key))

    def add_key(self):
        d = self.create_key(self)
        d.exec_()

        if d.result() != d.Accepted:
            # New key generation cancelled.
            return
        new_key_value = d.key_value
        if type(self.plugin_keys) == dict:
            if new_key_value in self.plugin_keys.values():
                old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0]
                info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name),
                                    u"The new {1} is the same as the existing {1} named <strong>{0}</strong> and has not been added.".format(old_key_name,self.key_type_name), show=True)
                return
            self.plugin_keys[d.key_name] = new_key_value
        else:
            if new_key_value in self.plugin_keys:
                info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name),
                                    u"This {0} is already in the list of {0}s has not been added.".format(self.key_type_name), show=True)
                return

            self.plugin_keys.append(d.key_value)
        self.listy.clear()
        self.populate_list()

    def rename_key(self):
        if not self.listy.currentItem():
            errmsg = u"No {0} selected to rename. Highlight a keyfile first.".format(self.key_type_name)
            r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                                    _(errmsg), show=True, show_copy_button=False)
            return

        d = RenameKeyDialog(self)
        d.exec_()

        if d.result() != d.Accepted:
            # rename cancelled or moot.
            return
        keyname = unicode(self.listy.currentItem().text().toUtf8(),'utf8')
        if not question_dialog(self, "{0} {1}: Confirm Rename".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to rename the {2} named <strong>{0}</strong> to <strong>{1}</strong>?".format(keyname,d.key_name,self.key_type_name), show_copy_button=False, default_yes=False):
            return
        self.plugin_keys[d.key_name] = self.plugin_keys[keyname]
        del self.plugin_keys[keyname]

        self.listy.clear()
        self.populate_list()

    def delete_key(self):
        if not self.listy.currentItem():
            return
        keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8')
        if not question_dialog(self, "{0} {1}: Confirm Delete".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to delete the {1} <strong>{0}</strong>?".format(keyname, self.key_type_name), show_copy_button=False, default_yes=False):
            return
        if type(self.plugin_keys) == dict:
            del self.plugin_keys[keyname]
        else:
            self.plugin_keys.remove(keyname)

        self.listy.clear()
        self.populate_list()

    def help_link_activated(self, url):
        def get_help_file_resource():
            # Copy the HTML helpfile to the plugin directory each time the
            # link is clicked in case the helpfile is updated in newer plugins.
            help_file_name = u"{0}_{1}_Help.htm".format(PLUGIN_NAME, self.key_type_name)
            file_path = os.path.join(config_dir, u"plugins", u"DeDRM", u"help", help_file_name)
            with open(file_path,'w') as f:
                f.write(self.parent.load_resource(help_file_name))
            return file_path
        url = 'file:///' + get_help_file_resource()
        open_url(QUrl(url))

    def migrate_files(self):
        dynamic[PLUGIN_NAME + u"config_dir"] = config_dir
        files = choose_files(self, PLUGIN_NAME + u"config_dir",
                u"Select {0} files to import".format(self.key_type_name), [(u"{0} files".format(self.key_type_name), [self.keyfile_ext])], False)
        counter = 0
        skipped = 0
        if files:
            for filename in files:
                fpath = os.path.join(config_dir, filename)
                filename = os.path.basename(filename)
                new_key_name = os.path.splitext(os.path.basename(filename))[0]
                with open(fpath,'rb') as keyfile:
                    new_key_value = keyfile.read()
                if self.binary_file:
                    new_key_value = new_key_value.encode('hex')
                elif self.json_file:
                    new_key_value = json.loads(new_key_value)
                match = False
                for key in self.plugin_keys.keys():
                    if uStrCmp(new_key_name, key, True):
                        skipped += 1
                        msg = u"A key with the name <strong>{0}</strong> already exists!\nSkipping key file  <strong>{1}</strong>.\nRename the existing key and import again".format(new_key_name,filename)
                        inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                                _(msg), show_copy_button=False, show=True)
                        match = True
                        break
                if not match:
                    if new_key_value in self.plugin_keys.values():
                        old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0]
                        skipped += 1
                        info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                                            u"The key in file {0} is the same as the existing key <strong>{1}</strong> and has been skipped.".format(filename,old_key_name), show_copy_button=False, show=True)
                    else:
                        counter += 1
                        self.plugin_keys[new_key_name] = new_key_value

            msg = u""
            if counter+skipped > 1:
                if counter > 0:
                    msg += u"Imported <strong>{0:d}</strong> key {1}. ".format(counter, u"file" if counter == 1 else u"files")
                if skipped > 0:
                    msg += u"Skipped <strong>{0:d}</strong> key {1}.".format(skipped, u"file" if counter == 1 else u"files")
                inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                                    _(msg), show_copy_button=False, show=True)
        return counter > 0

    def migrate_wrapper(self):
        if self.migrate_files():
            self.listy.clear()
            self.populate_list()

    def export_key(self):
        if not self.listy.currentItem():
            errmsg = u"No keyfile selected to export. Highlight a keyfile first."
            r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                                    _(errmsg), show=True, show_copy_button=False)
            return
        filter = QString(u"{0} Files (*.{1})".format(self.key_type_name, self.keyfile_ext))
        keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8')
        if dynamic.get(PLUGIN_NAME + 'save_dir'):
            defaultname = os.path.join(dynamic.get(PLUGIN_NAME + 'save_dir'), u"{0}.{1}".format(keyname , self.keyfile_ext))
        else:
            defaultname = os.path.join(os.path.expanduser('~'), u"{0}.{1}".format(keyname , self.keyfile_ext))
        filename = unicode(QtGui.QFileDialog.getSaveFileName(self, u"Save {0} File as...".format(self.key_type_name), defaultname,
                                            u"{0} Files (*.{1})".format(self.key_type_name,self.keyfile_ext), filter))
        if filename:
            dynamic[PLUGIN_NAME + 'save_dir'] = os.path.split(filename)[0]
            with file(filename, 'w') as fname:
                if self.binary_file:
                    fname.write(self.plugin_keys[keyname].decode('hex'))
                elif self.json_file:
                    fname.write(json.dumps(self.plugin_keys[keyname]))
                else:
                    fname.write(self.plugin_keys[keyname])
class PluginObject(object):

   tabName = 'Pass Phrase Finder'
   maxVersion = '0.93.99'
   
   #############################################################################
   def __init__(self, main):
      self.searchThread = None
      self.passPhraseFinder = None
      self.isSearchOver = False
      
      def updateResults(resultStr):
         self.resultStr += resultStr
         
      def updateDisplay():
         if len(self.resultStr) > 0:
            self.resultsDisplay.append(self.resultStr)
            self.resultStr = ''
            self.resultsDisplay.moveCursor(QtGui.QTextCursor.End)
            self.resultsDisplay.repaint()
         if self.isSearchOver:
            endSearch()
      
      # Call this from another thread to end the search
      def terminateSearch():
         self.isSearchOver = True
      
      # Call this from the main thread to end the search
      def endSearch():
         self.main.extraHeartbeatAlways.remove(updateDisplay)
         self.searchButton.setEnabled(True)
         self.stopButton.setEnabled(False)
         # If the thread is still searching tell the pass phrase finder to stop
         if self.passPhraseFinder and self.searchThread  and not self.searchThread.isFinished():
            self.passPhraseFinder.isStopped = True
            
      def searchForPassphrase():
         # Get the selected wallet from the main screen
         wlt = self.getSelectedWlt()
         if wlt and not wlt.watchingOnly and wlt.isLocked:
            self.resultStr = ''
            self.passPhraseFinder = PassPhraseFinder(wlt)
            self.resultsDisplay.setText(QString(''))
            self.main.extraHeartbeatAlways.append(updateDisplay)
            if len(self.segOrdStrSet) > 0:
               # From self.segOrdStrList, create a list of lists of indexes that describe the segment orderings to search
               # In other words convert all of the strings in orderings list to lists of integers
               segOrdIntListList = []
               for ordStr in self.segOrdStrSet:
                  # The indexes provided by the users are 1 based, and the list indexes ought to be 0 based
                  segOrdIntListList.append([int(indexStr)-1 for indexStr in ordStr.split(',')])
               self.searchThread = PyBackgroundThread(self.passPhraseFinder.searchForPassPhrase, 
                  [segDef.getSegList() for segDef in self.segDefList], 
                  segOrdIntListList, 
                  updateResults,
                  terminateSearch )
               # Reset the isSearchOver flag
               self.isSearchOver = False
               self.searchThread.start()
               
               # Disable search button adn enabled stop button
               self.stopButton.setEnabled(True)
               self.searchButton.setEnabled(False)
            else:
               QMessageBox.warning(self.main, tr('Invalid'), tr("""
                  There are no valid segment combinations to search.
                  Please add at least one segment and ordering to search."""), QMessageBox.Ok)
         else:
            QMessageBox.warning(self.main, tr('Invalid'), tr("""
               No valid wallet is selected. Please select a locked
               non-watching-only from Available Wallets."""), QMessageBox.Ok)

      def addKnownSegment():
         dlgEnterSegment = DlgEnterSegment(main, main)
         if dlgEnterSegment.exec_():
            segmentText = str(dlgEnterSegment.editSegment.text())
            if len(segmentText)>0:
               self.segDefList.append(KnownSeg(segmentText))
               self.segDefTableModel.updateSegList(self.segDefList)
      
      def addUnknownCaseSegment():
         dlgEnterSegment = DlgEnterSegment(main, main)
         if dlgEnterSegment.exec_():
            segmentText = str(dlgEnterSegment.editSegment.text())
            if len(segmentText)>0:
               self.segDefList.append(UnknownCaseSeg(segmentText))
               self.segDefTableModel.updateSegList(self.segDefList)
               
      def addUnknownOrderSegment():
         dlgEnterSegment = DlgEnterSegment(main, main, isUnknownOrder=True)
         if dlgEnterSegment.exec_():
            segmentText = str(dlgEnterSegment.editSegment.text())
            minLen = int(str(dlgEnterSegment.minSelector.currentText()))
            maxLen = int(str(dlgEnterSegment.maxSelector.currentText()))
            if len(segmentText)>0:
               self.segDefList.append(UnknownSeg(segmentText, minLen, maxLen))
               self.segDefTableModel.updateSegList(self.segDefList)

      def addOrdering():
         if len(self.segDefList) > 0:
            dlgSpecifyOrdering = DlgSpecifyOrdering(main, main, len(self.segDefList))     
            if dlgSpecifyOrdering.exec_():
               self.segOrdStrSet.add(str(dlgSpecifyOrdering.parseOrderingList()).strip('[]'))
               self.updateOrderingListBox()
         else:
            QMessageBox.warning(self.main, tr('Not Ready'), tr("""
               No segments have been entered. You must enter some segments before you can order them."""), QMessageBox.Ok)

      
      self.main = main
      self.segDefList = []
      self.segOrdStrSet = set()
      segmentHeader = QRichLabel(tr("""<b>Build segments for pass phrase search: </b>"""), doWrap=False)
      self.knownButton = QPushButton("Add Known Segment")
      self.unknownCaseButton = QPushButton("Add Unknown Case Segment")
      self.unknownOrderButton = QPushButton("Add Unknown Order Segment")
      self.main.connect(self.knownButton, SIGNAL('clicked()'), addKnownSegment)
      self.main.connect(self.unknownCaseButton, SIGNAL('clicked()'), addUnknownCaseSegment)
      self.main.connect(self.unknownOrderButton, SIGNAL('clicked()'), addUnknownOrderSegment)
      topRow =  makeHorizFrame([segmentHeader, self.knownButton, self.unknownCaseButton, self.unknownOrderButton, 'stretch'])
      
      self.segDefTableModel = SegDefDisplayModel()
      self.segDefTableView = QTableView()
      self.segDefTableView.setModel(self.segDefTableModel)
      self.segDefTableView.setSelectionBehavior(QTableView.SelectRows)
      self.segDefTableView.setSelectionMode(QTableView.SingleSelection)
      self.segDefTableView.verticalHeader().setDefaultSectionSize(20)
      self.segDefTableView.verticalHeader().hide()
      
      h = tightSizeNChar(self.segDefTableView, 1)[1]
      self.segDefTableView.setMinimumHeight(2 * (1.3 * h))
      self.segDefTableView.setMaximumHeight(10 * (1.3 * h))      
      initialColResize(self.segDefTableView, [.1, .2, .4, .1, .1, .1])

      self.segDefTableView.customContextMenuRequested.connect(self.showSegContextMenu)
      self.segDefTableView.setContextMenuPolicy(Qt.CustomContextMenu)
      
      segmentOrderingsHeader = QRichLabel(tr("""<b>Specify orderings for pass phrase search: </b>"""), doWrap=False)
      self.addOrderingButton = QPushButton("Add Ordering")
      
      
      self.main.connect(self.addOrderingButton, SIGNAL('clicked()'), addOrdering)
      orderingButtonPanel = makeHorizFrame([segmentOrderingsHeader, self.addOrderingButton, 'stretch'])

      self.segOrdListBox  = QListWidget()
      
      self.segOrdListBox.customContextMenuRequested.connect(self.showOrdContextMenu)
      self.segOrdListBox.setContextMenuPolicy(Qt.CustomContextMenu)
      
      
      self.searchButton = QPushButton("Search")
      self.main.connect(self.searchButton, SIGNAL('clicked()'), searchForPassphrase)
      self.stopButton = QPushButton("Stop Searching")
      self.stopButton.setEnabled(False)
      self.main.connect(self.stopButton, SIGNAL('clicked()'), endSearch)
      totalSearchLabel = QRichLabel(tr("""<b>Total Passphrase Tries To Search: </b>"""), doWrap=False)
      self.totalSearchTriesDisplay = QLineEdit()
      self.totalSearchTriesDisplay.setReadOnly(True)
      self.totalSearchTriesDisplay.setText(QString('0'))
      self.totalSearchTriesDisplay.setFont(GETFONT('Fixed'))
      self.totalSearchTriesDisplay.setMinimumWidth(tightSizeNChar(self.totalSearchTriesDisplay, 6)[0])
      self.totalSearchTriesDisplay.setMaximumWidth(tightSizeNChar(self.totalSearchTriesDisplay, 12)[0])
      searchButtonPanel = makeHorizFrame([self.searchButton, self.stopButton, 'stretch', totalSearchLabel,  self.totalSearchTriesDisplay])
      
      self.resultsDisplay = QTextEdit()
      self.resultsDisplay.setReadOnly(True)
      self.resultsDisplay.setFont(GETFONT('Fixed'))
      self.resultsDisplay.setMinimumHeight(100)
      self.searchPanel = makeVertFrame([topRow, self.segDefTableView, orderingButtonPanel,
             self.segOrdListBox, searchButtonPanel, self.resultsDisplay, 'stretch'])
      # Now set the scrollarea widget to the layout
      self.tabToDisplay = QScrollArea()
      self.tabToDisplay.setWidgetResizable(True)
      self.tabToDisplay.setWidget(self.searchPanel)
   
   def getSelectedWlt(self):
      wlt = None
      selectedWltList = self.main.walletsView.selectedIndexes()
      if len(selectedWltList)>0:
            row = selectedWltList[0].row()
            wltID = str(self.main.walletsView.model().index(row, WLTVIEWCOLS.ID).data().toString())
            wlt = self.main.walletMap[wltID]
      return wlt
   
   def showSegContextMenu(self):
      menu = QMenu(self.segDefTableView)
      if len(self.segDefTableView.selectedIndexes())==0:
         return

      row = self.segDefTableView.selectedIndexes()[0].row()
      deleteSegMenuItem = menu.addAction("Delete Segment")
      action = menu.exec_(QCursor.pos())
      
      if action == deleteSegMenuItem:
         self.deleteSegRow(row)
         
   def showOrdContextMenu(self):
      menu = QMenu(self.segOrdListBox)
      if len(self.segOrdListBox.selectedItems())==0:
         return

      item = self.segOrdListBox.currentItem()
      deleteOrdMenuItem = menu.addAction("Delete Ordering")
      action = menu.exec_(QCursor.pos())
      
      if action == deleteOrdMenuItem:
         self.deleteOrdItem(item)
         
   def deleteSegRow(self, row):
      self.segDefList.remove(self.segDefList[row])
      self.segDefTableModel.updateSegList(self.segDefList)
      self.segOrdStrSet.clear()
      self.updateOrderingListBox()
   
         
   def deleteOrdItem(self, ordItem):
      ordText = str(ordItem.text())
      self.segOrdStrSet.remove(ordText)
      self.updateOrderingListBox()
   
   
   def getTabToDisplay(self):
      return self.tabToDisplay

   def updateOrderingListBox(self):
      self.segOrdListBox.clear()
      segOrdList = list(self.segOrdStrSet)
      segOrdList.sort()
      totalTries = 0
      for ordStr in segOrdList:
         self.segOrdListBox.addItem(QListWidgetItem(ordStr))
         totalTries += self.calculateTries(ordStr)
      if totalTries > BILLION_INT:
         self.totalSearchTriesDisplay.setText(OVER_BILLION_STR)
      else:         
         self.totalSearchTriesDisplay.setText(str(totalTries))
      
   def calculateTries(self, ordStr):
      ordIntList = [int(indexStr) for indexStr in ordStr.split(',')]
      totalTries = 1
      # Multiply each of the totals of segment instance together.
      for ordInt in ordIntList:
         totalTries *= self.segDefList[ordInt-1].getSegListLen()
      return totalTries
class PM_Clipboard(PM_GroupBox):
    """
    The PM_Clipboard class provides a groupbox containing a list of clipboard
    items that can be pasted in the 3D Workspace. The selected item in this
    list is shown by its elementViewer (an instance of L{PM_PreviewGroupBox})
    The object being previewed can then be deposited into the 3D workspace.
    """
    def __init__(self,
                parentWidget,
                title = 'Clipboard',
                win   = None,
                elementViewer = None
                ):

        """
        Appends a PM_Clipboard groupbox widget to I{parentWidget},a L{PM_Dialog}

        @param parentWidget: The parent dialog (Property manager) containing
                             this  widget.
        @type  parentWidget: L{PM_Dialog}

        @param title: The title (button) text.
        @type  title: str

        @param win: MainWindow object
        @type  win: L{MWsemantics} or None

        @param elementViewer: The associated preview pane groupbox. If provided,
                              The selected item in L{self.clipboardListWidget}
                              is shown (previewed) by L{elementViewer}.
                              The object being previewed can then be deposited
                              into the 3D workspace.
        @type  elementViewer: L{PM_PreviewGroupBox} or None

        """

        self.w = win
        self.elementViewer = elementViewer
        self.elementViewer.setDisplay(diTUBES)
        self.pastableItems = None

        PM_GroupBox.__init__(self, parentWidget, title)

        self._loadClipboardGroupbox()


    def _loadClipboardGroupbox(self):
        """
        Load the L{self.clipboardListWidget} widget used to display a list of
        clipboard items inside this  clipboard  groupbox.
        """
        self.clipboardListWidget = QListWidget(self)

        self.gridLayout.addWidget(self.clipboardListWidget)
        #Append to the widget list. This is important for expand -collapse
        #functions (of the groupbox) to work properly.
        self._widgetList.append(self.clipboardListWidget)

    def _updateElementViewer(self, newModel = None):
        """
        Update the view of L{self.elementViewer}
        @param newModel: The model correseponding to the item selected
                         in L{self.clipboardListWidget}.
        @type  newModel: L{molecule} or L{Group}
        """
        if not self.elementViewer:
            return

        assert isinstance(self.elementViewer, MMKitView)
        self.elementViewer.resetView()
        if newModel:
            self.elementViewer.updateModel(newModel)

    def update(self):
        """
        Updates the clipboard items in the L{PM_Clipboard} groupbox. Also
        updates its element viewer.
        """
        PM_GroupBox.update(self)
        self.pastableItems = self.w.assy.shelf.getPastables()
        i = self.clipboardListWidget.currentRow()
        self.clipboardListWidget.clear()
        newModel = None

        if len(self.pastableItems):
            for item in self.pastableItems:
                self.clipboardListWidget.addItem(item.name)

            if i >= self.clipboardListWidget.count():
                i = self.clipboardListWidget.count() - 1

            if i < 0:
                i = 0

            self.clipboardListWidget.setCurrentItem(
                    self.clipboardListWidget.item(i))


            newModel = self.pastableItems[i]

        self._updateElementViewer(newModel)

    def clipboardListItemChanged(self, currentItem = None, previousItem = None):
        """
        Slot method. Called when user clicks on a different pastable item
        displayed in this groupbox
        @param currentItem: Current item in the L{self.clipboardListWidget}
                            that is selected
        @type  currentItem: U{B{QListWidgetItem}
                            <http://doc.trolltech.com/4.2/qlistwidgetitem.html>}
        @param previousItem: Previously selected item in the
                            L{self.clipboardListWidget}
        @type  previousItem: U{B{QListWidgetItem}
                            <http://doc.trolltech.com/4.2/qlistwidgetitem.html>}
        """

        if not (currentItem or previousItem):
            return

        itemId = self.clipboardListWidget.row(currentItem)

        if itemId != -1:

            newChunk = self.pastableItems[itemId]
            self.clipboardListWidget.setCurrentRow(itemId)
            self._updateElementViewer(newChunk)


    def connect_or_disconnect_signals(self, isConnect):
        """
        Connect or disconnect widget signals sent to their slot methods.
        @param isConnect: If True the widget will send the signals to the slot
                          method.
        @type  isConnect: boolean
        """
        if isConnect:
            change_connect = self.w.connect
        else:
            change_connect = self.w.disconnect

        change_connect(
            self.clipboardListWidget,
            SIGNAL("currentItemChanged(QListWidgetItem*,QListWidgetItem*)"),
            self.clipboardListItemChanged )

    def currentRow(self):
        """
        Return the current row of the selected item in this groupbox's
        listwidget ( L{self.clipboardListWidget} )
        @return: Current Row of the selected pastable item in the
                 clipboard groupbox.
        @rtype: int
        """
        currentRow = self.clipboardListWidget.currentRow()
        return currentRow
Exemple #17
0
class PM_Clipboard(PM_GroupBox):
    """
    The PM_Clipboard class provides a groupbox containing a list of clipboard
    items that can be pasted in the 3D Workspace. The selected item in this
    list is shown by its elementViewer (an instance of L{PM_PreviewGroupBox})
    The object being previewed can then be deposited into the 3D workspace.
    """
    def __init__(self,
                 parentWidget,
                 title='Clipboard',
                 win=None,
                 elementViewer=None):
        """
        Appends a PM_Clipboard groupbox widget to I{parentWidget},a L{PM_Dialog}

        @param parentWidget: The parent dialog (Property manager) containing
                             this  widget.
        @type  parentWidget: L{PM_Dialog}

        @param title: The title (button) text.
        @type  title: str

        @param win: MainWindow object
        @type  win: L{MWsemantics} or None

        @param elementViewer: The associated preview pane groupbox. If provided,
                              The selected item in L{self.clipboardListWidget}
                              is shown (previewed) by L{elementViewer}.
                              The object being previewed can then be deposited
                              into the 3D workspace.
        @type  elementViewer: L{PM_PreviewGroupBox} or None

        """

        self.w = win
        self.elementViewer = elementViewer
        self.elementViewer.setDisplay(diTUBES)
        self.pastableItems = None

        PM_GroupBox.__init__(self, parentWidget, title)

        self._loadClipboardGroupbox()

    def _loadClipboardGroupbox(self):
        """
        Load the L{self.clipboardListWidget} widget used to display a list of
        clipboard items inside this  clipboard  groupbox.
        """
        self.clipboardListWidget = QListWidget(self)

        self.gridLayout.addWidget(self.clipboardListWidget)
        #Append to the widget list. This is important for expand -collapse
        #functions (of the groupbox) to work properly.
        self._widgetList.append(self.clipboardListWidget)

    def _updateElementViewer(self, newModel=None):
        """
        Update the view of L{self.elementViewer}
        @param newModel: The model correseponding to the item selected
                         in L{self.clipboardListWidget}.
        @type  newModel: L{molecule} or L{Group}
        """
        if not self.elementViewer:
            return

        assert isinstance(self.elementViewer, MMKitView)
        self.elementViewer.resetView()
        if newModel:
            self.elementViewer.updateModel(newModel)

    def update(self):
        """
        Updates the clipboard items in the L{PM_Clipboard} groupbox. Also
        updates its element viewer.
        """
        PM_GroupBox.update(self)
        self.pastableItems = self.w.assy.shelf.getPastables()
        i = self.clipboardListWidget.currentRow()
        self.clipboardListWidget.clear()
        newModel = None

        if len(self.pastableItems):
            for item in self.pastableItems:
                self.clipboardListWidget.addItem(item.name)

            if i >= self.clipboardListWidget.count():
                i = self.clipboardListWidget.count() - 1

            if i < 0:
                i = 0

            self.clipboardListWidget.setCurrentItem(
                self.clipboardListWidget.item(i))

            newModel = self.pastableItems[i]

        self._updateElementViewer(newModel)

    def clipboardListItemChanged(self, currentItem=None, previousItem=None):
        """
        Slot method. Called when user clicks on a different pastable item
        displayed in this groupbox
        @param currentItem: Current item in the L{self.clipboardListWidget}
                            that is selected
        @type  currentItem: U{B{QListWidgetItem}
                            <http://doc.trolltech.com/4.2/qlistwidgetitem.html>}
        @param previousItem: Previously selected item in the
                            L{self.clipboardListWidget}
        @type  previousItem: U{B{QListWidgetItem}
                            <http://doc.trolltech.com/4.2/qlistwidgetitem.html>}
        """

        if not (currentItem or previousItem):
            return

        itemId = self.clipboardListWidget.row(currentItem)

        if itemId != -1:

            newChunk = self.pastableItems[itemId]
            self.clipboardListWidget.setCurrentRow(itemId)
            self._updateElementViewer(newChunk)

    def connect_or_disconnect_signals(self, isConnect):
        """
        Connect or disconnect widget signals sent to their slot methods.
        @param isConnect: If True the widget will send the signals to the slot
                          method.
        @type  isConnect: boolean
        """
        if isConnect:
            change_connect = self.w.connect
        else:
            change_connect = self.w.disconnect

        change_connect(
            self.clipboardListWidget,
            SIGNAL("currentItemChanged(QListWidgetItem*,QListWidgetItem*)"),
            self.clipboardListItemChanged)

    def currentRow(self):
        """
        Return the current row of the selected item in this groupbox's
        listwidget ( L{self.clipboardListWidget} )
        @return: Current Row of the selected pastable item in the
                 clipboard groupbox.
        @rtype: int
        """
        currentRow = self.clipboardListWidget.currentRow()
        return currentRow
Exemple #18
0
class AddBookDialog(SizePersistedDialog):
    def __init__(self, parent=None, mm=None, mi=None):
        SizePersistedDialog.__init__(self, parent,
                                     'casanova plugin:add book dialog')
        self.setWindowTitle('Add text to Casanova:')
        self.gui = parent
        self.mm = mm
        self.mi = mi
        self.one_line_description = ''

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.one_liner_label = QLabel(
            'Enter a short description (255 chars max) before pressing OK')
        layout.addWidget(self.one_liner_label)
        self.one_liner_str = QLineEdit(self)
        self.one_liner_str.setText('')
        layout.addWidget(self.one_liner_str)
        self.one_liner_label.setBuddy(self.one_liner_str)

        self.values_label = QLabel(
            'Below are potential matches of texts that already exist - please make sure you are adding something new'
        )
        layout.addWidget(self.values_label)
        self.values_list = QListWidget(self)
        self.values_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        layout.addWidget(self.values_list)

        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                           | QDialogButtonBox.Cancel)
        self.button_box.accepted.connect(self._accept_clicked)
        self.button_box.rejected.connect(self.reject)
        layout.addWidget(self.button_box)

        self._display_choices()

        # Cause our dialog size to be restored from prefs or created on first usage
        self.resize_dialog()

    def _display_choices(self):
        self.values_list.clear()
        choices = self.mm.search(self.mi.title)
        if choices is None or len(choices) == 0:
            item = QListWidgetItem(get_icon('images/books.png'),
                                   _('there seem to be no matches'),
                                   self.values_list)
            self.values_list.addItem(item)
        for id, name in choices.items():
            item = QListWidgetItem(get_icon('images/books.png'), name,
                                   self.values_list)
            item.setData(1, (id, ))
            self.values_list.addItem(item)

    def _accept_clicked(self):
        #self._save_preferences()
        one_liner = unicode(self.one_liner_str.text())
        if one_liner == '':
            self.values_list.clear()
            item = QListWidgetItem(get_icon('images/books.png'),
                                   _('you need to enter a short description'),
                                   self.values_list)
            self.values_list.addItem(item)
        else:
            self.one_line_description = one_liner
        self.accept()
Exemple #19
0
class IpetPbHistoryWindow(IpetMainWindow):

    NO_SELECTION_TEXT = "no selection"
    default_cmap = 'spectral'
    imagepath = osp.sep.join((osp.dirname(__file__), osp.pardir, "images"))

    DEBUG = True

    def __init__(self, testrunfiles=[], evaluationfile=None):
        QtGui.QMainWindow.__init__(self)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.setWindowTitle("application main window")

        self.file_menu = QtGui.QMenu('&File', self)
        self.file_menu.addAction('&Quit', self.fileQuit,
                                 QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
        self.menuBar().addMenu(self.file_menu)
        loadaction = self.createAction(
            "&Load",
            self.loadTestruns,
            QKeySequence.Open,
            icon="Load-icon",
            tip="Load testrun from trn file (current test run gets discarded)")
        resetaction = self.createAction(
            "&Reset selected names",
            self.resetSelectedTestrunNames,
            QKeySequence.Undo,
            icon="",
            tip="Reset names of selected test runs")
        self.file_menu.addAction(loadaction)
        self.help_menu = QtGui.QMenu('&Help', self)
        self.edit_menu = QtGui.QMenu('&Edit', self)
        self.edit_menu.addAction(resetaction)
        self.menuBar().addSeparator()
        self.menuBar().addMenu(self.help_menu)
        self.menuBar().addMenu(self.edit_menu)

        self.help_menu.addAction('&About', self.about)

        self.main_widget = QtGui.QWidget(self)

        lwframe = QFrame(self.main_widget)
        l = QtGui.QVBoxLayout(self.main_widget)
        self.sc = MyStaticMplCanvas(self.main_widget,
                                    width=5,
                                    height=4,
                                    dpi=100)
        toolbar = IpetNavigationToolBar(self.sc, self.main_widget)

        l.addWidget(toolbar)
        l.addWidget(self.sc)
        h = QtGui.QHBoxLayout(lwframe)
        l.addWidget(lwframe)

        self.trListWidget = QListWidget()
        #         for item in list("ABC"):
        #             self.trListWidget.addItem((item))
        self.trListWidget.setSelectionMode(QAbstractItemView.ExtendedSelection)
        h.addWidget(self.trListWidget)
        self.connect(self.trListWidget, SIGNAL("itemSelectionChanged()"),
                     self.selectionChanged)

        self.trListWidget.itemChanged.connect(self.testrunItemChanged)

        v = QtGui.QVBoxLayout(lwframe)

        self.probListWidget = QListWidget()
        #         for item in list("12345"):
        #             self.probListWidget.addItem((item))
        self.probListWidget.setSelectionMode(
            QAbstractItemView.ExtendedSelection)
        v.addWidget(self.probListWidget)
        self.connect(self.probListWidget, SIGNAL("itemSelectionChanged()"),
                     self.selectionChanged)

        self.testSetWidget = QListWidget()
        v.addWidget(self.testSetWidget)
        self.testSetWidget.addItem(self.NO_SELECTION_TEXT)
        for t in TestSets.getTestSets():
            self.testSetWidget.addItem(str(t))
        h.addLayout(v)
        self.connect(self.testSetWidget, SIGNAL("itemSelectionChanged()"),
                     self.selectionChanged)

        self.main_widget.setFocus()
        self.setCentralWidget(self.main_widget)
        self.testruns = []
        self.testrunnames = {}

        for tr in testrunfiles:
            tr = TestRun.loadFromFile(str(tr))
            try:
                self.addTestrun(tr)
            except Exception as e:
                print(e)

        self.evaluation = None
        if evaluationfile is not None:
            self.evaluation = IPETEvaluation.fromXMLFile(evaluationfile)


#         self.primallines = {}
#         self.duallines = {}
#         self.primalpatches = {}

        self.statusBar().showMessage("Ready to load some test run data!", 5000)

    def createAction(self,
                     text,
                     slot=None,
                     shortcut=None,
                     icon=None,
                     tip=None,
                     checkable=False,
                     signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(
                QIcon(osp.sep.join((self.imagepath, "%s.png" % icon))))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)

        return action

    def getSelectedProblist(self):
        selectedprobs = [
            str(item.text()) for item in self.probListWidget.selectedItems()
        ]
        selitem = self.testSetWidget.selectedItems()[0]
        if selitem.text() != self.NO_SELECTION_TEXT:
            testsetprobs = set(TestSets.getTestSetByName(selitem.text()))
            selectedprobs = [p for p in selectedprobs if p in testsetprobs]

        return selectedprobs

    def getSelectedTestrunList(self):
        return [
            tr for idx, tr in enumerate(self.testruns)
            if self.trListWidget.isItemSelected(self.trListWidget.item(idx))
        ]

    def selectionChanged(self):
        if len(self.testruns) == 0:
            return

        problist = self.getSelectedProblist()
        if len(problist) == 0:
            return

        testruns = self.getSelectedTestrunList()
        if len(testruns) == 0:
            return

        self.update_Axis(problist, testruns)

    def testrunItemChanged(self):
        curritem = self.trListWidget.currentItem()

        if not curritem:
            return

        rowindex = self.trListWidget.currentRow()
        if rowindex < 0 or rowindex > len(self.testruns):
            return

        newtext = str(curritem.text())
        testrun = self.testruns[rowindex]

        self.setTestrunName(testrun, newtext)

    def resetSelectedTestrunNames(self):
        for tr in self.getSelectedTestrunList():
            self.resetTestrunName(tr)

    def getTestrunName(self, testrun):
        """
        returns the test run name as specified by the user
        """
        return self.testrunnames.get(testrun.getName(), testrun.getName())

    def setTestrunName(self, testrun, newname):
        self.debugMessage("Changing testrun name from %s to %s" %
                          (self.getTestrunName(testrun), newname))

        self.testrunnames[testrun.getName()] = newname

    def resetTestrunName(self, testrun):
        try:
            del self.testrunnames[testrun.getName()]
            item = self.trListWidget.item(self.testruns.index(testrun))
            item.setText((self.getTestrunName(testrun)))
        except KeyError:
            pass

    def updateStatus(self, message):
        self.statusBar().showMessage(message, 5000)

    def fileQuit(self):
        self.close()

    def addTestrun(self, tr):
        self.testruns.append(tr)
        self.probListWidget.clear()
        self.trListWidget.clear()

        for testrun in self.testruns:
            item = QListWidgetItem((self.getTestrunName(testrun)))
            self.trListWidget.addItem(item)
            item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)

        problems = []
        if len(self.testruns) > 0:
            problems = self.testruns[0].getProblemNames()
        if len(self.testruns) > 1:
            for testrun in self.testruns[1:]:
                problems = [
                    p for p in problems if p in set(testrun.getProblemNames())
                ]

        for prob in sorted(problems):
            self.probListWidget.addItem(str(prob))

        self.trListWidget.selectAll()

    def closeEvent(self, ce):
        self.fileQuit()

    def debugMessage(self, message):
        if self.DEBUG:
            print(message)
        else:
            pass

    def loadTestruns(self):
        thedir = str(".")
        filenames = QFileDialog.getOpenFileNames(
            self,
            caption=("%s - Load testruns" % QApplication.applicationName()),
            directory=thedir,
            filter=str("Testrun files (*.trn)"))
        if filenames:
            loadedtrs = 0
            notloadedtrs = 0
            for filename in filenames:
                try:
                    print(filename)
                    tr = TestRun.loadFromFile(str(filename))
                    try:
                        self.addTestrun(tr)
                    except Exception as e:
                        print(e)

                    loadedtrs += 1
                except Exception:
                    notloadedtrs += 1

            message = "Loaded %d/%d test runs" % (loadedtrs,
                                                  loadedtrs + notloadedtrs)
            self.updateStatus(message)

        pass

    def update_Axis(self, probnames, testruns):
        """
        update method called every time a new instance was selected
        """
        #self.resetAxis()
        # make up data for plotting method
        x = {}
        y = {}
        z = {}
        zx = {}
        kws = {}
        duallinekws = {}
        dualbarkws = {}
        baseline = 0

        if len(probnames) == 1:
            self.updateStatus("Showing problem %s on %d test runs" %
                              (probnames[0], len(testruns)))
        else:
            self.updateStatus("Showing mean over %d problems on %d test runs" %
                              (len(probnames), len(testruns)))
        self.resetAxis()
        usenormalization = True
        showdualbound = True
        xmax = xmin = ymax = ymin = 0
        labelorder = []
        for testrun in testruns:
            testrunname = self.getTestrunName(testrun)

            if len(probnames) == 1:
                x[testrunname], y[testrunname] = getProcessPlotData(
                    testrun, probnames[0], usenormalization, access="name")
            else:
                x[testrunname], y[testrunname] = getMeanIntegral(testrun,
                                                                 probnames,
                                                                 access="name")
            if not usenormalization and len(probnames) == 1:
                baseline = testrun.problemGetOptimalSolution(probnames[0])
                y[testrunname] -= baseline

            xmax = max(xmax, max(x[testrunname]))
            ymax = max(ymax, max(y[testrunname]))
            ymin = min(ymin, min(y[testrunname]))
            print(y[testrunname])
            print(y[testrunname][1:] - y[testrunname][:-1] > 0)
            if numpy.any(y[testrunname][1:] - y[testrunname][:-1] > 0):
                logging.warn(
                    "Error: Increasing primal gap function on problems {}".
                    format(probnames))
            if showdualbound:
                arguments = {
                    "historytouse": Key.DualBoundHistory,
                    "boundkey": Key.DualBound
                }
                if len(probnames) == 1:
                    zx[testrunname], z[testrunname] = getProcessPlotData(
                        testrun,
                        probnames[0],
                        usenormalization,
                        access="name",
                        **arguments)
                else:
                    zx[testrunname], z[testrunname] = getMeanIntegral(
                        testrun, probnames, access="name", **arguments)

                # normalization requires negative dual gap
                if usenormalization:
                    z[testrunname] = -numpy.array(z[testrunname])

                ymin = min(ymin, min(z[testrunname]))

                duallinekws[testrunname] = dict(linestyle='dashed')
                dualbarkws = dict(alpha=0.1)

            # set special key words for the testrun
            kws[testrunname] = dict(alpha=0.1)
            labelorder.append(testrunname)
            # for now, only one color cycle exists
            #colormap = cm.get_cmap(name='spectral', lut=128)
            #self.axes.set_color_cycle([colormap(i) for i in numpy.linspace(0.1, 0.9, len(self.gui.getTestrunList()))])

            # call the plot on the collected data
        self.primalpatches, self.primallines, _ = self.axisPlotForTestrunData(
            x,
            y,
            baseline=baseline,
            legend=False,
            labelsuffix=" (primal)",
            plotkw=kws,
            barkw=kws,
            labelorder=labelorder)
        if showdualbound:
            __, self.duallines, _ = self.axisPlotForTestrunData(
                zx,
                z,
                step=False,
                baseline=0,
                legend=False,
                labelsuffix=" (dual)",
                plotkw=duallinekws,
                barkw=dualbarkws,
                labelorder=labelorder)

        # set a legend and limits
        self.sc.axes.legend(fontsize=8)
        self.sc.axes.set_xlim(
            (xmin - 0.05 * (xmax - xmin), xmax + 0.05 * (xmax - xmin)))
        self.sc.axes.set_ylim(
            (ymin - 0.1 * (ymax - ymin), ymax + 0.1 * (ymax - ymin)),
            emit=True)

        self.sc.draw()

    def axisPlotForTestrunData(self,
                               dataX,
                               dataY,
                               bars=False,
                               step=True,
                               barwidthfactor=1.0,
                               baseline=0,
                               testrunnames=None,
                               legend=True,
                               labelsuffix="",
                               colormapname="spectral",
                               plotkw=None,
                               barkw=None,
                               labelorder=[]):
        """
        create a plot for your X and Y data. The data can either be specified as matrix, or as a dictionary
        specifying containing the labels as keys.

        - returns the axes object and a dictionary {label:line} of the line plots that were added

        arguments:
        -dataX : The X data for the plot, exspected either as
                    1: A dictionary with the plot labels as keys and some iterable as value-list
                    OR
                    2: A list of some iterables which denote the X values.

        -dataY : The y plot data of the plot. Must be specified in the same way as the X data

        -testrunnames: labels for axis legend. they will overwrite the labels specified by dictionary-organized data.
                       if testrunnames == None, the primallines will either be labelled from '0' to 'len(dataX)-1',
                       or inferred from the dataX-keys().
        -ax: matplotlib axes object, will be created as new axis if not specified

        -legend: specify if legend should be created, default True
        -colormapname: name of the colormap to use in case no colors are specified by the 'colors' argument

        -kw, other keywords for the plotting function, such as transparency, etc. can be specified for every plot
            separately, either as a dictionary with the dataX-keys, or as a kw-list with the same length as the
            dataX list
        """

        # index everything by labels, either given as dictionary keys, or integer indices ranging from 0 to len(dataX) - 1
        assert type(dataX) is type(dataY)
        if type(dataX) is dict:
            labels = list(dataX.keys())
            if testrunnames is None:
                testrunnames = {label: label for label in labels}
        else:
            assert type(dataX) is list
            labels = list(range(len(dataX)))

            if testrunnames is None:
                testrunnames = {label: repr(label) for label in labels}

        # init colors if not given

        try:
            colormap = cm.get_cmap(name=colormapname, lut=128)
        except ValueError:
            print("Colormap of name ", colormapname, " does not exist")
            colormap = cm.get_cmap(name=IpetPbHistoryWindow.default_cmap,
                                   lut=128)
        colortransform = numpy.linspace(0.1, 0.9, len(labels))

        colors = {
            label: colormap(colortransform[index])
            for index, label in enumerate(labels)
        }

        patches = {}
        lines = {}

        if not labelorder:
            labelorder = sorted(labels)
        for label in labelorder:
            # retrieve special key words, or use the entire keyword dictionary
            if plotkw is not None:
                linekw = plotkw.get(testrunnames[label], plotkw)
            else:
                linekw = {}
            if barkw is not None:
                bkw = barkw.get(testrunnames[label], barkw)
            else:
                bkw = {}

            x = dataX[label]
            y = dataY[label]
            idd = testrunnames[label]
            if bars:
                patches[idd] = self.sc.axes.bar(x[:-1],
                                                y[:-1],
                                                width=barwidthfactor *
                                                (x[1:] - x[:-1]),
                                                bottom=baseline,
                                                color=colors[label],
                                                linewidth=0,
                                                **bkw)
            else:
                patches[idd] = []
            # # use step functions for primal and plot for dual plots
            plotlabel = idd + labelsuffix
            if step:
                #lines[idd], = ax.step(x, y + baseline, color=colors[label], label=idd, where='post')
                lines[idd], = self.sc.axes.step(x,
                                                y,
                                                label=plotlabel,
                                                where='post')
            else:
                #lines[idd], = ax.plot(x, y + baseline, color=colors[label], label=idd, **linekw)
                lines[idd], = self.sc.axes.plot(x,
                                                y + baseline,
                                                label=plotlabel,
                                                **linekw)

        if len(labels) > 0 and legend:
            self.sc.axes.legend(fontsize=8)
        return (patches, lines, self.sc.axes)

    def resetAxis(self):
        """
        reset axis by removing all primallines and primalpatches previously drawn.
        """
        self.sc.axes.cla()

    def about(self):
        QtGui.QMessageBox.about(
            self, "About", """embedding_in_qt4.py example
Copyright 2005 Florent Rougon, 2006 Darren Dale

This program is a simple example of a Qt4 application embedding matplotlib
canvases.

It may be used and modified with no restriction; raw copies as well as
modified versions may be distributed without limitation.""")
Exemple #20
0
class tab_widget(QtGui.QTabWidget):
    
    
    # Initiate Widget. 
    def __init__(self, parent=MainWindow):
        super(tab_widget, self).__init__()
        self.initUI()
    
    # Create interface, and connect buttons to signals.
    def initUI(self):
        vbox_inner = QVBoxLayout()
        grid = QtGui.QGridLayout()
        
        self.genreList = ['Fiction', 'Fact book', 'Poetry']
        
        # Tab 1: Add Data        
        self.author_label = QLabel("Author")
        self.author_text = QLineEdit()
        self.author_text.setPlaceholderText("Author")
        grid.addWidget(self.author_label, 0, 0)
        grid.addWidget(self.author_text, 1, 0)
        
        self.title_label = QLabel("Title")
        self.title_text = QLineEdit()
        self.title_text.setPlaceholderText("Title")

        grid.addWidget(self.title_label, 0, 1)
        grid.addWidget(self.title_text, 1, 1)

        self.date_label = QLabel("Date Read")
        self.date_text = QLineEdit()
        self.date_text.setPlaceholderText("yy-mm-dd")
        grid.addWidget(self.date_label, 2, 1)
        grid.addWidget(self.date_text, 3, 1)
        
        self.grade_label = QLabel("Grade")
        self.grade_text = QLineEdit()
        self.grade_text.setPlaceholderText("Grade 1-5")
        grid.addWidget(self.grade_label, 2, 0)
        grid.addWidget(self.grade_text, 3, 0)
        
        self.comments_label = QLabel("Comments")
        self.comments_text = QLineEdit()
        self.comments_text.setPlaceholderText("Comments here")
        grid.addWidget(self.comments_label, 4, 0)
        grid.addWidget(self.comments_text, 5, 0)

        self.genre_label = QLabel("Genre")
        self.genre_list = QListWidget(self)
        self.genre_list.addItems(self.genreList)
        self.genre_list.setObjectName('genre_list')
        self.genre_list.itemClicked.connect(self.item_clicked)
        grid.addWidget(self.genre_label, 6, 0)
        grid.addWidget(self.genre_list, 7, 0)
        
        self.genre2_label = QLabel("Genre2")
        self.genre2_list = QListWidget(self)
        self.genre2_list.setObjectName("genre2")
        self.genre2_list.addItem("Select genre first")
        grid.addWidget(self.genre2_label, 6, 1)
        grid.addWidget(self.genre2_list, 7, 1)
        
        
        # Tab 2:Get Data from file
        self.authorData = QLineEdit()
        self.authorData.setPlaceholderText("Author")
        self.authorData.setReadOnly(True)
        vbox_inner.addWidget(self.authorData)
        
        self.titleData = QLineEdit()
        self.titleData.setPlaceholderText("Title")
        self.titleData.setReadOnly(True)
        vbox_inner.addWidget(self.titleData)
        
        self.genreData = QLineEdit()
        self.genreData.setPlaceholderText("Genre")
        self.genreData.setReadOnly(True)
        vbox_inner.addWidget(self.genreData)
        
        self.genre2Data = QLineEdit()
        self.genre2Data.setPlaceholderText("Genre2")
        self.genre2Data.setReadOnly(True)
        vbox_inner.addWidget(self.genre2Data)
        
        self.dateData = QLineEdit()
        self.dateData.setPlaceholderText("Date read")
        self.dateData.setReadOnly(True)
        vbox_inner.addWidget(self.dateData)
        
        self.gradeData = QLineEdit()
        self.gradeData.setPlaceholderText("Grade")
        self.gradeData.setReadOnly(True)
        vbox_inner.addWidget(self.gradeData)
        
        self.commentsData = QLineEdit()
        self.commentsData.setPlaceholderText("Comments")
        self.commentsData.setReadOnly(True)
        vbox_inner.addWidget(self.commentsData)
        
        self.titles_list = QListWidget(self)
        self.titles_list.addItems(getTitlesFromFile())
        vbox_inner.addWidget(self.titles_list)
        
        
        self.getTitleData = QtGui.QPushButton("Get title data", self)
        self.getTitleData.clicked.connect(self.buttonClicked)
        vbox_inner.addWidget(self.getTitleData)
        
        
        self.submit = QtGui.QPushButton("Submit Data", self)
        self.submit.clicked.connect(self.buttonClicked)            
        grid.addWidget(self.submit, 8, 1)
            
        self.quit = QtGui.QPushButton("Exit", self)
        self.quit.clicked.connect(QtCore.QCoreApplication.instance().quit)
        self.quit.setMaximumWidth(80)
        grid.addWidget(self.quit, 8, 0)
    
        tab1 = QWidget()
        tab1.setLayout(grid)
        
        tab2 = QWidget()
        tab2.setLayout(vbox_inner)
    
        self.addTab(tab1, "Add Data")
        self.addTab(tab2, "Get Data")
        self.move(150, 150)
        self.show()
        
    # Function for when a QListWidgetItem is clicked if the genre_list is 
    # clicked, will check which genre was chosen and populate genre2_list
    # with subgenres of that genre.    
    def item_clicked(self):
        genre = self.sender()
        if genre.objectName() == "genre_list":
            curr = genre.currentItem().text()
            if curr == self.genreList[0]:
                genre2List = ["Detective", "autobiograpyh", "Horror", "Comedy"]
            elif curr == self.genreList[1]:
                genre2List = ["Technology", "Biology", "Chemistry", "Mathematics"]
            elif curr == self.genreList[2]:
                genre2List = ["Tirade", "Ballads", "Rhyme"]
            else:
                genre2List = ["None"]
            
            self.genre2_list.clear()
            self.genre2_list.addItems(genre2List)
       
    # Function for when a button is clicked, if 'Submit Data' is clicked,
    # will check that all input is correct format and if so write 
    # the data to the file. If the button pressed is 'Get title data'
    # will get the selected title in the QListWidget and show the row data
    def buttonClicked(self):
        sender = self.sender()
        if sender.text() == "Get title data":
            if self.titles_list.currentItem() != None:
                titleToGet = str(self.titles_list.currentItem().text())
                titleData = findTitleData(titleToGet)
                splitLine = []
                splitLine = titleData.split(",", 7)
                                
                self.authorData.setText('Author: '+splitLine[0].replace('"', "").lstrip())
                self.titleData.setText('Title: '+splitLine[1].replace('"', "").lstrip())
                self.genreData.setText('Genre: '+splitLine[2].replace('"', "").lstrip())
                self.genre2Data.setText('Genre2: '+splitLine[3].replace('"', "").lstrip())
                self.dateData.setText('Date Read: '+splitLine[4].replace('"', "").lstrip())
                self.gradeData.setText('Grade: '+splitLine[5].replace('"', "").lstrip())
                self.commentsData.setText('Comments: '+splitLine[6].replace('"', "").lstrip())
                
        elif sender.text() == "Submit Data":
            comments = str(self.comments_text.text())
        
            while True:
                author = str(self.author_text.text())
                if containsDigit(author) == True:
                    QMessageBox.about(self, "Wrong input", "Error: Author cant contain digits")
                    break
                
                if len(author) == 0:
                    QMessageBox.about(self, "Wrong input", "Author is a required field")
                    break
                
                title = str(self.title_text.text())
                try:
                    title = str(self.title_text.text())
                except:
                    QMessageBox.about(self, "Wrong input", "Error in comments, only A-z, 1-9 allowed")
                    break
                
                if len(title) == 0:
                    QMessageBox.about(self, "Wrong input", "Title is a required field")
                    break
                
                
                if self.genre_list.currentItem() != None:
                    genre = str(self.genre_list.currentItem().text())
                else:
                    QMessageBox.about(self, "Wrong input", "Error: Need to pick genre")
                    break
                                    
                if self.genre2_list.currentItem() != None:
                    genre2 = str(self.genre2_list.currentItem().text())
                else:
                    QMessageBox.about(self, "Wrong input", "Error: Need to pick genre2")
                    break
                
                d = str(self.date_text.text())  
                
                if len(d) == 0:
                    QMessageBox.about(self, "Wrong input", "Date is a required field")
                    break
                try:
                    dateRead = datetime.datetime.strptime(d, '%y-%m-%d').date() 
                except:
                    QMessageBox.about(self, "Wrong input", "Error: Date needs to be in format: yy-mm-dd")         
                    break
                
                
                try:
                    grade = int(str(self.grade_text.text()))
                except:
                    QMessageBox.about(self, "Wrong input", "Error: Grade needs to be a number between 1-5")
                    break
                
                if grade > 5 or grade < 1:
                    QMessageBox.about(self, "Wrong input", "Error: Grade needs to be a number between 1-5")
                    break
                
                try:
                    comments = str(self.comments_text.text())
                except:
                    QMessageBox.about(self, "Wrong input", "Error: in comments, only A-z, 1-9 allowed")
                    break
                
                if len(comments) == 0:
                    comments = "No comments"
                
                writeDataToFile(author, title, genre, genre2, str(dateRead), str(grade), comments)
                self.titles_list.clear()
                self.titles_list.addItems(getTitlesFromFile())
                QMessageBox.about(self, "Information", "Data added successfully")
                break
Exemple #21
0
class ManageKeysDialog(QDialog):
    def __init__(self,
                 parent,
                 key_type_name,
                 plugin_keys,
                 create_key,
                 keyfile_ext=u""):
        QDialog.__init__(self, parent)
        self.parent = parent
        self.key_type_name = key_type_name
        self.plugin_keys = plugin_keys
        self.create_key = create_key
        self.keyfile_ext = keyfile_ext
        self.import_key = (keyfile_ext != u"")
        self.binary_file = (key_type_name == u"Adobe Digital Editions Key")
        self.json_file = (key_type_name == u"Kindle for Mac and PC Key")

        self.setWindowTitle("{0} {1}: Manage {2}s".format(
            PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name))

        # Start Qt Gui dialog layout
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        help_layout = QHBoxLayout()
        layout.addLayout(help_layout)
        # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked.
        help_label = QLabel('<a href="http://www.foo.com/">Help</a>', self)
        help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse
                                           | Qt.LinksAccessibleByKeyboard)
        help_label.setAlignment(Qt.AlignRight)
        help_label.linkActivated.connect(self.help_link_activated)
        help_layout.addWidget(help_label)

        keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self)
        layout.addWidget(keys_group_box)
        keys_group_box_layout = QHBoxLayout()
        keys_group_box.setLayout(keys_group_box_layout)

        self.listy = QListWidget(self)
        self.listy.setToolTip(
            u"{0}s that will be used to decrypt ebooks".format(
                self.key_type_name))
        self.listy.setSelectionMode(QAbstractItemView.SingleSelection)
        self.populate_list()
        keys_group_box_layout.addWidget(self.listy)

        button_layout = QVBoxLayout()
        keys_group_box_layout.addLayout(button_layout)
        self._add_key_button = QtGui.QToolButton(self)
        self._add_key_button.setToolTip(u"Create new {0}".format(
            self.key_type_name))
        self._add_key_button.setIcon(QIcon(I('plus.png')))
        self._add_key_button.clicked.connect(self.add_key)
        button_layout.addWidget(self._add_key_button)

        self._delete_key_button = QtGui.QToolButton(self)
        self._delete_key_button.setToolTip(_(u"Delete highlighted key"))
        self._delete_key_button.setIcon(QIcon(I('list_remove.png')))
        self._delete_key_button.clicked.connect(self.delete_key)
        button_layout.addWidget(self._delete_key_button)

        if type(self.plugin_keys) == dict:
            self._rename_key_button = QtGui.QToolButton(self)
            self._rename_key_button.setToolTip(_(u"Rename highlighted key"))
            self._rename_key_button.setIcon(QIcon(I('edit-select-all.png')))
            self._rename_key_button.clicked.connect(self.rename_key)
            button_layout.addWidget(self._rename_key_button)

            self.export_key_button = QtGui.QToolButton(self)
            self.export_key_button.setToolTip(
                u"Save highlighted key to a .{0} file".format(
                    self.keyfile_ext))
            self.export_key_button.setIcon(QIcon(I('save.png')))
            self.export_key_button.clicked.connect(self.export_key)
            button_layout.addWidget(self.export_key_button)
        spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum,
                                       QtGui.QSizePolicy.Expanding)
        button_layout.addItem(spacerItem)

        layout.addSpacing(5)
        migrate_layout = QHBoxLayout()
        layout.addLayout(migrate_layout)
        if self.import_key:
            migrate_layout.setAlignment(Qt.AlignJustify)
            self.migrate_btn = QPushButton(u"Import Existing Keyfiles", self)
            self.migrate_btn.setToolTip(
                u"Import *.{0} files (created using other tools).".format(
                    self.keyfile_ext))
            self.migrate_btn.clicked.connect(self.migrate_wrapper)
            migrate_layout.addWidget(self.migrate_btn)
        migrate_layout.addStretch()
        self.button_box = QDialogButtonBox(QDialogButtonBox.Close)
        self.button_box.rejected.connect(self.close)
        migrate_layout.addWidget(self.button_box)

        self.resize(self.sizeHint())

    def populate_list(self):
        if type(self.plugin_keys) == dict:
            for key in self.plugin_keys.keys():
                self.listy.addItem(QListWidgetItem(key))
        else:
            for key in self.plugin_keys:
                self.listy.addItem(QListWidgetItem(key))

    def add_key(self):
        d = self.create_key(self)
        d.exec_()

        if d.result() != d.Accepted:
            # New key generation cancelled.
            return
        new_key_value = d.key_value
        if type(self.plugin_keys) == dict:
            if new_key_value in self.plugin_keys.values():
                old_key_name = [
                    name for name, value in self.plugin_keys.iteritems()
                    if value == new_key_value
                ][0]
                info_dialog(
                    None,
                    "{0} {1}: Duplicate {2}".format(PLUGIN_NAME,
                                                    PLUGIN_VERSION,
                                                    self.key_type_name),
                    u"The new {1} is the same as the existing {1} named <strong>{0}</strong> and has not been added."
                    .format(old_key_name, self.key_type_name),
                    show=True)
                return
            self.plugin_keys[d.key_name] = new_key_value
        else:
            if new_key_value in self.plugin_keys:
                info_dialog(
                    None,
                    "{0} {1}: Duplicate {2}".format(PLUGIN_NAME,
                                                    PLUGIN_VERSION,
                                                    self.key_type_name),
                    u"This {0} is already in the list of {0}s has not been added."
                    .format(self.key_type_name),
                    show=True)
                return

            self.plugin_keys.append(d.key_value)
        self.listy.clear()
        self.populate_list()

    def rename_key(self):
        if not self.listy.currentItem():
            errmsg = u"No {0} selected to rename. Highlight a keyfile first.".format(
                self.key_type_name)
            r = error_dialog(None,
                             "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                             _(errmsg),
                             show=True,
                             show_copy_button=False)
            return

        d = RenameKeyDialog(self)
        d.exec_()

        if d.result() != d.Accepted:
            # rename cancelled or moot.
            return
        keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8')
        if not question_dialog(
                self,
                "{0} {1}: Confirm Rename".format(PLUGIN_NAME, PLUGIN_VERSION),
                u"Do you really want to rename the {2} named <strong>{0}</strong> to <strong>{1}</strong>?"
                .format(keyname, d.key_name, self.key_type_name),
                show_copy_button=False,
                default_yes=False):
            return
        self.plugin_keys[d.key_name] = self.plugin_keys[keyname]
        del self.plugin_keys[keyname]

        self.listy.clear()
        self.populate_list()

    def delete_key(self):
        if not self.listy.currentItem():
            return
        keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8')
        if not question_dialog(
                self,
                "{0} {1}: Confirm Delete".format(PLUGIN_NAME, PLUGIN_VERSION),
                u"Do you really want to delete the {1} <strong>{0}</strong>?".
                format(keyname, self.key_type_name),
                show_copy_button=False,
                default_yes=False):
            return
        if type(self.plugin_keys) == dict:
            del self.plugin_keys[keyname]
        else:
            self.plugin_keys.remove(keyname)

        self.listy.clear()
        self.populate_list()

    def help_link_activated(self, url):
        def get_help_file_resource():
            # Copy the HTML helpfile to the plugin directory each time the
            # link is clicked in case the helpfile is updated in newer plugins.
            help_file_name = u"{0}_{1}_Help.htm".format(
                PLUGIN_NAME, self.key_type_name)
            file_path = os.path.join(config_dir, u"plugins", u"DeDRM", u"help",
                                     help_file_name)
            with open(file_path, 'w') as f:
                f.write(self.parent.load_resource(help_file_name))
            return file_path

        url = 'file:///' + get_help_file_resource()
        open_url(QUrl(url))

    def migrate_files(self):
        dynamic[PLUGIN_NAME + u"config_dir"] = config_dir
        files = choose_files(
            self, PLUGIN_NAME + u"config_dir",
            u"Select {0} files to import".format(self.key_type_name),
            [(u"{0} files".format(self.key_type_name), [self.keyfile_ext])],
            False)
        counter = 0
        skipped = 0
        if files:
            for filename in files:
                fpath = os.path.join(config_dir, filename)
                filename = os.path.basename(filename)
                new_key_name = os.path.splitext(os.path.basename(filename))[0]
                with open(fpath, 'rb') as keyfile:
                    new_key_value = keyfile.read()
                if self.binary_file:
                    new_key_value = new_key_value.encode('hex')
                elif self.json_file:
                    new_key_value = json.loads(new_key_value)
                match = False
                for key in self.plugin_keys.keys():
                    if uStrCmp(new_key_name, key, True):
                        skipped += 1
                        msg = u"A key with the name <strong>{0}</strong> already exists!\nSkipping key file  <strong>{1}</strong>.\nRename the existing key and import again".format(
                            new_key_name, filename)
                        inf = info_dialog(None,
                                          "{0} {1}".format(
                                              PLUGIN_NAME, PLUGIN_VERSION),
                                          _(msg),
                                          show_copy_button=False,
                                          show=True)
                        match = True
                        break
                if not match:
                    if new_key_value in self.plugin_keys.values():
                        old_key_name = [
                            name
                            for name, value in self.plugin_keys.iteritems()
                            if value == new_key_value
                        ][0]
                        skipped += 1
                        info_dialog(
                            None,
                            "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                            u"The key in file {0} is the same as the existing key <strong>{1}</strong> and has been skipped."
                            .format(filename, old_key_name),
                            show_copy_button=False,
                            show=True)
                    else:
                        counter += 1
                        self.plugin_keys[new_key_name] = new_key_value

            msg = u""
            if counter + skipped > 1:
                if counter > 0:
                    msg += u"Imported <strong>{0:d}</strong> key {1}. ".format(
                        counter, u"file" if counter == 1 else u"files")
                if skipped > 0:
                    msg += u"Skipped <strong>{0:d}</strong> key {1}.".format(
                        skipped, u"file" if counter == 1 else u"files")
                inf = info_dialog(None,
                                  "{0} {1}".format(PLUGIN_NAME,
                                                   PLUGIN_VERSION),
                                  _(msg),
                                  show_copy_button=False,
                                  show=True)
        return counter > 0

    def migrate_wrapper(self):
        if self.migrate_files():
            self.listy.clear()
            self.populate_list()

    def export_key(self):
        if not self.listy.currentItem():
            errmsg = u"No keyfile selected to export. Highlight a keyfile first."
            r = error_dialog(None,
                             "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
                             _(errmsg),
                             show=True,
                             show_copy_button=False)
            return
        filter = QString(u"{0} Files (*.{1})".format(self.key_type_name,
                                                     self.keyfile_ext))
        keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8')
        if dynamic.get(PLUGIN_NAME + 'save_dir'):
            defaultname = os.path.join(
                dynamic.get(PLUGIN_NAME + 'save_dir'),
                u"{0}.{1}".format(keyname, self.keyfile_ext))
        else:
            defaultname = os.path.join(
                os.path.expanduser('~'),
                u"{0}.{1}".format(keyname, self.keyfile_ext))
        filename = unicode(
            QtGui.QFileDialog.getSaveFileName(
                self, u"Save {0} File as...".format(self.key_type_name),
                defaultname,
                u"{0} Files (*.{1})".format(self.key_type_name,
                                            self.keyfile_ext), filter))
        if filename:
            dynamic[PLUGIN_NAME + 'save_dir'] = os.path.split(filename)[0]
            with file(filename, 'w') as fname:
                if self.binary_file:
                    fname.write(self.plugin_keys[keyname].decode('hex'))
                elif self.json_file:
                    fname.write(json.dumps(self.plugin_keys[keyname]))
                else:
                    fname.write(self.plugin_keys[keyname])
class tab_widget(QtGui.QTabWidget):
    
    
    # Initiate Widget. 
    def __init__(self, parent=MainWindow):
        super(tab_widget, self).__init__()
        self.initUI()
    
    # Create all object thats in the AddData tab
    def makeAddDataTab(self, grid):
        self.author_label = QLabel("Author")
        self.author_text = QLineEdit()
        self.author_text.setPlaceholderText("Author")
        grid.addWidget(self.author_label, 0, 0)
        grid.addWidget(self.author_text, 1, 0)
        self.title_label = QLabel("Title")
        self.title_text = QLineEdit()
        self.title_text.setPlaceholderText("Title")
        grid.addWidget(self.title_label, 0, 1)
        grid.addWidget(self.title_text, 1, 1)
        self.date_label = QLabel("Date Read")
        self.date_text = QLineEdit()
        self.date_text.setPlaceholderText("yy-mm-dd")
        grid.addWidget(self.date_label, 2, 1)
        grid.addWidget(self.date_text, 3, 1)
        self.grade_label = QLabel("Grade")
        self.grade_text = QLineEdit()
        self.grade_text.setPlaceholderText("Grade 1-5")
        grid.addWidget(self.grade_label, 2, 0)
        grid.addWidget(self.grade_text, 3, 0)
        self.comments_label = QLabel("Comments")
        self.comments_text = QLineEdit()
        self.comments_text.setPlaceholderText("Comments here")
        grid.addWidget(self.comments_label, 4, 0)
        grid.addWidget(self.comments_text, 5, 0)
        self.genre_label = QLabel("Genre")
        self.genre_list = QListWidget(self)
        self.genre_list.addItems(self.genreList)
        self.genre_list.setObjectName('genre_list')
        self.genre_list.itemClicked.connect(self.item_clicked)
        grid.addWidget(self.genre_label, 6, 0)
        grid.addWidget(self.genre_list, 7, 0)
        self.genre2_label = QLabel("Genre2")
        self.genre2_list = QListWidget(self)
        self.genre2_list.setObjectName("genre2")
        self.genre2_list.addItem("Select genre first")
        grid.addWidget(self.genre2_label, 6, 1)
        grid.addWidget(self.genre2_list, 7, 1)
        self.submit = QtGui.QPushButton("Submit Data", self)
        self.submit.clicked.connect(self.buttonClicked)
        grid.addWidget(self.submit, 8, 1)
        self.quit = QtGui.QPushButton("Exit", self)
        self.quit.clicked.connect(self.buttonClicked)
        self.quit.setMaximumWidth(80)
        grid.addWidget(self.quit, 8, 0)

    # Creates all the object thats in the getData tab
    def makeGetDataTab(self, vbox_inner):
        self.authorData = QLineEdit()
        self.authorData.setPlaceholderText("Author")
        self.authorData.setReadOnly(True)
        vbox_inner.addWidget(self.authorData)
        self.titleData = QLineEdit()
        self.titleData.setPlaceholderText("Title")
        self.titleData.setReadOnly(True)
        vbox_inner.addWidget(self.titleData)
        self.genreData = QLineEdit()
        self.genreData.setPlaceholderText("Genre")
        self.genreData.setReadOnly(True)
        vbox_inner.addWidget(self.genreData)
        self.genre2Data = QLineEdit()
        self.genre2Data.setPlaceholderText("Genre2")
        self.genre2Data.setReadOnly(True)
        vbox_inner.addWidget(self.genre2Data)
        self.dateData = QLineEdit()
        self.dateData.setPlaceholderText("Date read")
        self.dateData.setReadOnly(True)
        vbox_inner.addWidget(self.dateData)
        self.gradeData = QLineEdit()
        self.gradeData.setPlaceholderText("Grade")
        self.gradeData.setReadOnly(True)
        vbox_inner.addWidget(self.gradeData)
        self.commentsData = QLineEdit()
        self.commentsData.setPlaceholderText("Comments")
        self.commentsData.setReadOnly(True)
        vbox_inner.addWidget(self.commentsData)
        self.titles_list = QListWidget(self)
        vbox_inner.addWidget(self.titles_list)
        hbox_inner = QtGui.QHBoxLayout()
        self.getTitleData = QtGui.QPushButton("Get title data", self)
        self.getTitleData.clicked.connect(self.buttonClicked)
        hbox_inner.addWidget(self.getTitleData)
        self.refreshList = QtGui.QPushButton("Refresh list", self)
        self.refreshList.clicked.connect(self.buttonClicked)
        hbox_inner.addWidget(self.refreshList)
        return hbox_inner
    
    # Initiate the widgets gui
    def initUI(self):
        
        vbox_inner = QVBoxLayout()
        grid = QtGui.QGridLayout()
        
        self.genreList = ['Fiction', 'Fact book', 'Poetry']
        
        # Tab 1: Add Data        
        self.makeAddDataTab(grid)
        
        # Tab 2:Get Data from file
        hbox_inner = self.makeGetDataTab(vbox_inner)
    
        tab1 = QWidget()
        tab1.setLayout(grid)
        
        vbox_inner.addLayout(hbox_inner)
        tab2 = QWidget()
        tab2.setLayout(vbox_inner)
    
        self.addTab(tab1, "Add Book Data")
        self.addTab(tab2, "Get Book Data")
        self.move(150, 150)
        self.show()
        
    # Function for when a QListWidgetItem is clicked if the genre_list is 
    # clicked, will check which genre was chosen and populate genre2_list
    # with subgenres of that genre.    
    def item_clicked(self):
        genre = self.sender()
        if genre.objectName() == "genre_list":
            curr = genre.currentItem().text()
            if curr == self.genreList[0]:
                genre2List = ["Detective", "autobiography", "Horror", "Comedy"]
            elif curr == self.genreList[1]:
                genre2List = ["Technology", "Biology", "Chemistry", "Mathematics"]
            elif curr == self.genreList[2]:
                genre2List = ["Tirade", "Ballads", "Rhyme"]
            else:
                genre2List = ["None"]
            
            self.genre2_list.clear()
            self.genre2_list.addItems(genre2List)
       
    # Function for when a button is clicked, if 'Submit Data' is clicked,
    # will check that all input is correct format and if so write 
    # the data to the file. If the button pressed is 'Get title data'
    # will get the selected title in the QListWidget and show the row data
    def buttonClicked(self):
        sender = self.sender()
        if sender.text() == "Refresh list":
            if self.parent().dialog.isHidden():
                titles = getAllTitles(self.parent())
                self.titles_list.clear()
                if titles != "":
                    self.titles_list.addItems(titles)
            else:
                QMessageBox.warning(self.parent(), "Failure", "Connect to the server before refreshing.")
                
        if sender.text() == "Exit":
            if self.parent().dialog.isHidden():
                self.parent().disconnect()
            sys.exit(0)
           
        elif sender.text() == "Get title data":
            if self.titles_list.currentItem() != None:
                if self.parent().dialog.isHidden():
                    titleToGet = str(self.titles_list.currentItem().text())
                    
                    if titleToGet != "": 
                        titleData = getTitleData(self.parent(), titleToGet)
                        splitLine = []
                        splitLine = titleData.split(",", 7)
                    
                        if titleData != "Empty":
                            self.authorData.setText(splitLine[0].replace('"', "").lstrip())
                            self.titleData.setText(splitLine[1].replace('"', "").lstrip())
                            self.genreData.setText(splitLine[2].replace('"', "").lstrip())
                            self.genre2Data.setText(splitLine[3].replace('"', "").lstrip())
                            self.dateData.setText(splitLine[4].replace('"', "").lstrip())
                            self.gradeData.setText(splitLine[5].replace('"', "").lstrip())
                            self.commentsData.setText(splitLine[6].replace('"', "").lstrip())
                        else:
                            QMessageBox.warning(self, "Failed", "Connect to server first")
                            self.dialog.setWindowTitle("Book Library (Disconnected)")
                    
        elif sender.text() == "Submit Data":
            
            while self.parent().dialog.isHidden():
                    
                author = str(self.author_text.text())
                if containsDigit(author) == True:
                    QMessageBox.warning(self, "Wrong input", "Error: Author cant contain digits")
                    break
                
                if len(author) == 0:
                    QMessageBox.warning(self, "Wrong input", "Author is a required field")
                    break
                
                title = str(self.title_text.text())
                try:
                    title = str(self.title_text.text())
                except:
                    QMessageBox.warning(self, "Wrong input", "Error in comments, only A-z, 1-9 allowed")
                    break
                
                if len(title) == 0:
                    QMessageBox.warning(self, "Wrong input", "Title is a required field")
                    break
                
                
                if self.genre_list.currentItem() != None:
                    genre = str(self.genre_list.currentItem().text())
                else:
                    QMessageBox.warning(self, "Wrong input", "Error: Need to pick genre")
                    break
                                    
                if self.genre2_list.currentItem() != None:
                    genre2 = str(self.genre2_list.currentItem().text())
                else:
                    QMessageBox.warning(self, "Wrong input", "Error: Need to pick genre2")
                    break
                
                d = str(self.date_text.text())  
                
                if len(d) == 0:
                    QMessageBox.warning(self, "Wrong input", "Date is a required field")
                    break
                try:
                    dateRead = datetime.datetime.strptime(d, '%y-%m-%d').date() 
                except:
                    QMessageBox.warning(self, "Wrong input", "Error: Date needs to be in format: yy-mm-dd")         
                    break
                
                
                try:
                    grade = int(str(self.grade_text.text()))
                except:
                    QMessageBox.warning(self, "Wrong input", "Error: Grade needs to be a number between 1-5")
                    break
                
                if grade > 5 or grade < 1:
                    QMessageBox.warning(self, "Wrong input", "Error: Grade needs to be a number between 1-5")
                    break
                
                try:
                    comments = str(self.comments_text.text())
                except:
                    QMessageBox.warning(self, "Wrong input", "Error: in comments, only A-z, 1-9 allowed")
                    break
                
                if len(comments) == 0:
                    comments = "No comments"
                
                self.parent().sendBookData(author, title, genre, genre2, str(dateRead), str(grade), comments)
                break