Example #1
0
    def do_config(self):
        # Save values that need to be synced between the dialog and the
        # search widget.
        self.config['open_external'] = self.open_external.isChecked()

        # Create the config dialog. It's going to put two config widgets
        # into a QTabWidget for displaying all of the settings.
        d = QDialog(self)
        button_box = QDialogButtonBox(QDialogButtonBox.Close)
        v = QVBoxLayout(d)
        button_box.accepted.connect(d.accept)
        button_box.rejected.connect(d.reject)
        d.setWindowTitle(_('Customize Get books search'))

        tab_widget = QTabWidget(d)
        v.addWidget(tab_widget)
        v.addWidget(button_box)

        chooser_config_widget = StoreChooserWidget()
        search_config_widget = StoreConfigWidget(self.config)

        tab_widget.addTab(chooser_config_widget, _('Choose s&tores'))
        tab_widget.addTab(search_config_widget, _('Configure s&earch'))

        # Restore dialog state.
        geometry = self.config.get('config_dialog_geometry', None)
        if geometry:
            QApplication.instance().safe_restore_geometry(d, geometry)
        else:
            d.resize(800, 600)
        tab_index = self.config.get('config_dialog_tab_index', 0)
        tab_index = min(tab_index, tab_widget.count() - 1)
        tab_widget.setCurrentIndex(tab_index)

        d.exec_()

        # Save dialog state.
        self.config['config_dialog_geometry'] = bytearray(d.saveGeometry())
        self.config['config_dialog_tab_index'] = tab_widget.currentIndex()

        search_config_widget.save_settings()
        self.config_changed()
        self.gui.load_store_plugins()
        self.setup_store_checks()
Example #2
0
    def do_config(self):
        # Save values that need to be synced between the dialog and the
        # search widget.
        self.config['open_external'] = self.open_external.isChecked()

        # Create the config dialog. It's going to put two config widgets
        # into a QTabWidget for displaying all of the settings.
        d = QDialog(self)
        button_box = QDialogButtonBox(QDialogButtonBox.Close)
        v = QVBoxLayout(d)
        button_box.accepted.connect(d.accept)
        button_box.rejected.connect(d.reject)
        d.setWindowTitle(_('Customize Get books search'))

        tab_widget = QTabWidget(d)
        v.addWidget(tab_widget)
        v.addWidget(button_box)

        chooser_config_widget = StoreChooserWidget()
        search_config_widget = StoreConfigWidget(self.config)

        tab_widget.addTab(chooser_config_widget, _('Choose s&tores'))
        tab_widget.addTab(search_config_widget, _('Configure s&earch'))

        # Restore dialog state.
        geometry = self.config.get('config_dialog_geometry', None)
        if geometry:
            d.restoreGeometry(geometry)
        else:
            d.resize(800, 600)
        tab_index = self.config.get('config_dialog_tab_index', 0)
        tab_index = min(tab_index, tab_widget.count() - 1)
        tab_widget.setCurrentIndex(tab_index)

        d.exec_()

        # Save dialog state.
        self.config['config_dialog_geometry'] = bytearray(d.saveGeometry())
        self.config['config_dialog_tab_index'] = tab_widget.currentIndex()

        search_config_widget.save_settings()
        self.config_changed()
        self.gui.load_store_plugins()
        self.setup_store_checks()
Example #3
0
class Editor(QWidget):  # {{{

    toolbar_prefs_name = None
    data_changed = pyqtSignal()

    def __init__(self,
                 parent=None,
                 one_line_toolbar=False,
                 toolbar_prefs_name=None):
        QWidget.__init__(self, parent)
        self.toolbar_prefs_name = toolbar_prefs_name or self.toolbar_prefs_name
        self.toolbar1 = QToolBar(self)
        self.toolbar2 = QToolBar(self)
        self.toolbar3 = QToolBar(self)
        for i in range(1, 4):
            t = getattr(self, 'toolbar%d' % i)
            t.setIconSize(QSize(18, 18))
        self.editor = EditorWidget(self)
        self.editor.data_changed.connect(self.data_changed)
        self.set_base_url = self.editor.set_base_url
        self.set_html = self.editor.set_html
        self.tabs = QTabWidget(self)
        self.tabs.setTabPosition(self.tabs.South)
        self.wyswyg = QWidget(self.tabs)
        self.code_edit = QPlainTextEdit(self.tabs)
        self.source_dirty = False
        self.wyswyg_dirty = True

        self._layout = QVBoxLayout(self)
        self.wyswyg.layout = l = QVBoxLayout(self.wyswyg)
        self.setLayout(self._layout)
        l.setContentsMargins(0, 0, 0, 0)
        if one_line_toolbar:
            tb = QHBoxLayout()
            l.addLayout(tb)
        else:
            tb = l
        tb.addWidget(self.toolbar1)
        tb.addWidget(self.toolbar2)
        tb.addWidget(self.toolbar3)
        l.addWidget(self.editor)
        self._layout.addWidget(self.tabs)
        self.tabs.addTab(self.wyswyg, _('N&ormal view'))
        self.tabs.addTab(self.code_edit, _('&HTML source'))
        self.tabs.currentChanged[int].connect(self.change_tab)
        self.highlighter = Highlighter(self.code_edit.document())
        self.layout().setContentsMargins(0, 0, 0, 0)
        if self.toolbar_prefs_name is not None:
            hidden = gprefs.get(self.toolbar_prefs_name)
            if hidden:
                self.hide_toolbars()

        # toolbar1 {{{
        self.toolbar1.addAction(self.editor.action_undo)
        self.toolbar1.addAction(self.editor.action_redo)
        self.toolbar1.addAction(self.editor.action_select_all)
        self.toolbar1.addAction(self.editor.action_remove_format)
        self.toolbar1.addAction(self.editor.action_clear)
        self.toolbar1.addSeparator()

        for x in ('copy', 'cut', 'paste'):
            ac = getattr(self.editor, 'action_' + x)
            self.toolbar1.addAction(ac)

        self.toolbar1.addSeparator()
        self.toolbar1.addAction(self.editor.action_background)
        # }}}

        # toolbar2 {{{
        for x in ('', 'un'):
            ac = getattr(self.editor, 'action_%sordered_list' % x)
            self.toolbar2.addAction(ac)
        self.toolbar2.addSeparator()
        for x in ('superscript', 'subscript', 'indent', 'outdent'):
            self.toolbar2.addAction(getattr(self.editor, 'action_' + x))
            if x in ('subscript', 'outdent'):
                self.toolbar2.addSeparator()

        self.toolbar2.addAction(self.editor.action_block_style)
        w = self.toolbar2.widgetForAction(self.editor.action_block_style)
        if hasattr(w, 'setPopupMode'):
            w.setPopupMode(w.InstantPopup)
        self.toolbar2.addAction(self.editor.action_insert_link)
        self.toolbar2.addAction(self.editor.action_insert_hr)
        # }}}

        # toolbar3 {{{
        for x in ('bold', 'italic', 'underline', 'strikethrough'):
            ac = getattr(self.editor, 'action_' + x)
            self.toolbar3.addAction(ac)
        self.toolbar3.addSeparator()

        for x in ('left', 'center', 'right', 'justified'):
            ac = getattr(self.editor, 'action_align_' + x)
            self.toolbar3.addAction(ac)
        self.toolbar3.addSeparator()
        self.toolbar3.addAction(self.editor.action_color)
        # }}}

        self.code_edit.textChanged.connect(self.code_dirtied)
        self.editor.page().contentsChanged.connect(self.wyswyg_dirtied)

    def set_minimum_height_for_editor(self, val):
        self.editor.setMinimumHeight(val)

    @property
    def html(self):
        self.tabs.setCurrentIndex(0)
        return self.editor.html

    @html.setter
    def html(self, v):
        self.editor.html = v

    def change_tab(self, index):
        # print 'reloading:', (index and self.wyswyg_dirty) or (not index and
        #        self.source_dirty)
        if index == 1:  # changing to code view
            if self.wyswyg_dirty:
                self.code_edit.setPlainText(self.editor.html)
                self.wyswyg_dirty = False
        elif index == 0:  # changing to wyswyg
            if self.source_dirty:
                self.editor.html = unicode_type(self.code_edit.toPlainText())
                self.source_dirty = False

    @property
    def tab(self):
        return 'code' if self.tabs.currentWidget(
        ) is self.code_edit else 'wyswyg'

    @tab.setter
    def tab(self, val):
        self.tabs.setCurrentWidget(self.code_edit if val ==
                                   'code' else self.wyswyg)

    def wyswyg_dirtied(self, *args):
        self.wyswyg_dirty = True

    def code_dirtied(self, *args):
        self.source_dirty = True

    def hide_toolbars(self):
        self.toolbar1.setVisible(False)
        self.toolbar2.setVisible(False)
        self.toolbar3.setVisible(False)

    def show_toolbars(self):
        self.toolbar1.setVisible(True)
        self.toolbar2.setVisible(True)
        self.toolbar3.setVisible(True)

    def toggle_toolbars(self):
        visible = self.toolbars_visible
        getattr(self, ('hide' if visible else 'show') + '_toolbars')()
        if self.toolbar_prefs_name is not None:
            gprefs.set(self.toolbar_prefs_name, visible)

    @property
    def toolbars_visible(self):
        return self.toolbar1.isVisible() or self.toolbar2.isVisible(
        ) or self.toolbar3.isVisible()

    @toolbars_visible.setter
    def toolbars_visible(self, val):
        getattr(self, ('show' if val else 'hide') + '_toolbars')()

    def set_readonly(self, what):
        self.editor.set_readonly(what)

    def hide_tabs(self):
        self.tabs.tabBar().setVisible(False)
Example #4
0
class Editor(QWidget):  # {{{

    def __init__(self, parent=None, one_line_toolbar=False):
        QWidget.__init__(self, parent)
        self.toolbar1 = QToolBar(self)
        self.toolbar2 = QToolBar(self)
        self.toolbar3 = QToolBar(self)
        for i in range(1, 4):
            t = getattr(self, 'toolbar%d'%i)
            t.setIconSize(QSize(18, 18))
        self.editor = EditorWidget(self)
        self.set_html = self.editor.set_html
        self.tabs = QTabWidget(self)
        self.tabs.setTabPosition(self.tabs.South)
        self.wyswyg = QWidget(self.tabs)
        self.code_edit = QPlainTextEdit(self.tabs)
        self.source_dirty = False
        self.wyswyg_dirty = True

        self._layout = QVBoxLayout(self)
        self.wyswyg.layout = l = QVBoxLayout(self.wyswyg)
        self.setLayout(self._layout)
        l.setContentsMargins(0, 0, 0, 0)
        if one_line_toolbar:
            tb = QHBoxLayout()
            l.addLayout(tb)
        else:
            tb = l
        tb.addWidget(self.toolbar1)
        tb.addWidget(self.toolbar2)
        tb.addWidget(self.toolbar3)
        l.addWidget(self.editor)
        self._layout.addWidget(self.tabs)
        self.tabs.addTab(self.wyswyg, _('N&ormal view'))
        self.tabs.addTab(self.code_edit, _('&HTML Source'))
        self.tabs.currentChanged[int].connect(self.change_tab)
        self.highlighter = Highlighter(self.code_edit.document())
        self.layout().setContentsMargins(0, 0, 0, 0)

        # toolbar1 {{{
        self.toolbar1.addAction(self.editor.action_undo)
        self.toolbar1.addAction(self.editor.action_redo)
        self.toolbar1.addAction(self.editor.action_select_all)
        self.toolbar1.addAction(self.editor.action_remove_format)
        self.toolbar1.addAction(self.editor.action_clear)
        self.toolbar1.addSeparator()

        for x in ('copy', 'cut', 'paste'):
            ac = getattr(self.editor, 'action_'+x)
            self.toolbar1.addAction(ac)

        self.toolbar1.addSeparator()
        self.toolbar1.addAction(self.editor.action_background)
        # }}}

        # toolbar2 {{{
        for x in ('', 'un'):
            ac = getattr(self.editor, 'action_%sordered_list'%x)
            self.toolbar2.addAction(ac)
        self.toolbar2.addSeparator()
        for x in ('superscript', 'subscript', 'indent', 'outdent'):
            self.toolbar2.addAction(getattr(self.editor, 'action_' + x))
            if x in ('subscript', 'outdent'):
                self.toolbar2.addSeparator()

        self.toolbar2.addAction(self.editor.action_block_style)
        w = self.toolbar2.widgetForAction(self.editor.action_block_style)
        w.setPopupMode(w.InstantPopup)
        self.toolbar2.addAction(self.editor.action_insert_link)
        # }}}

        # toolbar3 {{{
        for x in ('bold', 'italic', 'underline', 'strikethrough'):
            ac = getattr(self.editor, 'action_'+x)
            self.toolbar3.addAction(ac)
        self.toolbar3.addSeparator()

        for x in ('left', 'center', 'right', 'justified'):
            ac = getattr(self.editor, 'action_align_'+x)
            self.toolbar3.addAction(ac)
        self.toolbar3.addSeparator()
        self.toolbar3.addAction(self.editor.action_color)
        # }}}

        self.code_edit.textChanged.connect(self.code_dirtied)
        self.editor.page().contentsChanged.connect(self.wyswyg_dirtied)

    def set_minimum_height_for_editor(self, val):
        self.editor.setMinimumHeight(val)

    @dynamic_property
    def html(self):
        def fset(self, v):
            self.editor.html = v
        def fget(self):
            self.tabs.setCurrentIndex(0)
            return self.editor.html
        return property(fget=fget, fset=fset)

    def change_tab(self, index):
        # print 'reloading:', (index and self.wyswyg_dirty) or (not index and
        #        self.source_dirty)
        if index == 1:  # changing to code view
            if self.wyswyg_dirty:
                self.code_edit.setPlainText(self.editor.html)
                self.wyswyg_dirty = False
        elif index == 0:  # changing to wyswyg
            if self.source_dirty:
                self.editor.html = unicode(self.code_edit.toPlainText())
                self.source_dirty = False

    @dynamic_property
    def tab(self):
        def fget(self):
            return 'code' if self.tabs.currentWidget() is self.code_edit else 'wyswyg'
        def fset(self, val):
            self.tabs.setCurrentWidget(self.code_edit if val == 'code' else self.wyswyg)
        return property(fget=fget, fset=fset)

    def wyswyg_dirtied(self, *args):
        self.wyswyg_dirty = True

    def code_dirtied(self, *args):
        self.source_dirty = True

    def hide_toolbars(self):
        self.toolbar1.setVisible(False)
        self.toolbar2.setVisible(False)
        self.toolbar3.setVisible(False)

    def show_toolbars(self):
        self.toolbar1.setVisible(True)
        self.toolbar2.setVisible(True)
        self.toolbar3.setVisible(True)

    @dynamic_property
    def toolbars_visible(self):
        def fget(self):
            return self.toolbar1.isVisible() or self.toolbar2.isVisible() or self.toolbar3.isVisible()
        def fset(self, val):
            getattr(self, ('show' if val else 'hide') + '_toolbars')()
        return property(fget=fget, fset=fset)

    def set_readonly(self, what):
        self.editor.set_readonly(what)

    def hide_tabs(self):
        self.tabs.tabBar().setVisible(False)
Example #5
0
class SchedulerDialog(QDialog):

    SCHEDULE_TYPES = OrderedDict([
            ('days_of_week', DaysOfWeek),
            ('days_of_month', DaysOfMonth),
            ('every_x_days', EveryXDays),
    ])

    download = pyqtSignal(object)

    def __init__(self, recipe_model, parent=None):
        QDialog.__init__(self, parent)
        self.commit_on_change = True
        self.previous_urn = None

        self.setWindowIcon(QIcon(I('scheduler.png')))
        self.setWindowTitle(_("Schedule news download"))
        self.l = l = QGridLayout(self)

        # Left panel
        self.h = h = QHBoxLayout()
        l.addLayout(h, 0, 0, 1, 1)
        self.search = s = SearchBox2(self)
        self.search.initialize('scheduler_search_history')
        self.search.setMinimumContentsLength(15)
        self.go_button = b = QToolButton(self)
        b.setText(_("Go"))
        b.clicked.connect(self.search.do_search)
        h.addWidget(s), h.addWidget(b)
        self.recipes = RecipesView(self)
        l.addWidget(self.recipes, 1, 0, 1, 1)
        self.recipe_model = recipe_model
        self.recipe_model.do_refresh()
        self.recipes.setModel(self.recipe_model)
        self.recipes.setFocus(Qt.OtherFocusReason)
        self.count_label = la = QLabel(_('%s news sources') % self.recipe_model.showing_count)
        la.setAlignment(Qt.AlignCenter)
        l.addWidget(la, 2, 0, 1, 1)
        self.search.search.connect(self.recipe_model.search)
        self.recipe_model.searched.connect(self.search.search_done, type=Qt.QueuedConnection)
        self.recipe_model.searched.connect(self.search_done)

        # Right Panel
        self.scroll_area_contents = sac = QWidget(self)
        self.l.addWidget(sac, 0, 1, 2, 1)
        sac.v = v = QVBoxLayout(sac)
        v.setContentsMargins(0, 0, 0, 0)
        self.detail_box = QTabWidget(self)
        self.detail_box.setVisible(False)
        self.detail_box.setCurrentIndex(0)
        v.addWidget(self.detail_box)
        v.addItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))

        # First Tab (scheduling)
        self.tab = QWidget()
        self.detail_box.addTab(self.tab, _("&Schedule"))
        self.tab.v = vt = QVBoxLayout(self.tab)
        vt.setContentsMargins(0, 0, 0, 0)
        self.blurb = la = QLabel('blurb')
        la.setWordWrap(True), la.setOpenExternalLinks(True)
        vt.addWidget(la)
        self.frame = f = QFrame(self.tab)
        vt.addWidget(f)
        f.setFrameShape(f.StyledPanel)
        f.setFrameShadow(f.Raised)
        f.v = vf = QVBoxLayout(f)
        self.schedule = s = QCheckBox(_("&Schedule for download:"), f)
        self.schedule.stateChanged[int].connect(self.toggle_schedule_info)
        vf.addWidget(s)
        f.h = h = QHBoxLayout()
        vf.addLayout(h)
        self.days_of_week = QRadioButton(_("&Days of  week"), f)
        self.days_of_month = QRadioButton(_("Da&ys of month"), f)
        self.every_x_days = QRadioButton(_("Every &x days"), f)
        self.days_of_week.setChecked(True)
        h.addWidget(self.days_of_week), h.addWidget(self.days_of_month), h.addWidget(self.every_x_days)
        self.schedule_stack = ss = QStackedWidget(f)
        self.schedule_widgets = []
        for key in reversed(self.SCHEDULE_TYPES):
            self.schedule_widgets.insert(0, self.SCHEDULE_TYPES[key](self))
            self.schedule_stack.insertWidget(0, self.schedule_widgets[0])
        vf.addWidget(ss)
        self.last_downloaded = la = QLabel(f)
        la.setWordWrap(True)
        vf.addWidget(la)
        self.account = acc = QGroupBox(self.tab)
        acc.setTitle(_("&Account"))
        vt.addWidget(acc)
        acc.g = g = QGridLayout(acc)
        acc.unla = la = QLabel(_("&Username:"******"&Password:"******"&Show password"), self.account)
        spw.stateChanged[int].connect(self.set_pw_echo_mode)
        g.addWidget(spw, 2, 0, 1, 2)
        self.rla = la = QLabel(_("For the scheduling to work, you must leave calibre running."))
        vt.addWidget(la)
        for b, c in iteritems(self.SCHEDULE_TYPES):
            b = getattr(self, b)
            b.toggled.connect(self.schedule_type_selected)
            b.setToolTip(textwrap.dedent(c.HELP))

        # Second tab (advanced settings)
        self.tab2 = t2 = QWidget()
        self.detail_box.addTab(self.tab2, _("&Advanced"))
        self.tab2.g = g = QGridLayout(t2)
        g.setContentsMargins(0, 0, 0, 0)
        self.add_title_tag = tt = QCheckBox(_("Add &title as tag"), t2)
        g.addWidget(tt, 0, 0, 1, 2)
        t2.la = la = QLabel(_("&Extra tags:"))
        self.custom_tags = ct = QLineEdit(self)
        la.setBuddy(ct)
        g.addWidget(la), g.addWidget(ct, 1, 1)
        t2.la2 = la = QLabel(_("&Keep at most:"))
        la.setToolTip(_("Maximum number of copies (issues) of this recipe to keep.  Set to 0 to keep all (disable)."))
        self.keep_issues = ki = QSpinBox(t2)
        tt.toggled['bool'].connect(self.keep_issues.setEnabled)
        ki.setMaximum(100000), la.setBuddy(ki)
        ki.setToolTip(_(
            "<p>When set, this option will cause calibre to keep, at most, the specified number of issues"
            " of this periodical. Every time a new issue is downloaded, the oldest one is deleted, if the"
            " total is larger than this number.\n<p>Note that this feature only works if you have the"
            " option to add the title as tag checked, above.\n<p>Also, the setting for deleting periodicals"
            " older than a number of days, below, takes priority over this setting."))
        ki.setSpecialValueText(_("all issues")), ki.setSuffix(_(" issues"))
        g.addWidget(la), g.addWidget(ki, 2, 1)
        si = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        g.addItem(si, 3, 1, 1, 1)

        # Bottom area
        self.hb = h = QHBoxLayout()
        self.l.addLayout(h, 2, 1, 1, 1)
        self.labt = la = QLabel(_("Delete downloaded &news older than:"))
        self.old_news = on = QSpinBox(self)
        on.setToolTip(_(
            "<p>Delete downloaded news older than the specified number of days. Set to zero to disable.\n"
            "<p>You can also control the maximum number of issues of a specific periodical that are kept"
            " by clicking the Advanced tab for that periodical above."))
        on.setSpecialValueText(_("never delete")), on.setSuffix(_(" days"))
        on.setMaximum(1000), la.setBuddy(on)
        on.setValue(gconf['oldest_news'])
        h.addWidget(la), h.addWidget(on)
        self.download_all_button = b = QPushButton(QIcon(I('news.png')), _("Download &all scheduled"), self)
        b.setToolTip(_("Download all scheduled news sources at once"))
        b.clicked.connect(self.download_all_clicked)
        self.l.addWidget(b, 3, 0, 1, 1)
        self.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self)
        bb.accepted.connect(self.accept), bb.rejected.connect(self.reject)
        self.download_button = b = bb.addButton(_('&Download now'), bb.ActionRole)
        b.setIcon(QIcon(I('arrow-down.png'))), b.setVisible(False)
        b.clicked.connect(self.download_clicked)
        self.l.addWidget(bb, 3, 1, 1, 1)

        geom = gprefs.get('scheduler_dialog_geometry')
        if geom is not None:
            QApplication.instance().safe_restore_geometry(self, geom)

    def sizeHint(self):
        return QSize(800, 600)

    def set_pw_echo_mode(self, state):
        self.password.setEchoMode(self.password.Normal
                if state == Qt.Checked else self.password.Password)

    def schedule_type_selected(self, *args):
        for i, st in enumerate(self.SCHEDULE_TYPES):
            if getattr(self, st).isChecked():
                self.schedule_stack.setCurrentIndex(i)
                break

    def keyPressEvent(self, ev):
        if ev.key() not in (Qt.Key_Enter, Qt.Key_Return):
            return QDialog.keyPressEvent(self, ev)

    def break_cycles(self):
        try:
            self.recipe_model.searched.disconnect(self.search_done)
            self.recipe_model.searched.disconnect(self.search.search_done)
            self.search.search.disconnect()
            self.download.disconnect()
        except:
            pass
        self.recipe_model = None

    def search_done(self, *args):
        if self.recipe_model.showing_count < 10:
            self.recipes.expandAll()

    def toggle_schedule_info(self, *args):
        enabled = self.schedule.isChecked()
        for x in self.SCHEDULE_TYPES:
            getattr(self, x).setEnabled(enabled)
        self.schedule_stack.setEnabled(enabled)
        self.last_downloaded.setVisible(enabled)

    def current_changed(self, current, previous):
        if self.previous_urn is not None:
            self.commit(urn=self.previous_urn)
            self.previous_urn = None

        urn = self.current_urn
        if urn is not None:
            self.initialize_detail_box(urn)
        self.recipes.scrollTo(current)

    def accept(self):
        if not self.commit():
            return False
        self.save_geometry()
        return QDialog.accept(self)

    def reject(self):
        self.save_geometry()
        return QDialog.reject(self)

    def save_geometry(self):
        gprefs.set('scheduler_dialog_geometry', bytearray(self.saveGeometry()))

    def download_clicked(self, *args):
        self.commit()
        if self.commit() and self.current_urn:
            self.download.emit(self.current_urn)

    def download_all_clicked(self, *args):
        if self.commit() and self.commit():
            self.download.emit(None)

    @property
    def current_urn(self):
        current = self.recipes.currentIndex()
        if current.isValid():
            return getattr(current.internalPointer(), 'urn', None)

    def commit(self, urn=None):
        urn = self.current_urn if urn is None else urn
        if not self.detail_box.isVisible() or urn is None:
            return True

        if self.account.isVisible():
            un, pw = map(unicode_type, (self.username.text(), self.password.text()))
            un, pw = un.strip(), pw.strip()
            if not un and not pw and self.schedule.isChecked():
                if not getattr(self, 'subscription_optional', False):
                    error_dialog(self, _('Need username and password'),
                            _('You must provide a username and/or password to '
                                'use this news source.'), show=True)
                    return False
            if un or pw:
                self.recipe_model.set_account_info(urn, un, pw)
            else:
                self.recipe_model.clear_account_info(urn)

        if self.schedule.isChecked():
            schedule_type, schedule = \
                    self.schedule_stack.currentWidget().schedule
            self.recipe_model.schedule_recipe(urn, schedule_type, schedule)
        else:
            self.recipe_model.un_schedule_recipe(urn)

        add_title_tag = self.add_title_tag.isChecked()
        keep_issues = '0'
        if self.keep_issues.isEnabled():
            keep_issues = unicode_type(self.keep_issues.value())
        custom_tags = unicode_type(self.custom_tags.text()).strip()
        custom_tags = [x.strip() for x in custom_tags.split(',')]
        self.recipe_model.customize_recipe(urn, add_title_tag, custom_tags, keep_issues)
        return True

    def initialize_detail_box(self, urn):
        self.previous_urn = urn
        self.detail_box.setVisible(True)
        self.download_button.setVisible(True)
        self.detail_box.setCurrentIndex(0)
        recipe = self.recipe_model.recipe_from_urn(urn)
        try:
            schedule_info = self.recipe_model.schedule_info_from_urn(urn)
        except:
            # Happens if user does something stupid like unchecking all the
            # days of the week
            schedule_info = None
        account_info = self.recipe_model.account_info_from_urn(urn)
        customize_info = self.recipe_model.get_customize_info(urn)

        ns = recipe.get('needs_subscription', '')
        self.account.setVisible(ns in ('yes', 'optional'))
        self.subscription_optional = ns == 'optional'
        act = _('Account')
        act2 = _('(optional)') if self.subscription_optional else \
                _('(required)')
        self.account.setTitle(act+' '+act2)
        un = pw = ''
        if account_info is not None:
            un, pw = account_info[:2]
            if not un:
                un = ''
            if not pw:
                pw = ''
        self.username.setText(un)
        self.password.setText(pw)
        self.show_password.setChecked(False)

        self.blurb.setText('''
        <p>
        <b>%(title)s</b><br>
        %(cb)s %(author)s<br/>
        %(description)s
        </p>
        '''%dict(title=recipe.get('title'), cb=_('Created by: '),
            author=recipe.get('author', _('Unknown')),
            description=recipe.get('description', '')))
        self.download_button.setToolTip(
                _('Download %s now')%recipe.get('title'))
        scheduled = schedule_info is not None
        self.schedule.setChecked(scheduled)
        self.toggle_schedule_info()
        self.last_downloaded.setText(_('Last downloaded: never'))
        ld_text = _('never')
        if scheduled:
            typ, sch, last_downloaded = schedule_info
            d = utcnow() - last_downloaded

            def hm(x):
                return (x-x%3600)//3600, (x%3600 - (x%3600)%60)//60
            hours, minutes = hm(d.seconds)
            tm = _('%(days)d days, %(hours)d hours'
                    ' and %(mins)d minutes ago')%dict(
                            days=d.days, hours=hours, mins=minutes)
            if d < timedelta(days=366):
                ld_text = tm
        else:
            typ, sch = 'day/time', (-1, 6, 0)
        sch_widget = {'day/time': 0, 'days_of_week': 0, 'days_of_month':1,
                'interval':2}[typ]
        rb = getattr(self, list(self.SCHEDULE_TYPES)[sch_widget])
        rb.setChecked(True)
        self.schedule_stack.setCurrentIndex(sch_widget)
        self.schedule_stack.currentWidget().initialize(typ, sch)
        add_title_tag, custom_tags, keep_issues = customize_info
        self.add_title_tag.setChecked(add_title_tag)
        self.custom_tags.setText(', '.join(custom_tags))
        self.last_downloaded.setText(_('Last downloaded:') + ' ' + ld_text)
        try:
            keep_issues = int(keep_issues)
        except:
            keep_issues = 0
        self.keep_issues.setValue(keep_issues)
        self.keep_issues.setEnabled(self.add_title_tag.isChecked())
Example #6
0
class MainWin(QMainWindow):
    """ It's a window, stores a TabWidget """

    def __init__(self, parent=None):
        super(MainWin, self).__init__(parent)
        self.setWindowTitle("Eilat Browser")
        # gc.set_debug(gc.DEBUG_LEAK)

        self.last_closed = None

        self.tab_widget = QTabWidget(self)
        self.tab_widget.setTabBar(MidClickTabBar(self))
        self.tab_widget.tabBar().setMovable(True)
        self.tab_widget.setTabsClosable(True)

        # the right side of the tab already has the space for
        # a non-shown close button
        self.tab_widget.setStyleSheet(
            'QTabBar::tab {padding-top: 0px; padding-bottom: 0px; '
            'padding-left: 0.3em;} '
            'QTabBar::tab:selected {color: #00f;}')

        # tabCloseRequested carries int (index of a tab)
        self.tab_widget.tabCloseRequested.connect(self.del_tab)

        self.setCentralWidget(self.tab_widget)

        self.tooltip = NotifyLabel(parent=self)

        def restore_last_closed():
            """ One-use callback for QShortcut.
            Opens a fresh new tab with the url address of the last tab closed
            """
            if self.last_closed is not None:
                url = self.last_closed
                self.add_tab(url)
                self.last_closed = None

        def dump_gc():
            """ prints sizes for large memory collectable objects """
            objs = gc.get_objects()
            pairs = [(str(k)[:80], type(k).__name__, sys.getsizeof(k))
                     for k in objs if sys.getsizeof(k) > 1024*4*5]

            for pair in pairs:
                print(pair)

        def reload_disk_init():
            """ transfer options.yaml and the css directory to global maps """
            load_options()
            load_css()
            notify("reloaded disk config")

        set_shortcuts([
            ("F9", self, dump_gc),
            # reload configuration
            ("Ctrl+Shift+R", self, reload_disk_init),
            # new tabs
            ("Ctrl+T", self, self.add_tab),
            ("Ctrl+Shift+T", self, partial(self.add_tab, scripting=True)),
            ("Y", self, self.new_tab_from_clipboard),
            # movement
            ("M", self, self.inc_tab),
            ("N", self, partial(self.inc_tab, -1)),
            ("Ctrl+PgUp", self, partial(self.inc_tab, -1)),
            ("Ctrl+PgDown", self, self.inc_tab),
            # destroy/undestroy
            ("U", self, restore_last_closed),
            ("Ctrl+W", self, self.del_tab),
            ("Ctrl+Q", self, self.finalize)
            ])

    def new_tab_from_clipboard(self):
        """ One-use callback for QShortcut.
        Reads the content of the PRIMARY clipboard and navigates to it
        on a new tab.

        """

        url = clipboard()

        if url is not None:
            self.add_tab(url)

    # aux. action (en register_actions)
    def inc_tab(self, incby=1):
        """ Takes the current tab index, modifies wrapping around,
        and sets as current.

        Afterwards the active tab has focus on its webkit area.

        """
        if self.tab_widget.count() < 2:
            return
        idx = self.tab_widget.currentIndex()
        idx += incby
        if idx < 0:
            idx = self.tab_widget.count()-1
        elif idx >= self.tab_widget.count():
            idx = 0
        self.tab_widget.setCurrentIndex(idx)
        self.tab_widget.currentWidget().webkit.setFocus()

    def finalize(self):
        """ Just doing self.close() doesn't clean up; for example, closing
        when the address bar popup is visible doesn't close the popup, and
        leaves the window hidden and unclosable (except e.g. for KILL 15)

        Makes a hard app close through os._exit to prevent garbage collection;
        cleanup has typically done more harm than good. Any state that we may
        want to preserve we should do ourselves (e.g. cookies through the NAMs)

        """

        idx = self.tab_widget.currentIndex()
        self.tab_widget.widget(idx).deleteLater()
        self.tab_widget.removeTab(idx)
        close_managers()  # also does an os._exit

    # action y connect en llamada en constructor
    def del_tab(self, idx=None):
        """ Closes a tab. If 'idx' is set, it was called by a
        tabCloseRequested signal (maybe mid click). If not,
        it was called by a keyboard action and closes the
        currently active tab.

        Afterwards the active tab has focus on its webkit area.

        It closes the window when deleting the last active tab.

        """

        if idx is None:
            idx = self.tab_widget.currentIndex()

        self.tab_widget.widget(idx).webkit.stop()

        self.last_closed = self.tab_widget.widget(idx).webkit.url()

        self.tab_widget.widget(idx).deleteLater()
        self.tab_widget.removeTab(idx)
        if len(self.tab_widget) == 0:
            close_managers()  # also does an os.__exit
        else:
            self.tab_widget.currentWidget().webkit.setFocus()

    # action (en register_actions)
    # only way to create a new tab
    # called externally in eilat.py to create the first tab
    def add_tab(self, url=None, scripting=False):
        """ Creates a new tab, either empty or navegating to the url.
        Sets itself as the active tab.

        If navegating to an url it gives focus to the webkit area. Otherwise,
        the address bar is focused.

        """
        tab = WebTab(parent=self.tab_widget)

        self.tab_widget.addTab(tab, tab.current['title'])

        self.tab_widget.setCurrentWidget(tab)
        tab_idx = self.tab_widget.indexOf(tab)

        self.tab_widget.tabBar().tabButton(tab_idx, 1).hide()  # 1: right align

        if scripting:
            tab.toggle_script()

        if url is not None:
            qurl = fix_url(url)
            tab.webkit.navigate(qurl)
        else:
            tab.address_bar.setFocus()
Example #7
0
class MainWin(QMainWindow):
    """ It's a window, stores a TabWidget """
    def __init__(self, parent=None):
        super(MainWin, self).__init__(parent)
        self.setWindowTitle("Eilat Browser")
        # gc.set_debug(gc.DEBUG_LEAK)

        self.last_closed = None

        self.tab_widget = QTabWidget(self)
        self.tab_widget.setTabBar(MidClickTabBar(self))
        self.tab_widget.tabBar().setMovable(True)
        self.tab_widget.setTabsClosable(True)

        # the right side of the tab already has the space for
        # a non-shown close button
        self.tab_widget.setStyleSheet(
            'QTabBar::tab {padding-top: 0px; padding-bottom: 0px; '
            'padding-left: 0.3em;} '
            'QTabBar::tab:selected {color: #00f;}')

        # tabCloseRequested carries int (index of a tab)
        self.tab_widget.tabCloseRequested.connect(self.del_tab)

        self.setCentralWidget(self.tab_widget)

        self.tooltip = NotifyLabel(parent=self)

        def restore_last_closed():
            """ One-use callback for QShortcut.
            Opens a fresh new tab with the url address of the last tab closed
            """
            if self.last_closed is not None:
                url = self.last_closed
                self.add_tab(url)
                self.last_closed = None

        def dump_gc():
            """ prints sizes for large memory collectable objects """
            objs = gc.get_objects()
            pairs = [(str(k)[:80], type(k).__name__, sys.getsizeof(k))
                     for k in objs if sys.getsizeof(k) > 1024 * 4 * 5]

            for pair in pairs:
                print(pair)

        def reload_disk_init():
            """ transfer options.yaml and the css directory to global maps """
            load_options()
            load_css()
            notify("reloaded disk config")

        set_shortcuts([
            ("F9", self, dump_gc),
            # reload configuration
            ("Ctrl+Shift+R", self, reload_disk_init),
            # new tabs
            ("Ctrl+T", self, self.add_tab),
            ("Ctrl+Shift+T", self, partial(self.add_tab, scripting=True)),
            ("Y", self, self.new_tab_from_clipboard),
            # movement
            ("M", self, self.inc_tab),
            ("N", self, partial(self.inc_tab, -1)),
            ("Ctrl+PgUp", self, partial(self.inc_tab, -1)),
            ("Ctrl+PgDown", self, self.inc_tab),
            # destroy/undestroy
            ("U", self, restore_last_closed),
            ("Ctrl+W", self, self.del_tab),
            ("Ctrl+Q", self, self.finalize)
        ])

    def new_tab_from_clipboard(self):
        """ One-use callback for QShortcut.
        Reads the content of the PRIMARY clipboard and navigates to it
        on a new tab.

        """

        url = clipboard()

        if url is not None:
            self.add_tab(url)

    # aux. action (en register_actions)
    def inc_tab(self, incby=1):
        """ Takes the current tab index, modifies wrapping around,
        and sets as current.

        Afterwards the active tab has focus on its webkit area.

        """
        if self.tab_widget.count() < 2:
            return
        idx = self.tab_widget.currentIndex()
        idx += incby
        if idx < 0:
            idx = self.tab_widget.count() - 1
        elif idx >= self.tab_widget.count():
            idx = 0
        self.tab_widget.setCurrentIndex(idx)
        self.tab_widget.currentWidget().webkit.setFocus()

    def finalize(self):
        """ Just doing self.close() doesn't clean up; for example, closing
        when the address bar popup is visible doesn't close the popup, and
        leaves the window hidden and unclosable (except e.g. for KILL 15)

        Makes a hard app close through os._exit to prevent garbage collection;
        cleanup has typically done more harm than good. Any state that we may
        want to preserve we should do ourselves (e.g. cookies through the NAMs)

        """

        idx = self.tab_widget.currentIndex()
        self.tab_widget.widget(idx).deleteLater()
        self.tab_widget.removeTab(idx)
        close_managers()  # also does an os._exit

    # action y connect en llamada en constructor
    def del_tab(self, idx=None):
        """ Closes a tab. If 'idx' is set, it was called by a
        tabCloseRequested signal (maybe mid click). If not,
        it was called by a keyboard action and closes the
        currently active tab.

        Afterwards the active tab has focus on its webkit area.

        It closes the window when deleting the last active tab.

        """

        if idx is None:
            idx = self.tab_widget.currentIndex()

        self.tab_widget.widget(idx).webkit.stop()

        self.last_closed = self.tab_widget.widget(idx).webkit.url()

        self.tab_widget.widget(idx).deleteLater()
        self.tab_widget.removeTab(idx)
        if len(self.tab_widget) == 0:
            close_managers()  # also does an os.__exit
        else:
            self.tab_widget.currentWidget().webkit.setFocus()

    # action (en register_actions)
    # only way to create a new tab
    # called externally in eilat.py to create the first tab
    def add_tab(self, url=None, scripting=False):
        """ Creates a new tab, either empty or navegating to the url.
        Sets itself as the active tab.

        If navegating to an url it gives focus to the webkit area. Otherwise,
        the address bar is focused.

        """
        tab = WebTab(parent=self.tab_widget)

        self.tab_widget.addTab(tab, tab.current['title'])

        self.tab_widget.setCurrentWidget(tab)
        tab_idx = self.tab_widget.indexOf(tab)

        self.tab_widget.tabBar().tabButton(tab_idx, 1).hide()  # 1: right align

        if scripting:
            tab.toggle_script()

        if url is not None:
            qurl = fix_url(url)
            tab.webkit.navigate(qurl)
        else:
            tab.address_bar.setFocus()
Example #8
0
class SchedulerDialog(QDialog):

    SCHEDULE_TYPES = OrderedDict([
            ('days_of_week', DaysOfWeek),
            ('days_of_month', DaysOfMonth),
            ('every_x_days', EveryXDays),
    ])

    download = pyqtSignal(object)

    def __init__(self, recipe_model, parent=None):
        QDialog.__init__(self, parent)
        self.commit_on_change = True
        self.previous_urn = None

        self.setWindowIcon(QIcon(I('scheduler.png')))
        self.setWindowTitle(_("Schedule news download"))
        self.l = l = QGridLayout(self)

        # Left panel
        self.h = h = QHBoxLayout()
        l.addLayout(h, 0, 0, 1, 1)
        self.search = s = SearchBox2(self)
        self.search.initialize('scheduler_search_history')
        self.search.setMinimumContentsLength(15)
        self.go_button = b = QToolButton(self)
        b.setText(_("Go"))
        b.clicked.connect(self.search.do_search)
        self.clear_search_button = cb = QToolButton(self)
        self.clear_search_button.clicked.connect(self.search.clear_clicked)
        cb.setIcon(QIcon(I('clear_left.png')))
        h.addWidget(s), h.addWidget(b), h.addWidget(cb)
        self.recipes = RecipesView(self)
        l.addWidget(self.recipes, 1, 0, 1, 1)
        self.recipe_model = recipe_model
        self.recipe_model.do_refresh()
        self.recipes.setModel(self.recipe_model)
        self.recipes.setFocus(Qt.OtherFocusReason)
        self.count_label = la = QLabel(_('%s news sources') % self.recipe_model.showing_count)
        la.setAlignment(Qt.AlignCenter)
        l.addWidget(la, 2, 0, 1, 1)
        self.search.search.connect(self.recipe_model.search)
        self.recipe_model.searched.connect(self.search.search_done, type=Qt.QueuedConnection)
        self.recipe_model.searched.connect(self.search_done)

        # Right Panel
        self.scroll_area = sa = QScrollArea(self)
        self.l.addWidget(sa, 0, 1, 2, 1)
        sa.setFrameShape(QFrame.NoFrame)
        sa.setWidgetResizable(True)
        self.scroll_area_contents = sac = QWidget(self)
        sa.setWidget(sac)
        sac.v = v = QVBoxLayout(sac)
        v.setContentsMargins(0, 0, 0, 0)
        self.detail_box = QTabWidget(self)
        self.detail_box.setVisible(False)
        self.detail_box.setCurrentIndex(0)
        v.addWidget(self.detail_box)
        v.addItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))

        # First Tab (scheduling)
        self.tab = QWidget()
        self.detail_box.addTab(self.tab, _("&Schedule"))
        self.tab.v = vt = QVBoxLayout(self.tab)
        vt.setContentsMargins(0, 0, 0, 0)
        self.blurb = la = QLabel('blurb')
        la.setWordWrap(True), la.setOpenExternalLinks(True)
        vt.addWidget(la)
        vt.addItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))
        self.frame = f = QFrame(self.tab)
        vt.addWidget(f)
        f.setFrameShape(f.StyledPanel)
        f.setFrameShadow(f.Raised)
        f.v = vf = QVBoxLayout(f)
        self.schedule = s = QCheckBox(_("&Schedule for download:"), f)
        self.schedule.stateChanged[int].connect(self.toggle_schedule_info)
        vf.addWidget(s)
        f.h = h = QHBoxLayout()
        vf.addLayout(h)
        self.days_of_week = QRadioButton(_("&Days of  week"), f)
        self.days_of_month = QRadioButton(_("Da&ys of month"), f)
        self.every_x_days = QRadioButton(_("Every &x days"), f)
        self.days_of_week.setChecked(True)
        h.addWidget(self.days_of_week), h.addWidget(self.days_of_month), h.addWidget(self.every_x_days)
        self.schedule_stack = ss = QStackedWidget(f)
        self.schedule_widgets = []
        for key in reversed(self.SCHEDULE_TYPES):
            self.schedule_widgets.insert(0, self.SCHEDULE_TYPES[key](self))
            self.schedule_stack.insertWidget(0, self.schedule_widgets[0])
        vf.addWidget(ss)
        self.last_downloaded = la = QLabel(f)
        la.setWordWrap(True)
        vf.addWidget(la)
        vt.addItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))
        self.account = acc = QGroupBox(self.tab)
        acc.setTitle(_("&Account"))
        vt.addWidget(acc)
        acc.g = g = QGridLayout(acc)
        acc.unla = la = QLabel(_("&Username:"******"&Password:"******"&Show password"), self.account)
        spw.stateChanged[int].connect(self.set_pw_echo_mode)
        g.addWidget(spw, 2, 0, 1, 2)
        self.rla = la = QLabel(_("For the scheduling to work, you must leave calibre running."))
        vt.addWidget(la)
        for b, c in self.SCHEDULE_TYPES.iteritems():
            b = getattr(self, b)
            b.toggled.connect(self.schedule_type_selected)
            b.setToolTip(textwrap.dedent(c.HELP))

        # Second tab (advanced settings)
        self.tab2 = t2 = QWidget()
        self.detail_box.addTab(self.tab2, _("&Advanced"))
        self.tab2.g = g = QGridLayout(t2)
        g.setContentsMargins(0, 0, 0, 0)
        self.add_title_tag = tt = QCheckBox(_("Add &title as tag"), t2)
        g.addWidget(tt, 0, 0, 1, 2)
        t2.la = la = QLabel(_("&Extra tags:"))
        self.custom_tags = ct = QLineEdit(self)
        la.setBuddy(ct)
        g.addWidget(la), g.addWidget(ct, 1, 1)
        t2.la2 = la = QLabel(_("&Keep at most:"))
        la.setToolTip(_("Maximum number of copies (issues) of this recipe to keep.  Set to 0 to keep all (disable)."))
        self.keep_issues = ki = QSpinBox(t2)
        tt.toggled['bool'].connect(self.keep_issues.setEnabled)
        ki.setMaximum(100000), la.setBuddy(ki)
        ki.setToolTip(_(
            "<p>When set, this option will cause calibre to keep, at most, the specified number of issues"
            " of this periodical. Every time a new issue is downloaded, the oldest one is deleted, if the"
            " total is larger than this number.\n<p>Note that this feature only works if you have the"
            " option to add the title as tag checked, above.\n<p>Also, the setting for deleting periodicals"
            " older than a number of days, below, takes priority over this setting."))
        ki.setSpecialValueText(_("all issues")), ki.setSuffix(_(" issues"))
        g.addWidget(la), g.addWidget(ki, 2, 1)
        si = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        g.addItem(si, 3, 1, 1, 1)

        # Bottom area
        self.hb = h = QHBoxLayout()
        self.l.addLayout(h, 2, 1, 1, 1)
        self.labt = la = QLabel(_("Delete downloaded &news older than:"))
        self.old_news = on = QSpinBox(self)
        on.setToolTip(_(
            "<p>Delete downloaded news older than the specified number of days. Set to zero to disable.\n"
            "<p>You can also control the maximum number of issues of a specific periodical that are kept"
            " by clicking the Advanced tab for that periodical above."))
        on.setSpecialValueText(_("never delete")), on.setSuffix(_(" days"))
        on.setMaximum(1000), la.setBuddy(on)
        on.setValue(gconf['oldest_news'])
        h.addWidget(la), h.addWidget(on)
        self.download_all_button = b = QPushButton(QIcon(I('news.png')), _("Download &all scheduled"), self)
        b.setToolTip(_("Download all scheduled news sources at once"))
        b.clicked.connect(self.download_all_clicked)
        self.l.addWidget(b, 3, 0, 1, 1)
        self.bb = bb = QDialogButtonBox(QDialogButtonBox.Save, self)
        bb.accepted.connect(self.accept), bb.rejected.connect(self.reject)
        self.download_button = b = bb.addButton(_('&Download now'), bb.ActionRole)
        b.setIcon(QIcon(I('arrow-down.png'))), b.setVisible(False)
        b.clicked.connect(self.download_clicked)
        self.l.addWidget(bb, 3, 1, 1, 1)

        geom = gprefs.get('scheduler_dialog_geometry')
        if geom is not None:
            self.restoreGeometry(geom)

    def sizeHint(self):
        return QSize(800, 600)

    def set_pw_echo_mode(self, state):
        self.password.setEchoMode(self.password.Normal
                if state == Qt.Checked else self.password.Password)

    def schedule_type_selected(self, *args):
        for i, st in enumerate(self.SCHEDULE_TYPES):
            if getattr(self, st).isChecked():
                self.schedule_stack.setCurrentIndex(i)
                break

    def keyPressEvent(self, ev):
        if ev.key() not in (Qt.Key_Enter, Qt.Key_Return):
            return QDialog.keyPressEvent(self, ev)

    def break_cycles(self):
        try:
            self.recipe_model.searched.disconnect(self.search_done)
            self.recipe_model.searched.disconnect(self.search.search_done)
            self.search.search.disconnect()
            self.download.disconnect()
        except:
            pass
        self.recipe_model = None

    def search_done(self, *args):
        if self.recipe_model.showing_count < 10:
            self.recipes.expandAll()

    def toggle_schedule_info(self, *args):
        enabled = self.schedule.isChecked()
        for x in self.SCHEDULE_TYPES:
            getattr(self, x).setEnabled(enabled)
        self.schedule_stack.setEnabled(enabled)
        self.last_downloaded.setVisible(enabled)

    def current_changed(self, current, previous):
        if self.previous_urn is not None:
            self.commit(urn=self.previous_urn)
            self.previous_urn = None

        urn = self.current_urn
        if urn is not None:
            self.initialize_detail_box(urn)
        self.recipes.scrollTo(current)

    def accept(self):
        if not self.commit():
            return False
        self.save_geometry()
        return QDialog.accept(self)

    def reject(self):
        self.save_geometry()
        return QDialog.reject(self)

    def save_geometry(self):
        gprefs.set('scheduler_dialog_geometry', bytearray(self.saveGeometry()))

    def download_clicked(self, *args):
        self.commit()
        if self.commit() and self.current_urn:
            self.download.emit(self.current_urn)

    def download_all_clicked(self, *args):
        if self.commit() and self.commit():
            self.download.emit(None)

    @property
    def current_urn(self):
        current = self.recipes.currentIndex()
        if current.isValid():
            return getattr(current.internalPointer(), 'urn', None)

    def commit(self, urn=None):
        urn = self.current_urn if urn is None else urn
        if not self.detail_box.isVisible() or urn is None:
            return True

        if self.account.isVisible():
            un, pw = map(unicode, (self.username.text(), self.password.text()))
            un, pw = un.strip(), pw.strip()
            if not un and not pw and self.schedule.isChecked():
                if not getattr(self, 'subscription_optional', False):
                    error_dialog(self, _('Need username and password'),
                            _('You must provide a username and/or password to '
                                'use this news source.'), show=True)
                    return False
            if un or pw:
                self.recipe_model.set_account_info(urn, un, pw)
            else:
                self.recipe_model.clear_account_info(urn)

        if self.schedule.isChecked():
            schedule_type, schedule = \
                    self.schedule_stack.currentWidget().schedule
            self.recipe_model.schedule_recipe(urn, schedule_type, schedule)
        else:
            self.recipe_model.un_schedule_recipe(urn)

        add_title_tag = self.add_title_tag.isChecked()
        keep_issues = u'0'
        if self.keep_issues.isEnabled():
            keep_issues = unicode(self.keep_issues.value())
        custom_tags = unicode(self.custom_tags.text()).strip()
        custom_tags = [x.strip() for x in custom_tags.split(',')]
        self.recipe_model.customize_recipe(urn, add_title_tag, custom_tags, keep_issues)
        return True

    def initialize_detail_box(self, urn):
        self.previous_urn = urn
        self.detail_box.setVisible(True)
        self.download_button.setVisible(True)
        self.detail_box.setCurrentIndex(0)
        recipe = self.recipe_model.recipe_from_urn(urn)
        try:
            schedule_info = self.recipe_model.schedule_info_from_urn(urn)
        except:
            # Happens if user does something stupid like unchecking all the
            # days of the week
            schedule_info = None
        account_info = self.recipe_model.account_info_from_urn(urn)
        customize_info = self.recipe_model.get_customize_info(urn)

        ns = recipe.get('needs_subscription', '')
        self.account.setVisible(ns in ('yes', 'optional'))
        self.subscription_optional = ns == 'optional'
        act = _('Account')
        act2 = _('(optional)') if self.subscription_optional else \
                _('(required)')
        self.account.setTitle(act+' '+act2)
        un = pw = ''
        if account_info is not None:
            un, pw = account_info[:2]
            if not un:
                un = ''
            if not pw:
                pw = ''
        self.username.setText(un)
        self.password.setText(pw)
        self.show_password.setChecked(False)

        self.blurb.setText('''
        <p>
        <b>%(title)s</b><br>
        %(cb)s %(author)s<br/>
        %(description)s
        </p>
        '''%dict(title=recipe.get('title'), cb=_('Created by: '),
            author=recipe.get('author', _('Unknown')),
            description=recipe.get('description', '')))
        self.download_button.setToolTip(
                _('Download %s now')%recipe.get('title'))
        scheduled = schedule_info is not None
        self.schedule.setChecked(scheduled)
        self.toggle_schedule_info()
        self.last_downloaded.setText(_('Last downloaded: never'))
        ld_text = _('never')
        if scheduled:
            typ, sch, last_downloaded = schedule_info
            d = utcnow() - last_downloaded
            def hm(x):
                return (x-x%3600)//3600, (x%3600 - (x%3600)%60)//60
            hours, minutes = hm(d.seconds)
            tm = _('%(days)d days, %(hours)d hours'
                    ' and %(mins)d minutes ago')%dict(
                            days=d.days, hours=hours, mins=minutes)
            if d < timedelta(days=366):
                ld_text = tm
        else:
            typ, sch = 'day/time', (-1, 6, 0)
        sch_widget = {'day/time': 0, 'days_of_week': 0, 'days_of_month':1,
                'interval':2}[typ]
        rb = getattr(self, list(self.SCHEDULE_TYPES)[sch_widget])
        rb.setChecked(True)
        self.schedule_stack.setCurrentIndex(sch_widget)
        self.schedule_stack.currentWidget().initialize(typ, sch)
        add_title_tag, custom_tags, keep_issues = customize_info
        self.add_title_tag.setChecked(add_title_tag)
        self.custom_tags.setText(u', '.join(custom_tags))
        self.last_downloaded.setText(_('Last downloaded:') + ' ' + ld_text)
        try:
            keep_issues = int(keep_issues)
        except:
            keep_issues = 0
        self.keep_issues.setValue(keep_issues)
        self.keep_issues.setEnabled(self.add_title_tag.isChecked())
class PanelQWidget(QWidget):
    """
        Class who manage Panel with Host and Services QWidgets
    """
    def __init__(self, parent=None):
        super(PanelQWidget, self).__init__(parent)
        self.setAcceptDrops(True)
        # Fields
        self.tab_widget = QTabWidget()
        self.layout = QVBoxLayout()
        self.dashboard_widget = DashboardQWidget()
        self.synthesis_widget = SynthesisQWidget()
        self.problems_widget = ProblemsQWidget()
        self.spy_widget = SpyQWidget()
        self.hostnames_list = []

    def initialize(self):
        """
        Create the QWidget with its items and layout.

        """

        logger.info('Create Panel View...')
        self.setLayout(self.layout)

        # Dashboard widget
        self.dashboard_widget.initialize()
        self.layout.addWidget(self.dashboard_widget)

        self.tab_widget.setMovable(True)
        self.layout.addWidget(self.tab_widget)
        tab_order = self.get_tab_order()

        # Set hostnames
        self.hostnames_list = data_manager.get_all_hostnames()

        # Synthesis
        self.synthesis_widget.initialize_synthesis()
        self.synthesis_widget.host_widget.spy_btn.clicked.connect(
            self.spy_host)
        self.synthesis_widget.line_search.returnPressed.connect(
            self.display_host)
        self.synthesis_widget.line_search.cursorPositionChanged.connect(
            self.display_host)
        self.synthesis_widget.create_line_search(self.hostnames_list)
        self.tab_widget.insertTab(tab_order.index('h'), self.synthesis_widget,
                                  _('Host Synthesis'))
        self.tab_widget.setTabToolTip(
            self.tab_widget.indexOf(self.synthesis_widget),
            _('See a synthesis view of a host'))

        # Problems
        self.problems_widget.initialize(self.spy_widget)
        self.problems_widget.host_btn.clicked.connect(self.display_host)
        self.problems_widget.problems_table.doubleClicked.connect(
            self.set_host_from_problems)
        self.tab_widget.insertTab(
            tab_order.index('p'), self.problems_widget,
            _('Problems (%d)') % len(data_manager.get_problems()['problems']))
        self.tab_widget.setTabToolTip(
            self.tab_widget.indexOf(self.problems_widget),
            _('See the problems found in backend'))

        # Spied hosts
        self.spy_widget.initialize()
        self.tab_widget.insertTab(tab_order.index('s'), self.spy_widget,
                                  _('Spy Hosts'))
        self.tab_widget.setTabToolTip(self.tab_widget.indexOf(self.spy_widget),
                                      _('See spy hosts by Alignak-app'))

        # Hide widget for first display
        self.dashboard_widget.show()
        self.synthesis_widget.host_widget.hide()
        self.synthesis_widget.services_widget.hide()

    @staticmethod
    def get_tab_order():
        """
        Return tab order defined by user, else default order

        :return: tab order of App
        :rtype: list
        """

        default_order = ['p', 'h', 's']
        tab_order = settings.get_config('Alignak-app', 'tab_order').split(',')

        try:
            assert len(tab_order) == len(default_order)
            for nb in default_order:
                assert nb in tab_order
        except AssertionError:
            logger.error('Wrong "tab_order" value in config file %s',
                         tab_order)
            tab_order = default_order

        return tab_order

    def spy_host(self):
        """
        Spy host who is available in line_search QLineEdit

        """

        if self.synthesis_widget.line_search.text() in self.hostnames_list:
            # Spy host
            self.spy_widget.spy_list_widget.add_spy_host(
                self.synthesis_widget.host_widget.host_item.item_id)

            # Update QWidgets
            self.synthesis_widget.host_widget.spy_btn.setEnabled(False)
            self.tab_widget.setTabText(
                self.tab_widget.indexOf(self.spy_widget),
                _("Spied Hosts (%d)") %
                self.spy_widget.spy_list_widget.count())

    def display_host(self):
        """
        Display and update HostQWidget

        """

        # Update and set "line_search" in case hosts have been added or deleted
        hostnames_list = data_manager.get_all_hostnames()
        if hostnames_list != self.hostnames_list:
            self.synthesis_widget.create_line_search(hostnames_list)

        # If sender is QPushButton from problems, set "line_search" text
        if isinstance(self.sender(), QPushButton):
            self.set_host_from_problems()

        # Display host if exists
        if self.synthesis_widget.line_search.text().rstrip(
        ) in self.hostnames_list:
            # Get Host Item and its services
            host = self.get_current_host()
            services = data_manager.get_host_services(host.item_id)

            if not services:
                app_backend.query_services(host.item_id)
                services = data_manager.get_host_services(host.item_id)

            # Update QWidgets
            self.tab_widget.setTabText(
                self.tab_widget.indexOf(self.synthesis_widget),
                _('Host "%s"') % host.get_display_name())
            not_spied = bool(host.item_id not in
                             self.spy_widget.spy_list_widget.spied_hosts)
            self.synthesis_widget.update_synthesis(host, services, not_spied)
            self.dashboard_widget.update_dashboard()
        else:
            self.synthesis_widget.update_synthesis(None, None, True)
            self.tab_widget.setTabText(
                self.tab_widget.indexOf(self.synthesis_widget),
                _('Host Synthesis'))

    def set_host_from_problems(self):
        """
        Set line search if ``sender()`` is instance of QPushButton from
        :class:`Problems <alignak_app.qobjects.alignak.problems.ProblemsQWidget>` QWidget

        """

        item = self.problems_widget.get_current_user_role_item()
        if item:
            if 'service' in item.item_type:
                hostname = data_manager.get_item('host',
                                                 item.data['host']).name
            else:
                hostname = item.name

            if hostname in self.hostnames_list:
                self.synthesis_widget.line_search.setText(hostname)
                self.tab_widget.setCurrentIndex(
                    self.tab_widget.indexOf(self.synthesis_widget))

    def get_current_host(self):
        """
        Return current Host item with name in QLineEdit

        :return: current host
        :rtype: alignak_app.items.host.Host
        """

        current_host = data_manager.get_item(
            'host',
            self.synthesis_widget.line_search.text().rstrip())

        return current_host

    def dragMoveEvent(self, event):  # pragma: no cover
        """
        Override dragMoveEvent.
         Only accept EventItem() objects who have ``Qt.UserRole``

        :param event: event triggered when something move
        """

        if event.source().currentItem().data(Qt.UserRole):
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):  # pragma: no cover
        """
        Override dropEvent.
         Get dropped item data, create a new one, and delete the one who is in EventsQWidget

        :param event: event triggered when something is dropped
        """

        host = data_manager.get_item(
            'host', '_id',
            event.source().currentItem().data(Qt.UserRole))

        logger.debug('Drag and drop host in Panel: %s', host.name)
        logger.debug('... with current item: %s', event.source().currentItem())

        self.synthesis_widget.line_search.setText(host.name)
        self.tab_widget.setCurrentIndex(
            self.tab_widget.indexOf(self.synthesis_widget))
        self.display_host()

    def dragEnterEvent(self, event):
        """
        Override dragEnterEvent.

        :param event: event triggered when something enter
        """

        event.accept()
        event.acceptProposedAction()
Example #10
0
class UFDebugToolUI(object):
    def __init__(self, window=None):
        self.window = window if window is not None else QWidget
        super(UFDebugToolUI, self).__init__()
        self.lang = 'en'
        self.set_ui()

    def set_ui(self):
        self._set_window()
        self._set_menubar()
        self._set_tab()

    def _set_window(self):
        self.window.setWindowTitle(self.window.tr('UF-Debug-Tool'))
        self.window.setMinimumHeight(800)
        self.window.setMinimumWidth(1080)
        self.main_layout = QVBoxLayout(self.window)

    def _set_menubar(self):
        self.menuBar = QMenuBar()
        self.main_layout.setMenuBar(self.menuBar)

        fileMenu = self.menuBar.addMenu('File')
        self.newFileAction = QAction(self.window.tr('New'), self.window)
        self.newFileAction.setShortcut('Ctrl+N')
        self.newFileAction.setStatusTip('New File')
        fileMenu.addAction(self.newFileAction)

        self.openFileAction = QAction(self.window.tr('Open'), self.window)
        self.openFileAction.setShortcut('Ctrl+O')
        self.openFileAction.setToolTip('Open File')
        fileMenu.addAction(self.openFileAction)

        self.saveFileAction = QAction(self.window.tr('Save'), self.window)
        self.saveFileAction.setShortcut('Ctrl+S')
        self.saveFileAction.setStatusTip('Save File')
        fileMenu.addAction(self.saveFileAction)

        self.closeFileAction = QAction(self.window.tr('Close'), self.window)
        self.closeFileAction.setShortcut('Ctrl+W')
        self.closeFileAction.setStatusTip('Close File')
        fileMenu.addAction(self.closeFileAction)

        self.newFileAction.triggered.connect(self.new_dialog)
        self.openFileAction.triggered.connect(self.open_dialog)
        self.saveFileAction.triggered.connect(self.save_dialog)
        self.closeFileAction.triggered.connect(self.close_dialog)

        debugMenu = self.menuBar.addMenu('Debug')
        self.logAction = QAction(self.window.tr('Log'), self.window)
        self.logAction.setShortcut('Ctrl+D')
        self.logAction.setStatusTip('Open-Log')
        self.logAction.triggered.connect(self.control_log_window)
        debugMenu.addAction(self.logAction)

    def control_log_window(self):
        if self.window.log_window.isHidden():
            self.window.log_window.show()
            self.logAction.setText('Close-Log')
        else:
            self.window.log_window.hide()
            self.logAction.setText('Open-Log')

    def switch_tab(self, index):
        pass
        # if index == 2:
        #     self.menuBar.setHidden(False)
        # else:
        #     self.menuBar.setHidden(True)

    def _set_tab(self):
        self.tab_widget = QTabWidget()
        # self.tab_widget.currentChanged.connect(self.switch_tab)
        # tab_widget.setMaximumHeight(self.window.geometry().height() // 2)
        self.main_layout.addWidget(self.tab_widget)

        toolbox1 = QToolBox()
        toolbox2 = QToolBox()
        toolbox3 = QToolBox()
        toolbox4 = QToolBox()
        toolbox5 = QToolBox()

        groupbox1 = QGroupBox()
        groupbox2 = QGroupBox()
        groupbox3 = QGroupBox()
        groupbox4 = QGroupBox()
        groupbox5 = QGroupBox()

        toolbox1.addItem(groupbox1, "")
        toolbox2.addItem(groupbox2, "")
        toolbox3.addItem(groupbox3, "")
        toolbox4.addItem(groupbox4, "")
        toolbox5.addItem(groupbox5, "")

        self.tab_widget.addTab(toolbox1, "uArm")
        self.tab_widget.addTab(toolbox2, "xArm")
        self.tab_widget.addTab(toolbox3, "OpenMV")
        self.tab_widget.addTab(toolbox4, "Gcode")
        self.tab_widget.addTab(toolbox5, "WebView")

        uarm_layout = QVBoxLayout(groupbox1)
        xarm_layout = QVBoxLayout(groupbox2)
        openmv_layout = QHBoxLayout(groupbox3)
        gcode_layout = QVBoxLayout(groupbox4)
        webview_layout = QVBoxLayout(groupbox5)

        self.uarm_ui = UArmUI(self, uarm_layout)
        self.xarm_ui = XArmUI(self, xarm_layout)
        self.openmv_ui = OpenMV_UI(self, openmv_layout)
        self.gcode_ui = GcodeUI(self, gcode_layout)
        self.webview_ui = WebViewUI(self, webview_layout)
        self.tab_widget.setCurrentIndex(0)

    def new_dialog(self):
        self.openmv_ui.textEdit.setText('')
        self.openmv_ui.textEdit.filename = None
        self.openmv_ui.label_title.setText('untitled')
        self.tab_widget.setCurrentIndex(2)
        self.openmv_ui.textEdit.setDisabled(False)

    def open_dialog(self):
        fname = QFileDialog.getOpenFileName(self.window, 'Open file', '')
        if fname and fname[0]:
            with open(fname[0], "r") as f:
                self.openmv_ui.textEdit.setText(f.read())
                self.openmv_ui.label_title.setText(fname[0])
                self.openmv_ui.textEdit.filename = fname[0]
        self.tab_widget.setCurrentIndex(2)
        self.openmv_ui.textEdit.setDisabled(False)

    def save_dialog(self):
        widget = self.window.focusWidget()
        if widget:
            if not self.openmv_ui.textEdit.filename:
                fname = QFileDialog.getSaveFileName(self.window, 'Save File',
                                                    '')
                if fname and fname[0]:
                    self.openmv_ui.textEdit.filename = fname[0]
            if self.openmv_ui.textEdit.filename:
                data = widget.toPlainText()
                with open(self.openmv_ui.textEdit.filename, "w") as f:
                    f.write(data)

    def close_dialog(self):
        self.openmv_ui.textEdit.clear()
        self.openmv_ui.textEdit.filename = None
        self.openmv_ui.label_title.setText('')
        self.openmv_ui.textEdit.setDisabled(True)
class PanelQWidget(QWidget):
    """
        Class who manage Panel with Host and Services QWidgets
    """

    def __init__(self, parent=None):
        super(PanelQWidget, self).__init__(parent)
        self.setAcceptDrops(True)
        # Fields
        self.tab_widget = QTabWidget()
        self.layout = QVBoxLayout()
        self.dashboard_widget = DashboardQWidget()
        self.synthesis_widget = SynthesisQWidget()
        self.problems_widget = ProblemsQWidget()
        self.spy_widget = SpyQWidget()
        self.hostnames_list = []

    def initialize(self):
        """
        Create the QWidget with its items and layout.

        """

        logger.info('Create Panel View...')
        self.setLayout(self.layout)

        # Dashboard widget
        self.dashboard_widget.initialize()
        self.layout.addWidget(self.dashboard_widget)

        self.tab_widget.setMovable(True)
        self.layout.addWidget(self.tab_widget)
        tab_order = self.get_tab_order()

        # Set hostnames
        self.hostnames_list = data_manager.get_all_hostnames()

        # Synthesis
        self.synthesis_widget.initialize_synthesis()
        self.synthesis_widget.host_widget.spy_btn.clicked.connect(self.spy_host)
        self.synthesis_widget.line_search.returnPressed.connect(self.display_host)
        self.synthesis_widget.line_search.cursorPositionChanged.connect(self.display_host)
        self.synthesis_widget.create_line_search(self.hostnames_list)
        self.tab_widget.insertTab(tab_order.index('h'), self.synthesis_widget, _('Host Synthesis'))
        self.tab_widget.setTabToolTip(
            self.tab_widget.indexOf(self.synthesis_widget), _('See a synthesis view of a host')
        )

        # Problems
        self.problems_widget.initialize(self.spy_widget)
        self.problems_widget.host_btn.clicked.connect(self.display_host)
        self.problems_widget.problems_table.doubleClicked.connect(self.set_host_from_problems)
        self.tab_widget.insertTab(
            tab_order.index('p'),
            self.problems_widget,
            _('Problems (%d)') % len(data_manager.get_problems()['problems'])
        )
        self.tab_widget.setTabToolTip(
            self.tab_widget.indexOf(self.problems_widget), _('See the problems found in backend')
        )

        # Spied hosts
        self.spy_widget.initialize()
        self.tab_widget.insertTab(tab_order.index('s'), self.spy_widget, _('Spy Hosts'))
        self.tab_widget.setTabToolTip(
            self.tab_widget.indexOf(self.spy_widget), _('See spy hosts by Alignak-app')
        )

        # Hide widget for first display
        self.dashboard_widget.show()
        self.synthesis_widget.host_widget.hide()
        self.synthesis_widget.services_widget.hide()

    @staticmethod
    def get_tab_order():
        """
        Return tab order defined by user, else default order

        :return: tab order of App
        :rtype: list
        """

        default_order = ['p', 'h', 's']
        tab_order = settings.get_config('Alignak-app', 'tab_order').split(',')

        try:
            assert len(tab_order) == len(default_order)
            for nb in default_order:
                assert nb in tab_order
        except AssertionError:
            logger.error('Wrong "tab_order" value in config file %s', tab_order)
            tab_order = default_order

        return tab_order

    def spy_host(self):
        """
        Spy host who is available in line_search QLineEdit

        """

        if self.synthesis_widget.line_search.text() in self.hostnames_list:
            # Spy host
            self.spy_widget.spy_list_widget.add_spy_host(
                self.synthesis_widget.host_widget.host_item.item_id
            )

            # Update QWidgets
            self.synthesis_widget.host_widget.spy_btn.setEnabled(False)
            self.tab_widget.setTabText(
                self.tab_widget.indexOf(self.spy_widget),
                _("Spied Hosts (%d)") % self.spy_widget.spy_list_widget.count()
            )

    def display_host(self):
        """
        Display and update HostQWidget

        """

        # Update and set "line_search" in case hosts have been added or deleted
        hostnames_list = data_manager.get_all_hostnames()
        if hostnames_list != self.hostnames_list:
            self.synthesis_widget.create_line_search(hostnames_list)

        # If sender is QPushButton from problems, set "line_search" text
        if isinstance(self.sender(), QPushButton):
            self.set_host_from_problems()

        # Display host if exists
        if self.synthesis_widget.line_search.text().rstrip() in self.hostnames_list:
            # Get Host Item and its services
            host = self.get_current_host()
            services = data_manager.get_host_services(host.item_id)

            if not services:
                app_backend.query_services(host.item_id)
                services = data_manager.get_host_services(host.item_id)

            # Update QWidgets
            self.tab_widget.setTabText(
                self.tab_widget.indexOf(self.synthesis_widget),
                _('Host "%s"') % host.get_display_name()
            )
            not_spied = bool(
                host.item_id not in self.spy_widget.spy_list_widget.spied_hosts
            )
            self.synthesis_widget.update_synthesis(host, services, not_spied)
            self.dashboard_widget.update_dashboard()
        else:
            self.synthesis_widget.update_synthesis(None, None, True)
            self.tab_widget.setTabText(
                self.tab_widget.indexOf(self.synthesis_widget),
                _('Host Synthesis')
            )

    def set_host_from_problems(self):
        """
        Set line search if ``sender()`` is instance of QPushButton from
        :class:`Problems <alignak_app.qobjects.alignak.problems.ProblemsQWidget>` QWidget

        """

        item = self.problems_widget.get_current_user_role_item()
        if item:
            if 'service' in item.item_type:
                hostname = data_manager.get_item('host', item.data['host']).name
            else:
                hostname = item.name

            if hostname in self.hostnames_list:
                self.synthesis_widget.line_search.setText(hostname)
                self.tab_widget.setCurrentIndex(self.tab_widget.indexOf(self.synthesis_widget))

    def get_current_host(self):
        """
        Return current Host item with name in QLineEdit

        :return: current host
        :rtype: alignak_app.items.host.Host
        """

        current_host = data_manager.get_item(
            'host',
            self.synthesis_widget.line_search.text().rstrip()
        )

        return current_host

    def dragMoveEvent(self, event):  # pragma: no cover
        """
        Override dragMoveEvent.
         Only accept EventItem() objects who have ``Qt.UserRole``

        :param event: event triggered when something move
        """

        if event.source().currentItem().data(Qt.UserRole):
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):  # pragma: no cover
        """
        Override dropEvent.
         Get dropped item data, create a new one, and delete the one who is in EventsQWidget

        :param event: event triggered when something is dropped
        """

        host = data_manager.get_item('host', '_id', event.source().currentItem().data(Qt.UserRole))

        logger.debug('Drag and drop host in Panel: %s', host.name)
        logger.debug('... with current item: %s', event.source().currentItem())

        self.synthesis_widget.line_search.setText(host.name)
        self.tab_widget.setCurrentIndex(self.tab_widget.indexOf(self.synthesis_widget))
        self.display_host()

    def dragEnterEvent(self, event):
        """
        Override dragEnterEvent.

        :param event: event triggered when something enter
        """

        event.accept()
        event.acceptProposedAction()
class FSMainWindow(QMainWindow, FSBase):
    """
    Main Window
    """
    def __init__(self):
        QMainWindow.__init__(self)
        FSBase.__init__(self)

        self.progressbar = None
        self.tab_widget = None
        self.file_tree_widget = None
        self.file_tree_model = None
        self.file_scanner_thread = None

        self.movie_table_widget = None
        self.movie_table_model = None
        self.movie_scanner_thread = None

        self.build_ui()
        self.build_content()

    def build_ui(self):
        self.setWindowTitle("Filesystem Analyzer")

        settings_action = QAction(QIcon("res/settings.svg"), "Settings", self)
        settings_action.setShortcut("Ctrl+S")
        settings_action.triggered.connect(self.settings_action_handler)

        set_path_action = QAction(QIcon("res/directory-submission-symbol.svg"),
                                  "Set path", self)
        set_path_action.setShortcut("Ctrl+N")
        set_path_action.triggered.connect(self.set_path_action_handler)

        refresh_action = QAction(QIcon("res/reload.svg"), "Refresh", self)
        refresh_action.setShortcut("Ctrl+R")
        refresh_action.triggered.connect(self.refresh_action_handler)

        menu_bar = self.menuBar()
        action_menu = menu_bar.addMenu("&Action")
        action_menu.addAction(settings_action)
        action_menu.addAction(set_path_action)
        action_menu.addAction(refresh_action)
        toolbar = self.addToolBar("Exit")
        toolbar.addAction(settings_action)
        toolbar.addAction(set_path_action)
        toolbar.addAction(refresh_action)

        self.progressbar = QProgressBar(self)
        self.progressbar.hide()
        self.progressbar.setRange(0, 100)

        cancel_button = QPushButton(QIcon("res/cancel-button.svg"), "Cancel",
                                    self)
        cancel_button.clicked.connect(self.set_path_cancel)

        self.statusBar().addPermanentWidget(self.progressbar)
        self.statusBar().addPermanentWidget(cancel_button)

        self.tab_widget = QTabWidget(self)

        self.file_tree_widget = FSFileTreeWidget()
        self.file_tree_model = FSFileTreeModel()
        self.file_tree_widget.setModel(self.file_tree_model)

        self.movie_table_widget = FSMovieTableWidget()
        self.movie_table_widget.setShowGrid(False)
        self.movie_table_widget.setAlternatingRowColors(True)
        self.movie_table_widget.verticalHeader().setVisible(False)
        self.movie_table_widget.setSelectionBehavior(QTableView.SelectRows)
        self.movie_table_model = FSMovieTableModel()
        self.movie_table_widget.setModel(self.movie_table_model)
        self.tab_widget.addTab(self.file_tree_widget, "General")
        self.tab_widget.addTab(self.movie_table_widget, "Movies")
        self.setCentralWidget(self.tab_widget)

        last_tab_index = self.app.load_setting("last_tab_index")
        if last_tab_index:
            self.tab_widget.setCurrentIndex(int(last_tab_index))
        self.tab_widget.currentChanged.connect(self.tab_widget_changed)

        self.show()

    def settings_action_handler(self):
        settings_dialog = FSSettingsDialog(self)
        settings_dialog.show()

    def build_content(self):
        path = self.app.load_setting("path")
        self.set_path(path)

    def set_path_action_handler(self):
        file_dialog = QFileDialog()
        path = file_dialog.getExistingDirectory(
            self, "Select directory", "/home/",
            QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)
        self.logger.info("Path set to %s", path)
        self.set_path(path)
        self.app.save_setting("path", path)

    def set_path(self, path):
        self.progressbar.show()

        if self.tab_widget.currentIndex() == 0:
            self.file_tree_model.reset_root()
            file_scanner_context = FSFileScannerContext(
                path, self.file_tree_model.root)
            self.file_scanner_thread = FSFileScannerTask(
                self, file_scanner_context)
            self.file_scanner_thread.notifyProgress.connect(
                self.update_progress)
            self.file_scanner_thread.notifyFinish.connect(
                self.set_path_action_finish)
            self.file_scanner_thread.notifyError.connect(self.report_error)
            self.file_scanner_thread.start()
        else:
            movie_extensions = self.app.load_setting(
                self.app.ExtensionSettings[FSExtensionType.TYPE_MOVIE])
            movie_extensions_list = [
                movie_extension.strip()
                for movie_extension in movie_extensions.split(",")
            ]
            movie_scanner_context = FSMovieScannerContext(
                path, self.movie_table_model.movies, movie_extensions_list)
            self.movie_scanner_thread = FSMovieScannerTask(
                self, movie_scanner_context)
            self.movie_scanner_thread.notifyProgress.connect(
                self.update_progress)
            self.movie_scanner_thread.notifyFinish.connect(
                self.set_path_action_finish)
            self.movie_scanner_thread.notifyError.connect(self.report_error)
            self.movie_scanner_thread.start()

    def set_path_action_finish(self):
        self.progressbar.hide()
        if self.tab_widget.currentIndex() == 0:
            self.file_tree_model.reset_model()
            self.file_tree_widget.setColumnWidth(0, 250)
        else:
            self.movie_table_model.reset_model()
            self.movie_table_widget.resizeColumnsToContents()

    def set_path_cancel(self):
        self.file_scanner_thread.stop_flag = True

    def refresh_action_handler(self):
        path = self.app.load_setting("path")
        self.set_path(path)

    def update_progress(self, value):
        self.progressbar.setValue(value)

    def report_error(self, error):
        print(error)

    def tab_widget_changed(self, index):
        self.app.save_setting("last_tab_index", index)
Example #13
0
class LibraryCodesDialog(SizePersistedDialog):
    #-----------------------------------------------------------------------------------------
    def __init__(self, gui, icon, guidb, plugin_path, ui_exit, action_type):
        parent = gui
        unique_pref_name = 'library_codes:gui_parameters_dialog'
        SizePersistedDialog.__init__(self, parent, unique_pref_name)
        #-----------------------------------------------------
        self.gui = gui
        self.guidb = guidb
        #-----------------------------------------------------
        self.icon = icon
        #-----------------------------------------------------
        self.plugin_path = plugin_path
        #-----------------------------------------------------
        self.ui_exit = ui_exit
        #-----------------------------------------------------
        self.action_type = action_type
        #-----------------------------------------------------
        self.myparentprefs = collections.OrderedDict([])
        prefsdefaults = deepcopy(prefs.defaults)
        tmp_list = []
        #~ for k,v in prefs.iteritems():
        for k, v in iteritems(prefs):
            tmp_list.append(k)
        #END FOR
        #~ for k,v in prefsdefaults.iteritems():
        for k, v in iteritems(prefsdefaults):
            tmp_list.append(k)
        #END FOR
        tmp_set = set(tmp_list)
        tmp_list = list(tmp_set)  #no duplicates
        del tmp_set
        tmp_list.sort()
        for k in tmp_list:
            self.myparentprefs[k] = " "  # ordered by key
        #END FOR
        del tmp_list
        #~ for k,v in prefs.iteritems():
        for k, v in iteritems(prefs):
            self.myparentprefs[k] = v
        #END FOR
        #~ for k,v in prefsdefaults.iteritems():
        for k, v in iteritems(prefsdefaults):
            if not k in prefs:
                prefs[k] = v
            else:
                if not prefs[k] > " ":
                    prefs[k] = v
            if not k in self.myparentprefs:
                self.myparentprefs[k] = v
            else:
                if not self.myparentprefs[k] > " ":
                    self.myparentprefs[k] = v
        #END FOR
        #~ for k,v in self.myparentprefs.iteritems():
        for k, v in iteritems(self.myparentprefs):
            prefs[k] = v
        #END FOR
        prefs  #prefs now synched
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.param_dict = collections.OrderedDict([])
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.init_tooltips_for_parent()
        self.setToolTip(self.parent_tooltip)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        # Tab 0: LibraryCodesTab
        #-----------------------------------------------------
        #-----------------------------------------------------
        from calibre_plugins.library_codes.library_codes_dialog import LibraryCodesTab
        self.LibraryCodesTab = LibraryCodesTab(self.gui, self.guidb,
                                               self.myparentprefs,
                                               self.param_dict, self.ui_exit,
                                               self.save_dialog_geometry)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #    Parent             LibraryCodesDialog
        #-----------------------------------------------------
        font = QFont()
        font.setBold(False)
        font.setPointSize(10)

        tablabel_font = QFont()
        tablabel_font.setBold(False)
        tablabel_font.setPointSize(10)

        #-----------------------------------------------------
        self.setWindowTitle('Library Codes')
        self.setWindowIcon(icon)
        #-----------------------------------------------------
        self.layout_frame = QVBoxLayout()
        self.layout_frame.setAlignment(Qt.AlignLeft)
        self.setLayout(self.layout_frame)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        n_width = 600

        self.LCtabWidget = QTabWidget()
        self.LCtabWidget.setMaximumWidth(n_width)
        self.LCtabWidget.setFont(tablabel_font)

        self.LCtabWidget.addTab(
            self.LibraryCodesTab,
            "Derivation from ISBN or ISSN or Author/Title")
        self.LibraryCodesTab.setToolTip(
            "<p style='white-space:wrap'>Derive Library Codes DDC and/or LCC and/or OCLC-OWI from ISBN or ISSN or Author/Title.  Visit: http://classify.oclc.org/classify2/ "
        )
        self.LibraryCodesTab.setMaximumWidth(n_width)

        #-----------------------------------------------------
        self.layout_frame.addWidget(self.LCtabWidget)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.resize_dialog()  # inherited from SizePersistedDialog
        #-----------------------------------------------------
        self.LCtabWidget.setCurrentIndex(0)

    #-----------------------------------------------------------------------------------------
    #-----------------------------------------------------------------------------------------

    #-----------------------------------------------------------------------------------------
    #-----------------------------------------------------------------------------------------
    # OTHER
    #-----------------------------------------------------------------------------------------
    #-----------------------------------------------------------------------------------------
    def init_tooltips_for_parent(self):
        self.setStyleSheet(
            "QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }"
        )
        self.parent_tooltip = "<p style='white-space:wrap'>" + \
        '''