Beispiel #1
1
class MainWindow(QMainWindow):
    
#    class EventFilter(QObject):
#        def __init__(self, parent):
#            super().__init__(parent)
#
#        def eventFilter(self, obj, e):
#            #print(obj.metaObject().className())
#
#            if e.type() == QEvent.KeyPress or e.type() == QEvent.ShortcutOverride:
#                key = e.key()
#                mod = e.modifiers()
#
#                print(str(e) + ' ' + str(e.type()) )
#
#                if mod == Qt.AltModifier:
#                    print('*'*30)
#                    print('alt pressed')
#                    if key == Qt.Key_Left or key == Qt.Key_Right:
#                        print('alt-left') if key == Qt.Key_Left else print('alt-right')
##                       action = QAbstractItemView.MoveLeft if key == Qt.Key_Left else QAbstractItemView.MoveRight
##                       idx = obj.moveCursor(action, Qt.NoModifier)
##                       item = obj.itemFromIndex(idx)
##                       obj.setCurrentItem(item)
#                        return True
#
#            return False


    PROGRAM_NAME = 'KiCad Schematic Component Manager'

    #--------------------------------------------------------------------------------
    class EventFilter(QObject):
        def __init__(self, parent):
            super().__init__(parent)

        def eventFilter(self, obj, e):
            if e.type() == QEvent.KeyPress or e.type() == QEvent.ShortcutOverride:
                key = e.key()
                mod = e.modifiers()

                #print(obj.focusWidget().metaObject().className())

            return False
    #--------------------------------------------------------------------------------
    def scroll_left(self):
        print('alt-left')
        if self.ToolIndex == 3 or self.ToolIndex == 2:
            self.ToolList[self.ToolIndex].finish_edit()
            
        self.ToolIndex -= 1
        if self.ToolIndex < 0:
            self.ToolIndex = len(self.ToolList) - 1
            
        print('Tool Index: ' + str(self.ToolIndex))
        self.ToolList[self.ToolIndex].setFocus()
    #--------------------------------------------------------------------------------    
    def scroll_right(self):
        print('alt-right')
        if self.ToolIndex == 3 or self.ToolIndex == 2:
            self.ToolList[self.ToolIndex].finish_edit()
            
        self.ToolIndex += 1
        if self.ToolIndex == len(self.ToolList):
            self.ToolIndex = 0

        print('Tool Index: ' + str(self.ToolIndex))
        self.ToolList[self.ToolIndex].setFocus()
    #--------------------------------------------------------------------------------    
    def mouse_change_tool(self, s):
        print('Tool ' + s)
        if s == 'CmpTable':
            self.ToolIndex = 0
        elif s == 'Selector':
            self.ToolIndex = 1
        elif s == 'Inspector':
            self.ToolIndex = 2
        elif s == 'FieldInspector':
            self.ToolIndex = 3
            
        if self.ToolIndex != 3:
            self.ToolList[3].finish_edit()  # save field properties when leave field inspector
    #--------------------------------------------------------------------------------    
    def add_user_property(self):
        self.Inspector.save_cmps()
        self.FieldInspector.save_fields()
        
        self.Inspector.add_property()
    #--------------------------------------------------------------------------------
    def remove_user_property(self):
        #self.Inspector.save_cmps()
        self.FieldInspector.save_fields()

        self.Inspector.remove_property()
    #--------------------------------------------------------------------------------        
    def rename_user_property(self):
        #self.Inspector.save_cmps()
        self.FieldInspector.save_fields()
                    
        self.Inspector.rename_property()
    #--------------------------------------------------------------------------------    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        self.installEventFilter(self.EventFilter(self))
        
        self.setFocusPolicy(Qt.WheelFocus)
        self.setTabOrder(self.CmpTable,      self.Inspector )
        self.setTabOrder(self.Inspector,     self.Selector)
        self.setTabOrder(self.Selector,      self.FieldInspector)
        #self.setTabOrder(self.FieldInspector, self.CmpTable)

        #----------------------------------------------------
        #
        #   Application Hotkeys
        #
        self.shortcutLeft  = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Left), self)
        self.shortcutRight = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Right), self)
        self.shortcutLeft.setContext(Qt.ApplicationShortcut)
        self.shortcutRight.setContext(Qt.ApplicationShortcut)
        self.shortcutLeft.activated.connect(self.scroll_left)
        self.shortcutRight.activated.connect(self.scroll_right)
        
    #--------------------------------------------------------------------------------    
    def initUI(self):
        
        #----------------------------------------------------
        #
        #    Main Window
        #
        work_zone = QWidget(self)
        Layout    = QHBoxLayout(work_zone)
        self.setCentralWidget(work_zone)
        
        openAction = QAction(QIcon( os.path.join(resources_path, 'open24.png') ), 'Open', self)
        openAction.setShortcut('Ctrl+O')
        openAction.setStatusTip('Open Schematic File')
        openAction.triggered.connect(self.open_file)
        
        saveAction = QAction(QIcon( os.path.join(resources_path, 'save24.png') ), 'Save', self)
        saveAction.setShortcut('Ctrl+S')
        saveAction.setStatusTip('Save Schematic File')
        saveAction.triggered.connect(self.save_file)
                
        saveAsAction = QAction(QIcon( os.path.join(resources_path, 'save-as24.png') ), 'Save As...', self)
        saveAsAction.setShortcut('Ctrl+Shift+S')
        saveAsAction.setStatusTip('Save Schematic File As...')
        saveAsAction.triggered.connect(self.save_file_as)
        
                        
        exitAction = QAction(QIcon( os.path.join(resources_path, 'exit24.png') ), 'Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)
        
        settingsAction = QAction(QIcon( os.path.join(resources_path, 'settings24.png') ), 'Settings', self)
        settingsAction.setShortcut('Ctrl+Alt+S')
        settingsAction.setStatusTip('Edit settings')
        settingsAction.triggered.connect(self.edit_settings)
        
        helpAction = QAction(QIcon( os.path.join(resources_path, 'help_book24.png') ), 'User\'s Manual', self)
        helpAction.setShortcut('F1')
        helpAction.setStatusTip('User\'s Manual')
        helpAction.triggered.connect(self.show_user_manual_slot)
        
        helpSDAction = QAction(QIcon( os.path.join(resources_path, 'gear24.png') ), 'Settings Dialog', self)
        helpSDAction.setShortcut('Ctrl+F1')
        helpSDAction.setStatusTip('Settings Dialog Help')
        helpSDAction.triggered.connect(self.show_setting_dialog_help_slot)
                
        helpHKAction = QAction(QIcon( os.path.join(resources_path, 'rocket24.png') ), 'Hotkeys', self)
        helpHKAction.setShortcut('Shift+F1')
        helpHKAction.setStatusTip('Hotkeys Help')
        helpHKAction.triggered.connect(self.show_hotkeys_help_slot)

        self.statusBar().showMessage('Ready')

        #--------------------------------------------
        #
        #    Main Menu
        #
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(openAction)
        fileMenu.addAction(saveAction)
        fileMenu.addAction(saveAsAction)
        fileMenu.addAction(exitAction)

        #--------------------------------------------
        #
        #    Options Menu
        #
        optionsMenu = menubar.addMenu('&Options')
        optionsMenu.addAction(settingsAction)
        
        #--------------------------------------------
        #
        #    Help Menu
        #
        helpMenu = menubar.addMenu('&Help')
        helpMenu.addAction(helpAction)
        helpMenu.addAction(helpSDAction)
        helpMenu.addAction(helpHKAction)
                
        #--------------------------------------------
        #
        #    Toolbar
        #
        toolbar = self.addToolBar('Exit')
        toolbar.addAction(exitAction)        
        toolbar.addAction(openAction)        
        toolbar.addAction(saveAction)        
        toolbar.addAction(saveAsAction)        
        toolbar.addAction(settingsAction)        
        toolbar.addAction(helpAction)        
        
        #----------------------------------------------------
        #
        #    Settings Dialog
        #
        
        #----------------------------------------------------
        #
        #    Components Table
        #
        self.CmpTabBox    = QGroupBox('Components', self)
        self.CmpTabLayout = QVBoxLayout(self.CmpTabBox)
        self.CmpTabLayout.setContentsMargins(4,10,4,4)
        self.CmpTabLayout.setSpacing(10)

        self.CmpTabLayout.setSizeConstraint(QVBoxLayout.SetMaximumSize)

        self.CmpTable       = ComponentsTable(self) 
        #self.CmpChooseButton = QPushButton('Choose', self)
        
        self.CmpTabLayout.addWidget(self.CmpTable)
        #self.CmpTabLayout.addWidget(self.CmpChooseButton)
        
                
        #----------------------------------------------------
        #
        #    Selector
        #
        self.SelectorBox    = QGroupBox('Selector', self)
        self.SelectorLayout = QVBoxLayout(self.SelectorBox)
        self.SelectorLayout.setContentsMargins(4,10,4,4)
        self.SelectorLayout.setSpacing(2)
        
        self.SelectorBtnWidget = QWidget(self)
        self.SelectorBtnLayout = QHBoxLayout(self.SelectorBtnWidget)
        self.SelectorBtnLayout.setContentsMargins(4,10,4,4)
        self.SelectorBtnLayout.setSpacing(10)

        self.Selector = Selector(self)

        self.SelApplyButton = QPushButton('Apply', self)
        self.SelApplyButton.setToolTip('Alt+S: Apply selection patterns to components')

        self.SelClearButton = QPushButton('Clear', self)
        self.SelClearButton.setToolTip('Alt+C: Clear selection patterns')

        self.SelTemplateButton = QPushButton('Use Component', self)
        self.SelTemplateButton.setToolTip('Alt+T: Use Selected Component As Template')


        self.SelectorLayout.addWidget(self.Selector)
        self.SelectorBtnLayout.addWidget(self.SelTemplateButton)
        self.SelectorBtnLayout.addWidget(self.SelApplyButton)
        self.SelectorBtnLayout.addWidget(self.SelClearButton)
        self.SelectorLayout.addWidget(self.SelectorBtnWidget)
        
        self.shortcutSelApply = QShortcut(QKeySequence(Qt.ALT + Qt.Key_S), self)
        self.shortcutSelApply.activated.connect(self.Selector.apply_slot)
        
        self.shortcutSelClear = QShortcut(QKeySequence(Qt.ALT + Qt.Key_C), self)
        self.shortcutSelClear.activated.connect(self.Selector.clear_slot)
                
        self.shortcutSelTemplate = QShortcut(QKeySequence(Qt.ALT + Qt.Key_T), self)
        self.shortcutSelTemplate.activated.connect(self.Selector.use_comp_as_template_slot)
        
        #----------------------------------------------------
        #
        #    Inspector
        #
        self.Inspector       = Inspector(self)
        self.FieldInspector  = FieldInspector(self)

        self.InspectorBtnWidget = QWidget(self)
        self.InspectorBtnLayout = QHBoxLayout(self.InspectorBtnWidget)
        self.InspectorBtnLayout.setContentsMargins(4,10,4,4)
        self.InspectorBtnLayout.setSpacing(10)
        

        self.AddUserProperty    = QPushButton('Add Property', self)
        self.AddUserProperty.setToolTip('Alt+A: Add new user property')
        self.DeleteUserProperty = QPushButton('Delete Property', self)
        self.DeleteUserProperty.setToolTip('Alt+Delete: Delete user property')
        self.RenameUserProperty = QPushButton('Rename Property', self)
        self.RenameUserProperty.setToolTip('Alt+R: Rename user property')
        
        self.InspectorBox    = QGroupBox('Inspector', self)
        self.InspectorSplit  = QSplitter(Qt.Vertical, self)
        self.InspectorLayout = QVBoxLayout(self.InspectorBox)
        self.InspectorLayout.setContentsMargins(4,10,4,4)
        self.InspectorLayout.setSpacing(2)
        
        
        self.InspectorSplit.addWidget(self.Inspector)
        self.InspectorSplit.addWidget(self.FieldInspector)
        self.InspectorLayout.addWidget(self.InspectorSplit)
        
        self.InspectorBtnLayout.addWidget(self.AddUserProperty)
        self.InspectorBtnLayout.addWidget(self.DeleteUserProperty)
        self.InspectorBtnLayout.addWidget(self.RenameUserProperty)
                
        self.InspectorLayout.addWidget(self.InspectorBtnWidget)

        self.shortcutSelApply = QShortcut(QKeySequence(Qt.ALT + Qt.Key_A), self)
        self.shortcutSelApply.activated.connect(self.add_user_property)
        
        self.shortcutSelApply = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Delete), self)
        self.shortcutSelApply.activated.connect(self.remove_user_property)
        
        self.shortcutSelApply = QShortcut(QKeySequence(Qt.ALT + Qt.Key_R), self)
        self.shortcutSelApply.activated.connect(self.rename_user_property)
        
        #----------------------------------------------------

        self.Splitter = QSplitter(self)
        self.Splitter.addWidget(self.CmpTabBox)
        self.Splitter.addWidget(self.SelectorBox)   
        self.Splitter.addWidget(self.InspectorBox) 
                 
        self.centralWidget().layout().addWidget(self.Splitter)
        
        
        #----------------------------------------------------
        #
        #     Signals and Slots connections
        #
        self.CmpTable.cells_chosen.connect(self.Inspector.load_cmp)
        self.CmpTable.cells_chosen.connect(self.Selector.comp_template_slot)
        self.CmpTable.file_load.connect(self.file_loaded_slot)
        self.CmpTable.cmps_updated.connect(self.Selector.process_comps_slot)
        self.CmpTable.cmps_selected.connect(self.set_status_text_slot)

        self.SelApplyButton.clicked.connect(self.Selector.apply_slot)
        self.SelClearButton.clicked.connect(self.Selector.clear_slot)
        self.SelTemplateButton.clicked.connect(self.Selector.use_comp_as_template_slot)
        
        self.Selector.select_comps_signal.connect(self.CmpTable.select_comps_slot)

        self.Inspector.load_field.connect(self.FieldInspector.load_field_slot)
        self.Inspector.update_comps.connect(self.data_changed_slot)
        self.Inspector.update_comps.connect(self.CmpTable.update_cmp_list_slot)
        self.FieldInspector.data_changed.connect(self.data_changed_slot)
        CmpMgr.file_saved.connect(self.file_saved_slot)
        
        self.CmpTable.mouse_click.connect(self.mouse_change_tool)
        self.Inspector.mouse_click.connect(self.mouse_change_tool)
        self.FieldInspector.mouse_click.connect(self.mouse_change_tool)

        self.Inspector.header().sectionResized.connect(self.FieldInspector.column_resize)
        
        self.AddUserProperty.clicked.connect(self.add_user_property)
        self.DeleteUserProperty.clicked.connect(self.remove_user_property)
        self.RenameUserProperty.clicked.connect(self.rename_user_property)
        
        #----------------------------------------------------
        self.ToolList = []
        self.ToolList.append(self.CmpTable)
        self.ToolList.append(self.Selector)
        self.ToolList.append(self.Inspector)
        self.ToolList.append(self.FieldInspector)
        self.ToolIndex = 0
        
        
        #----------------------------------------------------
        #
        #    Window
        #
        self.setWindowTitle(self.PROGRAM_NAME)
        Settings = QSettings('kicad-tools', 'Schematic Component Manager')
        #print(Settings.allKeys())
        if Settings.contains('geometry'):
            self.restoreGeometry( Settings.value('geometry') )
        else:
            self.setGeometry(100, 100, 1024, 768)

        if Settings.contains('cmptable'):
            w0, w1 = Settings.value('cmptable')
            self.CmpTable.setColumnWidth( 0, int(w0) )
            self.CmpTable.setColumnWidth( 1, int(w1) )
            
        if Settings.contains('selector'):
            w0, w1 = Settings.value('selector')
            self.Selector.setColumnWidth( 0, int(w0) )
            self.Selector.setColumnWidth( 1, int(w1) )
                        
        if Settings.contains('inspector'):
            w0, w1 = Settings.value('inspector')
            self.Inspector.setColumnWidth( 0, int(w0) )
            self.Inspector.setColumnWidth( 1, int(w1) )
            self.FieldInspector.setColumnWidth( 0, int(w0) )
            self.FieldInspector.setColumnWidth( 1, int(w1) )
            #self.Inspector.setColumnWidth( 2, int(w2) )
            
        if Settings.contains('splitter'):
            self.Splitter.restoreState( Settings.value('splitter') )
            
        if Settings.contains('inssplitter'):
            self.InspectorSplit.restoreState( Settings.value('inssplitter') )
            
        #----------------------------------------------------
        #
        #    Process command line arguments
        #
        if len(sys.argv) > 1:
            fname = sys.argv[1]
            if os.path.exists(fname):
                self.CmpTable.load_file(fname)
            else:
                print('E: input file "' + fname + '"does not exist')
            
        self.show()
    #---------------------------------------------------------------------------
    def closeEvent(self, event):
        Settings = QSettings('kicad-tools', 'Schematic Component Manager')
        Settings.setValue( 'geometry', self.saveGeometry() )
        Settings.setValue( 'cmptable',  [self.CmpTable.columnWidth(0), self.CmpTable.columnWidth(1)] )
        Settings.setValue( 'selector',  [self.Selector.columnWidth(0), self.Selector.columnWidth(1)] )
        Settings.setValue( 'inspector', [self.Inspector.columnWidth(0), self.Inspector.columnWidth(1)] )
        Settings.setValue( 'splitter', self.Splitter.saveState() )
        Settings.setValue( 'inssplitter', self.InspectorSplit.saveState() )
        QWidget.closeEvent(self, event)
    #---------------------------------------------------------------------------
    def open_file(self):
        #filename = QFileDialog.getOpenFileName(self, 'Open schematic file', '/opt/cad/kicad', 'KiCad Schematic Files (*.sch)')
        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFile)
        dialog.setNameFilter('KiCad Schematic Files (*.sch)')
        
        filenames = []
        if dialog.exec_():
            filenames = dialog.selectedFiles()
        if len(filenames) == 0:
            return
        
        CmpMgr.set_curr_file_path( filenames[0] )
        self.CmpTable.load_file( filenames[0] )
    #---------------------------------------------------------------------------
    def save_file(self):
        self.FieldInspector.save_fields()
        self.Inspector.save_cmps()
        
        curr_file = CmpMgr.curr_file_path()
        message = 'Save File "' + curr_file + '"'
        print(message)
        self.statusBar().showMessage(message)
        
        CmpMgr.save_file(curr_file)
    #---------------------------------------------------------------------------
    def save_file_as(self):
        self.Inspector.save_cmps()
        self.FieldInspector.save_fields()
        filenames = QFileDialog.getSaveFileName(self, 'Save File As...', '', 'KiCad Schematic Files (*.sch)')
            
        if filenames[0] == '':
            return
            
        print('Save File As "' + filenames[0] + '"')
        CmpMgr.save_file(filenames[0])
        CmpMgr.set_curr_file_path( filenames[0] )
    #---------------------------------------------------------------------------
    def file_loaded_slot(self):
        text = CmpMgr.curr_file_path()
        self.set_title(text)
    #---------------------------------------------------------------------------
    def data_changed_slot(self):
        text = CmpMgr.curr_file_path() + ' *'
        self.set_title(text)
    #---------------------------------------------------------------------------
    def file_saved_slot(self):
        text = CmpMgr.curr_file_path()
        self.set_title(text)
    #---------------------------------------------------------------------------
    def set_title(self, text = ''):
        text = ' - ' + text if len(text) > 0 else ''
        self.setWindowTitle(self.PROGRAM_NAME + ' v' + VERSION + text)
    #---------------------------------------------------------------------------
    def set_status_text_slot(self, text):
        self.statusBar().showMessage(text)
    #---------------------------------------------------------------------------
    def edit_settings(self):
        print('edit settings')
        SettingsDialog = TSettingsDialog(self)
        SettingsDialog.resize(400, 400)
        SettingsDialog.Tabs.setMinimumWidth(800)
        SettingsDialog.show()
    #---------------------------------------------------------------------------
    def show_user_manual_slot(self):
        help = THelpForm(self, 'User\'s Manual', 'main.html')
    #---------------------------------------------------------------------------
    def show_setting_dialog_help_slot(self):
        help = THelpForm(self, 'Settings Dialog', 'settings.html')
    #---------------------------------------------------------------------------
    def show_hotkeys_help_slot(self):
        help = THelpForm(self, 'Hotkeys', 'hotkeys.html')
Beispiel #2
0
class Runner():

    _window = None
    _application = None

    def __init__(self):

        self._application = QApplication(sys.argv)
        self._window = None

        # Main Window Initialized..
        try:
            self._window = yali.gui.YaliWindow.Widget()
        except yali.Error, msg:
            ctx.logger.debug(msg)
            sys.exit(1)

        self._translator = QTranslator()
        self._translator.load(
            "qt_" + QLocale.system().name(),
            QLibraryInfo.location(QLibraryInfo.TranslationsPath))

        ctx.mainScreen = self._window

        screens = self._get_screens(ctx.flags.install_type)
        self._set_steps(screens)

        # These shorcuts for developers :)
        prevScreenShortCut = QShortcut(QKeySequence(Qt.SHIFT + Qt.Key_F1),
                                       self._window)
        nextScreenShortCut = QShortcut(QKeySequence(Qt.SHIFT + Qt.Key_F2),
                                       self._window)
        prevScreenShortCut.activated.connect(self._window.slotBack)
        nextScreenShortCut.activated.connect(self._window.slotNext)

        # VBox utils
        ctx.logger.debug("Starting VirtualBox tools..")
        #FIXME:sh /etc/X11/Xsession.d/98-vboxclient.sh
        yali.util.run_batch("VBoxClient", ["--autoresize"])
        yali.util.run_batch("VBoxClient", ["--clipboard"])

        # Cp Reboot, ShutDown
        yali.util.run_batch("cp", ["/sbin/reboot", "/tmp/reboot"])
        yali.util.run_batch("cp", ["/sbin/shutdown", "/tmp/shutdown"])

        # base connections
        self._application.lastWindowClosed.connect(self._application.quit)
        self._window.signalProcessEvents.connect(
            self._application.processEvents)  #hata olabilir
        self._application.desktop().resized[int].connect(
            self._reinit_screen)  #hata olabilir

        # Font Resize
        fontMinusShortCut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Minus),
                                      self._window)
        fontPlusShortCut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Plus),
                                     self._window)
        fontMinusShortCut.activated.connect(self._window.setFontMinus)
        fontPlusShortCut.activated.connect(self._window.setFontPlus)
Beispiel #3
0
    def setupUi(self, *args):  # {{{
        self.resize(990, 670)

        self.download_shortcut = QShortcut(self)
        self.download_shortcut.setKey(QKeySequence('Ctrl+D',
            QKeySequence.PortableText))
        p = self.parent()
        if hasattr(p, 'keyboard'):
            kname = u'Interface Action: Edit Metadata (Edit Metadata) : menu action : download'
            sc = p.keyboard.keys_map.get(kname, None)
            if sc:
                self.download_shortcut.setKey(sc[0])
        self.swap_title_author_shortcut = s = QShortcut(self)
        s.setKey(QKeySequence('Alt+Down', QKeySequence.PortableText))

        self.button_box = bb = QDialogButtonBox(self)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)
        self.next_button = QPushButton(QIcon(I('forward.png')), _('Next'),
                self)
        self.next_button.setShortcut(QKeySequence('Alt+Right'))
        self.next_button.clicked.connect(self.next_clicked)
        self.prev_button = QPushButton(QIcon(I('back.png')), _('Previous'),
                self)
        self.prev_button.setShortcut(QKeySequence('Alt+Left'))

        self.button_box.addButton(self.prev_button, bb.ActionRole)
        self.button_box.addButton(self.next_button, bb.ActionRole)
        self.prev_button.clicked.connect(self.prev_clicked)
        bb.setStandardButtons(bb.Ok|bb.Cancel)
        bb.button(bb.Ok).setDefault(True)

        self.scroll_area = QScrollArea(self)
        self.scroll_area.setFrameShape(QScrollArea.NoFrame)
        self.scroll_area.setWidgetResizable(True)
        self.central_widget = QTabWidget(self)
        self.scroll_area.setWidget(self.central_widget)

        self.l = QVBoxLayout(self)
        self.setLayout(self.l)
        self.l.addWidget(self.scroll_area)
        ll = self.button_box_layout = QHBoxLayout()
        self.l.addLayout(ll)
        ll.addSpacing(10)
        ll.addWidget(self.button_box)

        self.setWindowIcon(QIcon(I('edit_input.png')))
        self.setWindowTitle(BASE_TITLE)

        self.create_basic_metadata_widgets()

        if len(self.db.custom_column_label_map):
            self.create_custom_metadata_widgets()

        self.do_layout()
        geom = gprefs.get('metasingle_window_geometry3', None)
        if geom is not None:
            self.restoreGeometry(bytes(geom))
Beispiel #4
0
    def setupUi(self, *args):  # {{{
        self.resize(990, 670)

        self.download_shortcut = QShortcut(self)
        self.download_shortcut.setKey(QKeySequence('Ctrl+D',
            QKeySequence.PortableText))
        p = self.parent()
        if hasattr(p, 'keyboard'):
            kname = u'Interface Action: Edit Metadata (Edit Metadata) : menu action : download'
            sc = p.keyboard.keys_map.get(kname, None)
            if sc:
                self.download_shortcut.setKey(sc[0])
        self.swap_title_author_shortcut = s = QShortcut(self)
        s.setKey(QKeySequence('Alt+Down', QKeySequence.PortableText))

        self.button_box = bb = QDialogButtonBox(self)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)
        self.next_button = QPushButton(QIcon(I('forward.png')), _('Next'),
                self)
        self.next_button.setShortcut(QKeySequence('Alt+Right'))
        self.next_button.clicked.connect(self.next_clicked)
        self.prev_button = QPushButton(QIcon(I('back.png')), _('Previous'),
                self)
        self.prev_button.setShortcut(QKeySequence('Alt+Left'))

        self.button_box.addButton(self.prev_button, bb.ActionRole)
        self.button_box.addButton(self.next_button, bb.ActionRole)
        self.prev_button.clicked.connect(self.prev_clicked)
        bb.setStandardButtons(bb.Ok|bb.Cancel)
        bb.button(bb.Ok).setDefault(True)

        self.scroll_area = QScrollArea(self)
        self.scroll_area.setFrameShape(QScrollArea.NoFrame)
        self.scroll_area.setWidgetResizable(True)
        self.central_widget = QTabWidget(self)
        self.scroll_area.setWidget(self.central_widget)

        self.l = QVBoxLayout(self)
        self.setLayout(self.l)
        self.l.addWidget(self.scroll_area)
        ll = self.button_box_layout = QHBoxLayout()
        self.l.addLayout(ll)
        ll.addSpacing(10)
        ll.addWidget(self.button_box)

        self.setWindowIcon(QIcon(I('edit_input.png')))
        self.setWindowTitle(BASE_TITLE)

        self.create_basic_metadata_widgets()

        if len(self.db.custom_column_label_map):
            self.create_custom_metadata_widgets()
        self.comments_edit_state_at_apply = {self.comments:None}

        self.do_layout()
        geom = gprefs.get('metasingle_window_geometry3', None)
        if geom is not None:
            self.restoreGeometry(bytes(geom))
    def initUI(self):
        #self._layout = QHBoxLayout(self)
        self._widget = QWidget(self)
        #self._layout.addWidget(self._widget)
        self._menuBar = QMenuBar(self._widget)

        exitAct = QAction(QIcon('exit.png'), '&Exit', self)
        exitAct.setShortcut('Ctrl+Q')
        exitAct.setStatusTip('Exit application')
        exitAct.triggered.connect(qApp.quit)

        self.statusBar()

        #menubar = self.menuBar()
        menubar = self._menuBar
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(exitAct)

        act = self._menuBar.addAction('test')
        act.setShortcut(QKeySequence('Ctrl+M'))

        def testCb():
            print('hello')

        act.triggered.connect(testCb)
        act.setShortcutContext(Qt.WidgetShortcut)
        print('_menuBar parent', self._menuBar.parent())
        print('act parent', act.parent())
        print('_widget parent', self._widget.parent())
        #act.setParent(self)
        #print(act.parent())
        self.addAction(act)
        # This is important for Qt.WidgetShortcut
        # the Example is focused, and it's menu's act can trigger
        # Qt.WidgetShortcut context action
        #self.setFocus()
        #act.parent().setFocus()
        print('focusWidget', QApplication.focusWidget())

        def cb():
            tt = QApplication.focusWidget()
            print(tt)

        from PyQt5.Qt import QShortcut
        self.short0 = QShortcut(QKeySequence('Ctrl+N'), self)
        self.short0.activated.connect(cb)

        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Simple menu')
        self.show()
Beispiel #6
0
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        self.installEventFilter(self.EventFilter(self))
        
        self.setFocusPolicy(Qt.WheelFocus)
        self.setTabOrder(self.CmpTable,      self.Inspector )
        self.setTabOrder(self.Inspector,     self.Selector)
        self.setTabOrder(self.Selector,      self.FieldInspector)
        #self.setTabOrder(self.FieldInspector, self.CmpTable)

        #----------------------------------------------------
        #
        #   Application Hotkeys
        #
        self.shortcutLeft  = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Left), self)
        self.shortcutRight = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Right), self)
        self.shortcutLeft.setContext(Qt.ApplicationShortcut)
        self.shortcutRight.setContext(Qt.ApplicationShortcut)
        self.shortcutLeft.activated.connect(self.scroll_left)
        self.shortcutRight.activated.connect(self.scroll_right)
Beispiel #7
0
    def __init__(self,
                 title,
                 widget=None,
                 closeButton=True,
                 keySequence=None,
                 isDialog=False,
                 icon=None):
        QDialog.__init__(self, ctx.mainScreen)
        self.setObjectName("dialog")

        self.isDialog = isDialog
        self.layout = QVBoxLayout()
        self.setLayout(self.layout)
        self.wlayout = QHBoxLayout()

        if icon:
            self.setStyleSheet(
                """QDialog QLabel{ margin-left:16px;margin-right:10px}
                                  QDialog#dialog {background-image:url(':/images/%s.png');
                                                  background-repeat:no-repeat;
                                                  background-position: top left; padding-left:500px;} """
                % icon)

        self.windowTitle = windowTitle(self, closeButton)
        self.setTitle(title)
        #self.layout.setMargin(0)
        self.layout.addWidget(self.windowTitle)

        if widget:
            self.addWidget(widget)
            try:
                widget.finished[int].connect(self.reject)
            except:
                pass
            finally:
                try:
                    widget.resizeDialog[int, int].connect(self.resize)
                except:
                    pass

        if closeButton:
            self.windowTitle.pushButton.clicked.connect(self.reject)

        if keySequence:
            shortCut = QShortcut(keySequence, self)
            shortCut.activated.connect(self.reject)

        QMetaObject.connectSlotsByName(self)
        self.resize(10, 10)
    def __init__(self, view, parent=None):
        '''
        @param: view WebView
        @param: parent QWidget
        '''
        super().__init__(parent)
        self._ui = uic.loadUi('mc/webtab/SearchToolBar.ui', self)
        self._view = view  # WebView
        self._findFlags = QWebEnginePage.FindCaseSensitively  # QWebEnginePage.FindFlags
        self._searchRequests = 0

        self._ui.closeButton.clicked.connect(self.close)
        self._ui.lineEdit.textEdited.connect(self.findNext)
        self._ui.next.clicked.connect(self.findNext)
        self._ui.previous.clicked.connect(self.findPrevious)
        self._ui.caseSensitive.clicked.connect(self.caseSensitivityChanged)

        findNextAction = QShortcut(QKeySequence('F3'), self)
        findNextAction.activated.connect(self.findNext)

        findPreviousAction = QShortcut(QKeySequence('Shift+F3'), self)
        findPreviousAction.activated.connect(self.findPrevious)

        parent.installEventFilter(self)
Beispiel #9
0
    def __init__(self):
        super().__init__()

        self.initUI()

        self.installEventFilter(self.EventFilter(self))

        self.setFocusPolicy(Qt.WheelFocus)
        self.setTabOrder(self.CmpTable, self.Inspector)
        self.setTabOrder(self.Inspector, self.Selector)
        self.setTabOrder(self.Selector, self.FieldInspector)
        #self.setTabOrder(self.FieldInspector, self.CmpTable)

        #----------------------------------------------------
        #
        #   Application Hotkeys
        #
        self.shortcutLeft = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Left), self)
        self.shortcutRight = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Right),
                                       self)
        self.shortcutLeft.setContext(Qt.ApplicationShortcut)
        self.shortcutRight.setContext(Qt.ApplicationShortcut)
        self.shortcutLeft.activated.connect(self.scroll_left)
        self.shortcutRight.activated.connect(self.scroll_right)
Beispiel #10
0
    def __init__(self, parent, title, path):
        #super().__init__(parent, Qt.WA_DeleteOnClose )
        super().__init__(parent, Qt.Window)

        self.text_browser = QTextBrowser(self)
        #self.text_browser  = QWebEngineView(self)
        self.back_button = QPushButton('Back', self)
        self.forward_button = QPushButton('Forward', self)
        self.close_button = QPushButton('Close', self)

        self.layout = QVBoxLayout(self)
        self.btn_widget = QWidget(self)
        self.btn_layout = QHBoxLayout(self.btn_widget)
        self.btn_layout.addWidget(self.back_button)
        self.btn_layout.addWidget(self.forward_button)
        self.btn_layout.addStretch(1)
        self.btn_layout.addWidget(self.close_button)

        self.shortcutEscape = QShortcut(QKeySequence(Qt.Key_Escape), self)
        self.shortcutEscape.activated.connect(self.close)

        self.layout.addWidget(self.btn_widget)
        self.layout.addWidget(self.text_browser)

        self.back_button.clicked.connect(self.text_browser.backward)
        self.forward_button.clicked.connect(self.text_browser.forward)
        self.close_button.clicked.connect(self.close)

        self.text_browser.setSearchPaths([os.path.join(resources_path, 'doc')])
        self.text_browser.setSource(QUrl(path))
        #       f = QFont()
        #       f.setPointSize(14)
        #       self.text_browser.setFont(f)

        Settings = QSettings('kicad-tools', 'Schematic Component Manager')

        if Settings.contains('help-window'):
            self.restoreGeometry(Settings.value('help-window'))
            #pos_x, pos_y, width, height = Settings.value('help-window')
        else:
            pos_x, pos_y, width, height = 0, 0, 640, 640
            self.setGeometry(pos_x, pos_y, width, height)

        self.window().setWindowTitle(title)
        self.show()
Beispiel #11
0
    def _setupMenu(self):
        if const.OS_MACOS:
            macMainMenu = None
            if not macMainMenu:
                macMainMenu = MainMenu(self, 0)
                macMainMenu.initMenuBar(QMenuBar(0))
                gVar.app.activeWindowChanged.connect(macMainMenu.setWindow)
            else:
                macMainMenu.setWindow(self)
        else:
            self.setMenuBar(MenuBar(self))
            self._mainMenu = MainMenu(self, self)
            self._mainMenu.initMenuBar(self.menuBar())

        self._mainMenu.initSuperMenu(self._superMenu)

        # Setup other shortcuts
        reloadBypassCacheAction = QShortcut(QKeySequence('Ctrl+F5'), self)
        reloadBypassCacheAction2 = QShortcut(QKeySequence('Ctrl+Shift+R'),
                                             self)
        reloadBypassCacheAction.activated.connect(self.reloadBypassCache)
        reloadBypassCacheAction2.activated.connect(self.reloadBypassCache)

        closeTabAction = QShortcut(QKeySequence('Ctrl+W'), self)
        closeTabAction2 = QShortcut(QKeySequence('Ctrl+F4'), self)

        closeTabAction.activated.connect(self._closeTab)
        closeTabAction2.activated.connect(self._closeTab)

        reloadAction = QShortcut(QKeySequence('Ctrl+R'), self)
        reloadAction.activated.connect(self.reload)

        openLocationAction = QShortcut(QKeySequence('Alt+D'), self)
        openLocationAction.activated.connect(self._openLocation)

        inspectorAction = QShortcut(QKeySequence('F12'), self)
        inspectorAction.activated.connect(self.toggleWebInspector)

        restoreClosedWindow = QShortcut(QKeySequence('Ctrl+Shift+N'), self)
        restoreClosedWindow.activated.connect(
            gVar.app.closedWindowsManager().restoreClosedWindow)
Beispiel #12
0
    def __init__(self, parent):

        #---------------------------------------------------
        super().__init__(parent)
        self.Parent = parent
        #---------------------------------------------------
        Settings = QSettings('kicad-tools', 'Schematic Component Manager')
        if Settings.contains('component-view'):
            CmpViewDict = Settings.value('component-view')
        else:
            CmpViewDict = {
                'C': '$Value, $Footprint',
                'D': '$LibRef',
                'R': '$Value, $Footprint'
            }

        if Settings.contains('component-ignore'):
            IgnoreCmpRefsList = Settings.value('component-ignore')
        else:
            IgnoreCmpRefsList = []

        #---------------------------------------------------
        self.CmpViewTable = self.TCmpViewTable(self, CmpViewDict)
        self.IgnoreCmpList = self.TIgnoreCmpList(self, IgnoreCmpRefsList)
        #---------------------------------------------------
        self.Tabs = QTabWidget(self)
        self.Tabs.addTab(self.CmpViewTable, 'Component View')
        self.Tabs.addTab(self.IgnoreCmpList, 'Ignore Component List')
        #---------------------------------------------------
        self.ButtonBox = QDialogButtonBox(QDialogButtonBox.Ok
                                          | QDialogButtonBox.Cancel)
        self.ButtonBox.accepted.connect(self.save_settings)
        self.ButtonBox.rejected.connect(self.cancel)
        #---------------------------------------------------
        self.Layout = QVBoxLayout(self)
        self.Layout.addWidget(self.Tabs)
        self.Layout.addWidget(self.ButtonBox)
        #---------------------------------------------------
        self.setWindowTitle('Settings')
        self.setModal(True)
        #---------------------------------------------------
        self.shortcutHelp = QShortcut(QKeySequence(Qt.Key_F1), self)
        self.shortcutHelp.activated.connect(self.show_help)
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = None  # Ui::DownloadManager
        self._timer = QBasicTimer()

        self._lastDownloadPath = ''
        self._downloadPath = ''
        self._useNativeDialog = False
        self._isClosing = False
        self._closeOnFinish = False
        self._activeDownloadsCount = 0

        self._useExternalManager = False
        self._externalExecutable = ''
        self._externalArguments = ''

        self._lastDownloadOption = self.NoOption  # DownloadOption

        self._taskbarButton = None  # QPointer<QWinTaskbarButton>

        self._ui = uic.loadUi('mc/downloads/DownloadManager.ui', self)
        self.setWindowFlags(self.windowFlags() ^ Qt.WindowMaximizeButtonHint)
        if const.OS_WIN:
            if QtWin.isCompositionEnabled():  # TODO: ?
                QtWin.extendFrameIntoClientArea(self, -1, -1, -1, -1)
        self._ui.clearButton.setIcon(QIcon.fromTheme('edit-clear'))
        gVar.appTools.centerWidgetOnScreen(self)

        self._ui.clearButton.clicked.connect(self._clearList)

        clearShortcut = QShortcut(QKeySequence('CTRL+L'), self)
        clearShortcut.activated.connect(self._clearList)

        self.loadSettings()

        gVar.appTools.setWmClass('Download Manager', self)
Beispiel #14
0
class MetadataSingleDialogBase(ResizableDialog):

    view_format = pyqtSignal(object, object)
    cc_two_column = tweaks['metadata_single_use_2_cols_for_custom_fields']
    one_line_comments_toolbar = False
    use_toolbutton_for_config_metadata = True

    def __init__(self, db, parent=None):
        self.db = db
        self.changed = set()
        self.books_to_refresh = set()
        self.rows_to_refresh = set()
        self.metadata_before_fetch = None
        ResizableDialog.__init__(self, parent)

    def setupUi(self, *args):  # {{{
        self.resize(990, 670)

        self.download_shortcut = QShortcut(self)
        self.download_shortcut.setKey(
            QKeySequence('Ctrl+D', QKeySequence.PortableText))
        p = self.parent()
        if hasattr(p, 'keyboard'):
            kname = u'Interface Action: Edit Metadata (Edit Metadata) : menu action : download'
            sc = p.keyboard.keys_map.get(kname, None)
            if sc:
                self.download_shortcut.setKey(sc[0])

        self.button_box = bb = QDialogButtonBox(self)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)
        self.next_button = QPushButton(QIcon(I('forward.png')), _('Next'),
                                       self)
        self.next_button.setShortcut(QKeySequence('Alt+Right'))
        self.next_button.clicked.connect(self.next_clicked)
        self.prev_button = QPushButton(QIcon(I('back.png')), _('Previous'),
                                       self)
        self.prev_button.setShortcut(QKeySequence('Alt+Left'))

        self.button_box.addButton(self.prev_button, bb.ActionRole)
        self.button_box.addButton(self.next_button, bb.ActionRole)
        self.prev_button.clicked.connect(self.prev_clicked)
        bb.setStandardButtons(bb.Ok | bb.Cancel)
        bb.button(bb.Ok).setDefault(True)

        self.scroll_area = QScrollArea(self)
        self.scroll_area.setFrameShape(QScrollArea.NoFrame)
        self.scroll_area.setWidgetResizable(True)
        self.central_widget = QTabWidget(self)
        self.scroll_area.setWidget(self.central_widget)

        self.l = QVBoxLayout(self)
        self.setLayout(self.l)
        self.l.addWidget(self.scroll_area)
        ll = self.button_box_layout = QHBoxLayout()
        self.l.addLayout(ll)
        ll.addSpacing(10)
        ll.addWidget(self.button_box)

        self.setWindowIcon(QIcon(I('edit_input.png')))
        self.setWindowTitle(BASE_TITLE)

        self.create_basic_metadata_widgets()

        if len(self.db.custom_column_label_map):
            self.create_custom_metadata_widgets()

        self.do_layout()
        geom = gprefs.get('metasingle_window_geometry3', None)
        if geom is not None:
            self.restoreGeometry(bytes(geom))

    # }}}

    def create_basic_metadata_widgets(self):  # {{{
        self.basic_metadata_widgets = []

        self.languages = LanguagesEdit(self)
        self.basic_metadata_widgets.append(self.languages)

        self.title = TitleEdit(self)
        self.title.textChanged.connect(self.update_window_title)
        self.deduce_title_sort_button = QToolButton(self)
        self.deduce_title_sort_button.setToolTip(
            _('Automatically create the title sort entry based on the current '
              'title entry.\nUsing this button to create title sort will '
              'change title sort from red to green.'))
        self.deduce_title_sort_button.setWhatsThis(
            self.deduce_title_sort_button.toolTip())
        self.title_sort = TitleSortEdit(self, self.title,
                                        self.deduce_title_sort_button,
                                        self.languages)
        self.basic_metadata_widgets.extend([self.title, self.title_sort])

        self.deduce_author_sort_button = b = QToolButton(self)
        b.setToolTip('<p>' + _(
            'Automatically create the author sort entry based on the current '
            'author entry. Using this button to create author sort will '
            'change author sort from red to green.  There is a menu of '
            'functions available under this button. Click and hold '
            'on the button to see it.') + '</p>')
        if isosx:
            # Workaround for https://bugreports.qt-project.org/browse/QTBUG-41017
            class Menu(QMenu):
                def mouseReleaseEvent(self, ev):
                    ac = self.actionAt(ev.pos())
                    if ac is not None:
                        ac.trigger()
                    return QMenu.mouseReleaseEvent(self, ev)

            b.m = m = Menu()
        else:
            b.m = m = QMenu()
        ac = m.addAction(QIcon(I('forward.png')),
                         _('Set author sort from author'))
        ac2 = m.addAction(QIcon(I('back.png')),
                          _('Set author from author sort'))
        ac3 = m.addAction(QIcon(I('user_profile.png')), _('Manage authors'))
        ac4 = m.addAction(QIcon(I('next.png')),
                          _('Copy author to author sort'))
        ac5 = m.addAction(QIcon(I('previous.png')),
                          _('Copy author sort to author'))

        b.setMenu(m)
        self.authors = AuthorsEdit(self, ac3)
        self.author_sort = AuthorSortEdit(self, self.authors, b, self.db, ac,
                                          ac2, ac4, ac5)
        self.basic_metadata_widgets.extend([self.authors, self.author_sort])

        self.swap_title_author_button = QToolButton(self)
        self.swap_title_author_button.setIcon(QIcon(I('swap.png')))
        self.swap_title_author_button.setToolTip(
            _('Swap the author and title'))
        self.swap_title_author_button.clicked.connect(self.swap_title_author)

        self.manage_authors_button = QToolButton(self)
        self.manage_authors_button.setIcon(QIcon(I('user_profile.png')))
        self.manage_authors_button.setToolTip(
            '<p>' + _('Manage authors. Use to rename authors and correct '
                      'individual author\'s sort values') + '</p>')
        self.manage_authors_button.clicked.connect(self.authors.manage_authors)

        self.series = SeriesEdit(self)
        self.clear_series_button = QToolButton(self)
        self.clear_series_button.setToolTip(_('Clear series'))
        self.clear_series_button.clicked.connect(self.series.clear)
        self.series_index = SeriesIndexEdit(self, self.series)
        self.basic_metadata_widgets.extend([self.series, self.series_index])

        self.formats_manager = FormatsManager(self, self.copy_fmt)
        # We want formats changes to be committed before title/author, as
        # otherwise we could have data loss if the title/author changed and the
        # user was trying to add an extra file from the old books directory.
        self.basic_metadata_widgets.insert(0, self.formats_manager)
        self.formats_manager.metadata_from_format_button.clicked.connect(
            self.metadata_from_format)
        self.formats_manager.cover_from_format_button.clicked.connect(
            self.cover_from_format)
        self.cover = Cover(self)
        self.cover.download_cover.connect(self.download_cover)
        self.basic_metadata_widgets.append(self.cover)

        self.comments = CommentsEdit(self, self.one_line_comments_toolbar)
        self.basic_metadata_widgets.append(self.comments)

        self.rating = RatingEdit(self)
        self.clear_ratings_button = QToolButton(self)
        self.clear_ratings_button.setToolTip(_('Clear rating'))
        self.clear_ratings_button.setIcon(QIcon(I('trash.png')))
        self.clear_ratings_button.clicked.connect(self.rating.zero)

        self.basic_metadata_widgets.append(self.rating)

        self.tags = TagsEdit(self)
        self.tags_editor_button = QToolButton(self)
        self.tags_editor_button.setToolTip(_('Open Tag Editor'))
        self.tags_editor_button.setIcon(QIcon(I('chapters.png')))
        self.tags_editor_button.clicked.connect(self.tags_editor)
        self.clear_tags_button = QToolButton(self)
        self.clear_tags_button.setToolTip(_('Clear all tags'))
        self.clear_tags_button.setIcon(QIcon(I('trash.png')))
        self.clear_tags_button.clicked.connect(self.tags.clear)
        self.basic_metadata_widgets.append(self.tags)

        self.identifiers = IdentifiersEdit(self)
        self.basic_metadata_widgets.append(self.identifiers)
        self.clear_identifiers_button = QToolButton(self)
        self.clear_identifiers_button.setIcon(QIcon(I('trash.png')))
        self.clear_identifiers_button.setToolTip(_('Clear Ids'))
        self.clear_identifiers_button.clicked.connect(self.identifiers.clear)
        self.paste_isbn_button = QToolButton(self)
        self.paste_isbn_button.setToolTip(
            '<p>' + _('Paste the contents of the clipboard into the '
                      'identifiers box prefixed with isbn:') + '</p>')
        self.paste_isbn_button.setIcon(QIcon(I('edit-paste.png')))
        self.paste_isbn_button.clicked.connect(self.identifiers.paste_isbn)

        self.publisher = PublisherEdit(self)
        self.basic_metadata_widgets.append(self.publisher)

        self.timestamp = DateEdit(self)
        self.pubdate = PubdateEdit(self)
        self.basic_metadata_widgets.extend([self.timestamp, self.pubdate])

        self.fetch_metadata_button = b = QToolButton(self)
        b.setText(_('&Download metadata')), b.setPopupMode(b.DelayedPopup)
        b.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed))
        self.fetch_metadata_button.clicked.connect(self.fetch_metadata)
        self.fetch_metadata_menu = m = QMenu(self.fetch_metadata_button)
        m.addAction(QIcon(I('edit-undo.png')),
                    _('Undo last metadata download'), self.undo_fetch_metadata)
        self.fetch_metadata_button.setMenu(m)
        self.download_shortcut.activated.connect(
            self.fetch_metadata_button.click)
        font = self.fmb_font = QFont()
        font.setBold(True)
        self.fetch_metadata_button.setFont(font)

        if self.use_toolbutton_for_config_metadata:
            self.config_metadata_button = QToolButton(self)
            self.config_metadata_button.setIcon(QIcon(I('config.png')))
        else:
            self.config_metadata_button = QPushButton(self)
            self.config_metadata_button.setText(
                _('Configure download metadata'))
        self.config_metadata_button.setIcon(QIcon(I('config.png')))
        self.config_metadata_button.clicked.connect(self.configure_metadata)
        self.config_metadata_button.setToolTip(
            _('Change how calibre downloads metadata'))

    # }}}

    def create_custom_metadata_widgets(self):  # {{{
        self.custom_metadata_widgets_parent = w = QWidget(self)
        layout = QGridLayout()
        w.setLayout(layout)
        self.custom_metadata_widgets, self.__cc_spacers = \
            populate_metadata_page(layout, self.db, None, parent=w, bulk=False,
                two_column=self.cc_two_column)
        self.__custom_col_layouts = [layout]

    # }}}

    def set_custom_metadata_tab_order(self, before=None, after=None):  # {{{
        sto = QWidget.setTabOrder
        if getattr(self, 'custom_metadata_widgets', []):
            ans = self.custom_metadata_widgets
            for i in range(len(ans) - 1):
                if before is not None and i == 0:
                    pass
                if len(ans[i + 1].widgets) == 2:
                    sto(ans[i].widgets[-1], ans[i + 1].widgets[1])
                else:
                    sto(ans[i].widgets[-1], ans[i + 1].widgets[0])
                for c in range(2, len(ans[i].widgets), 2):
                    sto(ans[i].widgets[c - 1], ans[i].widgets[c + 1])
            if after is not None:
                pass

    # }}}

    def do_view_format(self, path, fmt):
        if path:
            self.view_format.emit(None, path)
        else:
            self.view_format.emit(self.book_id, fmt)

    def copy_fmt(self, fmt, f):
        self.db.copy_format_to(self.book_id, fmt, f, index_is_id=True)

    def do_layout(self):
        raise NotImplementedError()

    def __call__(self, id_):
        self.book_id = id_
        self.books_to_refresh = set([])
        self.metadata_before_fetch = None
        for widget in self.basic_metadata_widgets:
            widget.initialize(self.db, id_)
        for widget in getattr(self, 'custom_metadata_widgets', []):
            widget.initialize(id_)
        if callable(self.set_current_callback):
            self.set_current_callback(id_)
        # Commented out as it doesn't play nice with Next, Prev buttons
        # self.fetch_metadata_button.setFocus(Qt.OtherFocusReason)

    # Miscellaneous interaction methods {{{
    def update_window_title(self, *args):
        title = self.title.current_val
        if len(title) > 50:
            title = title[:50] + u'\u2026'
        self.setWindowTitle(
            BASE_TITLE + ' - ' + title + ' - ' + _(' [%(num)d of %(tot)d]') %
            dict(num=self.current_row + 1, tot=len(self.row_list)))

    def swap_title_author(self, *args):
        title = self.title.current_val
        self.title.current_val = authors_to_string(self.authors.current_val)
        self.authors.current_val = string_to_authors(title)
        self.title_sort.auto_generate()
        self.author_sort.auto_generate()

    def tags_editor(self, *args):
        self.tags.edit(self.db, self.book_id)

    def metadata_from_format(self, *args):
        mi, ext = self.formats_manager.get_selected_format_metadata(
            self.db, self.book_id)
        if mi is not None:
            self.update_from_mi(mi)

    def get_pdf_cover(self):
        pdfpath = self.formats_manager.get_format_path(self.db, self.book_id,
                                                       'pdf')
        from calibre.gui2.metadata.pdf_covers import PDFCovers
        d = PDFCovers(pdfpath, parent=self)
        if d.exec_() == d.Accepted:
            cpath = d.cover_path
            if cpath:
                with open(cpath, 'rb') as f:
                    self.update_cover(f.read(), 'PDF')
        d.cleanup()

    def cover_from_format(self, *args):
        ext = self.formats_manager.get_selected_format()
        if ext is None:
            return
        if ext == 'pdf':
            return self.get_pdf_cover()
        try:
            mi, ext = self.formats_manager.get_selected_format_metadata(
                self.db, self.book_id)
        except (IOError, OSError) as err:
            if getattr(err, 'errno',
                       None) == errno.EACCES:  # Permission denied
                import traceback
                fname = err.filename if err.filename else 'file'
                error_dialog(self,
                             _('Permission denied'),
                             _('Could not open %s. Is it being used by another'
                               ' program?') % fname,
                             det_msg=traceback.format_exc(),
                             show=True)
                return
            raise
        if mi is None:
            return
        cdata = None
        if mi.cover and os.access(mi.cover, os.R_OK):
            cdata = open(mi.cover).read()
        elif mi.cover_data[1] is not None:
            cdata = mi.cover_data[1]
        if cdata is None:
            error_dialog(self, _('Could not read cover'),
                         _('Could not read cover from %s format') %
                         ext).exec_()
            return
        self.update_cover(cdata, ext)

    def update_cover(self, cdata, fmt):
        orig = self.cover.current_val
        self.cover.current_val = cdata
        if self.cover.current_val is None:
            self.cover.current_val = orig
            return error_dialog(self,
                                _('Could not read cover'),
                                _('The cover in the %s format is invalid') %
                                fmt,
                                show=True)
            return

    def update_from_mi(self,
                       mi,
                       update_sorts=True,
                       merge_tags=True,
                       merge_comments=False):
        fw = self.focusWidget()
        if not mi.is_null('title'):
            self.title.set_value(mi.title)
            if update_sorts:
                self.title_sort.auto_generate()
        if not mi.is_null('authors'):
            self.authors.set_value(mi.authors)
        if not mi.is_null('author_sort'):
            self.author_sort.set_value(mi.author_sort)
        elif update_sorts:
            self.author_sort.auto_generate()
        if not mi.is_null('rating'):
            try:
                self.rating.set_value(mi.rating)
            except:
                pass
        if not mi.is_null('publisher'):
            self.publisher.set_value(mi.publisher)
        if not mi.is_null('tags'):
            old_tags = self.tags.current_val
            tags = mi.tags if mi.tags else []
            if old_tags and merge_tags:
                ltags, lotags = {t.lower()
                                 for t in tags}, {t.lower()
                                                  for t in old_tags}
                tags = [t for t in tags if t.lower() in ltags - lotags
                        ] + old_tags
            self.tags.set_value(tags)
        if not mi.is_null('identifiers'):
            current = self.identifiers.current_val
            current.update(mi.identifiers)
            self.identifiers.set_value(current)
        if not mi.is_null('pubdate'):
            self.pubdate.set_value(mi.pubdate)
        if not mi.is_null('series') and mi.series.strip():
            self.series.set_value(mi.series)
            if mi.series_index is not None:
                self.series_index.reset_original()
                self.series_index.set_value(float(mi.series_index))
        if not mi.is_null('languages'):
            langs = [canonicalize_lang(x) for x in mi.languages]
            langs = [x for x in langs if x is not None]
            if langs:
                self.languages.set_value(langs)
        if mi.comments and mi.comments.strip():
            val = mi.comments
            if val and merge_comments:
                cval = self.comments.current_val
                if cval:
                    val = merge_two_comments(cval, val)
            self.comments.set_value(val)
        if fw is not None:
            fw.setFocus(Qt.OtherFocusReason)

    def fetch_metadata(self, *args):
        d = FullFetch(self.cover.pixmap(), self)
        ret = d.start(title=self.title.current_val,
                      authors=self.authors.current_val,
                      identifiers=self.identifiers.current_val)
        if ret == d.Accepted:
            self.metadata_before_fetch = {
                f: getattr(self, f).current_val
                for f in fetched_fields
            }
            from calibre.ebooks.metadata.sources.prefs import msprefs
            mi = d.book
            dummy = Metadata(_('Unknown'))
            for f in msprefs['ignore_fields']:
                if ':' not in f:
                    setattr(mi, f, getattr(dummy, f))
            if mi is not None:
                pd = mi.pubdate
                if pd is not None:
                    # Put the downloaded published date into the local timezone
                    # as we discard time info and the date is timezone
                    # invariant. This prevents the as_local_timezone() call in
                    # update_from_mi from changing the pubdate
                    mi.pubdate = datetime(pd.year,
                                          pd.month,
                                          pd.day,
                                          tzinfo=local_tz)
                self.update_from_mi(mi,
                                    merge_comments=msprefs['append_comments'])
            if d.cover_pixmap is not None:
                self.metadata_before_fetch['cover'] = self.cover.current_val
                self.cover.current_val = pixmap_to_data(d.cover_pixmap)

    def undo_fetch_metadata(self):
        if self.metadata_before_fetch is None:
            return error_dialog(self,
                                _('No downloaded metadata'),
                                _('There is no downloaded metadata to undo'),
                                show=True)
        for field, val in self.metadata_before_fetch.iteritems():
            getattr(self, field).current_val = val
        self.metadata_before_fetch = None

    def configure_metadata(self):
        from calibre.gui2.preferences import show_config_widget
        gui = self.parent()
        show_config_widget('Sharing',
                           'Metadata download',
                           parent=self,
                           gui=gui,
                           never_shutdown=True)

    def download_cover(self, *args):
        from calibre.gui2.metadata.single_download import CoverFetch
        d = CoverFetch(self.cover.pixmap(), self)
        ret = d.start(self.title.current_val, self.authors.current_val,
                      self.identifiers.current_val)
        if ret == d.Accepted:
            if d.cover_pixmap is not None:
                self.cover.current_val = pixmap_to_data(d.cover_pixmap)

    # }}}

    def to_book_metadata(self):
        mi = Metadata(_('Unknown'))
        if self.db is None:
            return mi
        mi.set_all_user_metadata(
            self.db.field_metadata.custom_field_metadata())
        for widget in self.basic_metadata_widgets:
            widget.apply_to_metadata(mi)
        for widget in getattr(self, 'custom_metadata_widgets', []):
            widget.apply_to_metadata(mi)
        return mi

    def apply_changes(self):
        self.changed.add(self.book_id)
        if self.db is None:
            # break_cycles has already been called, don't know why this should
            # happen but a user reported it
            return True
        for widget in self.basic_metadata_widgets:
            try:
                if hasattr(widget, 'validate_for_commit'):
                    title, msg, det_msg = widget.validate_for_commit()
                    if title is not None:
                        error_dialog(self,
                                     title,
                                     msg,
                                     det_msg=det_msg,
                                     show=True)
                        return False
                widget.commit(self.db, self.book_id)
                self.books_to_refresh |= getattr(widget, 'books_to_refresh',
                                                 set())
            except (IOError, OSError) as err:
                if getattr(err, 'errno',
                           None) == errno.EACCES:  # Permission denied
                    import traceback
                    fname = getattr(err, 'filename', None)
                    p = 'Locked file: %s\n\n' % fname if fname else ''
                    error_dialog(
                        self,
                        _('Permission denied'),
                        _('Could not change the on disk location of this'
                          ' book. Is it open in another program?'),
                        det_msg=p + traceback.format_exc(),
                        show=True)
                    return False
                raise
        for widget in getattr(self, 'custom_metadata_widgets', []):
            self.books_to_refresh |= widget.commit(self.book_id)

        self.db.commit()
        rows = self.db.refresh_ids(list(self.books_to_refresh))
        if rows:
            self.rows_to_refresh |= set(rows)

        return True

    def accept(self):
        self.save_state()
        if not self.apply_changes():
            return
        ResizableDialog.accept(self)

    def reject(self):
        self.save_state()
        ResizableDialog.reject(self)

    def save_state(self):
        try:
            gprefs['metasingle_window_geometry3'] = bytearray(
                self.saveGeometry())
        except:
            # Weird failure, see https://bugs.launchpad.net/bugs/995271
            import traceback
            traceback.print_exc()

    # Dialog use methods {{{
    def start(self,
              row_list,
              current_row,
              view_slot=None,
              set_current_callback=None):
        self.row_list = row_list
        self.current_row = current_row
        if view_slot is not None:
            self.view_format.connect(view_slot)
        self.set_current_callback = set_current_callback
        self.do_one(apply_changes=False)
        ret = self.exec_()
        self.break_cycles()
        return ret

    def next_clicked(self):
        if not self.apply_changes():
            return
        self.do_one(delta=1, apply_changes=False)

    def prev_clicked(self):
        if not self.apply_changes():
            return
        self.do_one(delta=-1, apply_changes=False)

    def do_one(self, delta=0, apply_changes=True):
        if apply_changes:
            self.apply_changes()
        self.current_row += delta
        prev = next_ = None
        if self.current_row > 0:
            prev = self.db.title(self.row_list[self.current_row - 1])
        if self.current_row < len(self.row_list) - 1:
            next_ = self.db.title(self.row_list[self.current_row + 1])

        if next_ is not None:
            tip = (_('Save changes and edit the metadata of %s') +
                   ' [Alt+Right]') % next_
            self.next_button.setToolTip(tip)
        self.next_button.setEnabled(next_ is not None)
        if prev is not None:
            tip = (_('Save changes and edit the metadata of %s') +
                   ' [Alt+Left]') % prev
            self.prev_button.setToolTip(tip)
        self.prev_button.setEnabled(prev is not None)
        self.button_box.button(self.button_box.Ok).setDefault(True)
        self.button_box.button(self.button_box.Ok).setFocus(
            Qt.OtherFocusReason)
        self(self.db.id(self.row_list[self.current_row]))

    def break_cycles(self):
        # Break any reference cycles that could prevent python
        # from garbage collecting this dialog
        self.set_current_callback = self.db = None
        self.metadata_before_fetch = None

        def disconnect(signal):
            try:
                signal.disconnect()
            except:
                pass  # Fails if view format was never connected

        disconnect(self.view_format)
        for b in ('next_button', 'prev_button'):
            x = getattr(self, b, None)
            if x is not None:
                disconnect(x.clicked)
        for widget in self.basic_metadata_widgets:
            bc = getattr(widget, 'break_cycles', None)
            if bc is not None and callable(bc):
                bc()
        for widget in getattr(self, 'custom_metadata_widgets', []):
            widget.break_cycles()
Beispiel #15
0
    def __init_shortcuts(self):
        self.__keyF11 = QShortcut(self)
        self.__keyF11.setKey(Qt.Key_F11)
        self.__keyF11.activated.connect(self.__action_full_screen)

        self.__keyCtrlQ = QShortcut(self)
        self.__keyCtrlQ.setKey(Qt.CTRL + Qt.Key_Q)
        self.__keyCtrlQ.activated.connect(self.__action_quit)

        self.__keyCtrlH = QShortcut(self)
        self.__keyCtrlH.setKey(Qt.CTRL + Qt.Key_H)
        self.__keyCtrlH.activated.connect(self.__action_home)

        self.__keyCtrlR = QShortcut(self)
        self.__keyCtrlR.setKey(Qt.CTRL + Qt.Key_R)
        self.__keyCtrlR.activated.connect(self.__action_reload)

        self.__keyF5 = QShortcut(self)
        self.__keyF5.setKey(Qt.Key_F5)
        self.__keyF5.activated.connect(self.__action_reload)

        self.__keyAltLeft = QShortcut(self)
        self.__keyAltLeft.setKey(Qt.ALT + Qt.Key_Left)
        self.__keyAltLeft.activated.connect(self.__action_back)
    def __init__(self, parent=None):
        '''
        @param parent QWidget
        '''
        super().__init__(parent)
        self._ui = uic.loadUi('mc/cookies/CookieManager.ui', self)

        self._domainHash = {}  # QHash<QString, QTreeWidgetItem>
        self._itemHash = {}  # QHash<QTreeWidgetItem, QNetworkCookie>

        self.setAttribute(Qt.WA_DeleteOnClose)

        gVar.appTools.centerWidgetOnScreen(self)

        if self.isRightToLeft():
            self._ui.cookieTree.headerItem().setTextAlignment(
                0, Qt.AlignRight | Qt.AlignVCenter)
            self._ui.cookieTree.headerItem().setTextAlignment(
                1, Qt.AlignRight | Qt.AlignVCenter)
            self._ui.cookieTree.setLayoutDirection(Qt.LeftToRight)
            self._ui.whiteList.setLayoutDirection(Qt.LeftToRight)
            self._ui.blackList.setLayoutDirection(Qt.LeftToRight)

        # Stored Cookies
        self._ui.cookieTree.currentItemChanged.connect(
            self._currentItemChanged)
        self._ui.removeAll.clicked.connect(self._removeAll)
        self._ui.removeOne.clicked.connect(self._remove)
        self._ui.close.clicked.connect(lambda: self._close())
        self._ui.close2.clicked.connect(lambda: self._close())
        self._ui.close3.clicked.connect(lambda: self._close())
        self._ui.search.textChanged.connect(self._filterString)

        # Cookie Filtering
        self._ui.whiteAdd.clicked.connect(self._addWhitelist)
        self._ui.whiteRemove.clicked.connect(self._removeWhitelist)
        self._ui.blackAdd.clicked.connect(self._addBlacklist)
        self._ui.blackRemove.clicked.connect(self._removeBlacklist)

        # Cookie Settings
        settings = Settings()
        settings.beginGroup('Cookie-Settings')
        self._ui.saveCookies.setChecked(settings.value('allCookies', True))
        self._ui.filter3rdParty.setChecked(
            settings.value('filterThirdPartyCookies', False))
        self._ui.filterTracking.setChecked(
            settings.value('filterTrackingCookie', False))
        self._ui.deleteCookiesOnClose.setChecked(
            settings.value('deleteCookiesOnClose', False))
        self._ui.whiteList.addItems(settings.value('whitelist', []))
        self._ui.blackList.addItems(settings.value('blacklist', []))
        settings.endGroup()

        if const.QTWEBENGINEWIDGETS_VERSION < const.QT_VERSION_CHECK(5, 11, 0):
            self._ui.filter3rdParty.hide()

        self._ui.search.setPlaceholderText(_('Search'))
        self._ui.cookieTree.setDefaultItemShowMode(TreeWidget.ItemsCollapsed)
        self._ui.cookieTree.sortItems(0, Qt.AscendingOrder)
        self._ui.cookieTree.header().setDefaultSectionSize(220)
        self._ui.cookieTree.setFocus()

        self._ui.whiteList.setSortingEnabled(True)
        self._ui.blackList.setSortingEnabled(True)

        self._removeShortcut = QShortcut(QKeySequence('Del'), self)
        self._removeShortcut.activated.connect(self._deletePressed)

        self._ui.search.textChanged.connect(self._filterString)
        cookieJar = gVar.app.cookieJar()
        cookieJar.cookieAdded.connect(self._addCookie)
        cookieJar.cookieRemoved.connect(self._removeCookie)

        # Load cookies
        for cookie in cookieJar.getAllCookies():
            self._addCookie(cookie)

        gVar.appTools.setWmClass('Cookies', self)
Beispiel #17
0
def set_shortcuts(lista, context=Qt.WidgetWithChildrenShortcut):
    """ Creates QShortcuts from a list of (key, owner, callback) 3-tuples

    """
    for (shortcut, owner, callback) in lista:
        QShortcut(shortcut, owner, callback).setContext(context)
Beispiel #18
0
    def initUI(self):

        #----------------------------------------------------
        #
        #    Main Window
        #
        work_zone = QWidget(self)
        Layout = QHBoxLayout(work_zone)
        self.setCentralWidget(work_zone)

        openAction = QAction(QIcon(os.path.join(resources_path, 'open24.png')),
                             'Open', self)
        openAction.setShortcut('Ctrl+O')
        openAction.setStatusTip('Open Schematic File')
        openAction.triggered.connect(self.open_file)

        saveAction = QAction(QIcon(os.path.join(resources_path, 'save24.png')),
                             'Save', self)
        saveAction.setShortcut('Ctrl+S')
        saveAction.setStatusTip('Save Schematic File')
        saveAction.triggered.connect(self.save_file)

        saveAsAction = QAction(
            QIcon(os.path.join(resources_path, 'save-as24.png')), 'Save As...',
            self)
        saveAsAction.setShortcut('Ctrl+Shift+S')
        saveAsAction.setStatusTip('Save Schematic File As...')
        saveAsAction.triggered.connect(self.save_file_as)

        exitAction = QAction(QIcon(os.path.join(resources_path, 'exit24.png')),
                             'Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)

        settingsAction = QAction(
            QIcon(os.path.join(resources_path, 'settings24.png')), 'Settings',
            self)
        settingsAction.setShortcut('Ctrl+Alt+S')
        settingsAction.setStatusTip('Edit settings')
        settingsAction.triggered.connect(self.edit_settings)

        helpAction = QAction(
            QIcon(os.path.join(resources_path, 'help_book24.png')),
            'User\'s Manual', self)
        helpAction.setShortcut('F1')
        helpAction.setStatusTip('User\'s Manual')
        helpAction.triggered.connect(self.show_user_manual_slot)

        helpSDAction = QAction(
            QIcon(os.path.join(resources_path, 'gear24.png')),
            'Settings Dialog', self)
        helpSDAction.setShortcut('Ctrl+F1')
        helpSDAction.setStatusTip('Settings Dialog Help')
        helpSDAction.triggered.connect(self.show_setting_dialog_help_slot)

        helpHKAction = QAction(
            QIcon(os.path.join(resources_path, 'rocket24.png')), 'Hotkeys',
            self)
        helpHKAction.setShortcut('Shift+F1')
        helpHKAction.setStatusTip('Hotkeys Help')
        helpHKAction.triggered.connect(self.show_hotkeys_help_slot)

        self.statusBar().showMessage('Ready')

        #--------------------------------------------
        #
        #    Main Menu
        #
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(openAction)
        fileMenu.addAction(saveAction)
        fileMenu.addAction(saveAsAction)
        fileMenu.addAction(exitAction)

        #--------------------------------------------
        #
        #    Options Menu
        #
        optionsMenu = menubar.addMenu('&Options')
        optionsMenu.addAction(settingsAction)

        #--------------------------------------------
        #
        #    Help Menu
        #
        helpMenu = menubar.addMenu('&Help')
        helpMenu.addAction(helpAction)
        helpMenu.addAction(helpSDAction)
        helpMenu.addAction(helpHKAction)

        #--------------------------------------------
        #
        #    Toolbar
        #
        toolbar = self.addToolBar('Exit')
        toolbar.addAction(exitAction)
        toolbar.addAction(openAction)
        toolbar.addAction(saveAction)
        toolbar.addAction(saveAsAction)
        toolbar.addAction(settingsAction)
        toolbar.addAction(helpAction)

        #----------------------------------------------------
        #
        #    Settings Dialog
        #

        #----------------------------------------------------
        #
        #    Components Table
        #
        self.CmpTabBox = QGroupBox('Components', self)
        self.CmpTabLayout = QVBoxLayout(self.CmpTabBox)
        self.CmpTabLayout.setContentsMargins(4, 10, 4, 4)
        self.CmpTabLayout.setSpacing(10)

        self.CmpTabLayout.setSizeConstraint(QVBoxLayout.SetMaximumSize)

        self.CmpTable = ComponentsTable(self)
        #self.CmpChooseButton = QPushButton('Choose', self)

        self.CmpTabLayout.addWidget(self.CmpTable)
        #self.CmpTabLayout.addWidget(self.CmpChooseButton)

        #----------------------------------------------------
        #
        #    Selector
        #
        self.SelectorBox = QGroupBox('Selector', self)
        self.SelectorLayout = QVBoxLayout(self.SelectorBox)
        self.SelectorLayout.setContentsMargins(4, 10, 4, 4)
        self.SelectorLayout.setSpacing(2)

        self.SelectorBtnWidget = QWidget(self)
        self.SelectorBtnLayout = QHBoxLayout(self.SelectorBtnWidget)
        self.SelectorBtnLayout.setContentsMargins(4, 10, 4, 4)
        self.SelectorBtnLayout.setSpacing(10)

        self.Selector = Selector(self)

        self.SelApplyButton = QPushButton('Apply', self)
        self.SelApplyButton.setToolTip(
            'Alt+S: Apply selection patterns to components')

        self.SelClearButton = QPushButton('Clear', self)
        self.SelClearButton.setToolTip('Alt+C: Clear selection patterns')

        self.SelTemplateButton = QPushButton('Use Component', self)
        self.SelTemplateButton.setToolTip(
            'Alt+T: Use Selected Component As Template')

        self.SelectorLayout.addWidget(self.Selector)
        self.SelectorBtnLayout.addWidget(self.SelTemplateButton)
        self.SelectorBtnLayout.addWidget(self.SelApplyButton)
        self.SelectorBtnLayout.addWidget(self.SelClearButton)
        self.SelectorLayout.addWidget(self.SelectorBtnWidget)

        self.shortcutSelApply = QShortcut(QKeySequence(Qt.ALT + Qt.Key_S),
                                          self)
        self.shortcutSelApply.activated.connect(self.Selector.apply_slot)

        self.shortcutSelClear = QShortcut(QKeySequence(Qt.ALT + Qt.Key_C),
                                          self)
        self.shortcutSelClear.activated.connect(self.Selector.clear_slot)

        self.shortcutSelTemplate = QShortcut(QKeySequence(Qt.ALT + Qt.Key_T),
                                             self)
        self.shortcutSelTemplate.activated.connect(
            self.Selector.use_comp_as_template_slot)

        #----------------------------------------------------
        #
        #    Inspector
        #
        self.Inspector = Inspector(self)
        self.FieldInspector = FieldInspector(self)

        self.InspectorBtnWidget = QWidget(self)
        self.InspectorBtnLayout = QHBoxLayout(self.InspectorBtnWidget)
        self.InspectorBtnLayout.setContentsMargins(4, 10, 4, 4)
        self.InspectorBtnLayout.setSpacing(10)

        self.AddUserProperty = QPushButton('Add Property', self)
        self.AddUserProperty.setToolTip('Alt+A: Add new user property')
        self.DeleteUserProperty = QPushButton('Delete Property', self)
        self.DeleteUserProperty.setToolTip('Alt+Delete: Delete user property')
        self.RenameUserProperty = QPushButton('Rename Property', self)
        self.RenameUserProperty.setToolTip('Alt+R: Rename user property')

        self.InspectorBox = QGroupBox('Inspector', self)
        self.InspectorSplit = QSplitter(Qt.Vertical, self)
        self.InspectorLayout = QVBoxLayout(self.InspectorBox)
        self.InspectorLayout.setContentsMargins(4, 10, 4, 4)
        self.InspectorLayout.setSpacing(2)

        self.InspectorSplit.addWidget(self.Inspector)
        self.InspectorSplit.addWidget(self.FieldInspector)
        self.InspectorLayout.addWidget(self.InspectorSplit)

        self.InspectorBtnLayout.addWidget(self.AddUserProperty)
        self.InspectorBtnLayout.addWidget(self.DeleteUserProperty)
        self.InspectorBtnLayout.addWidget(self.RenameUserProperty)

        self.InspectorLayout.addWidget(self.InspectorBtnWidget)

        self.shortcutSelApply = QShortcut(QKeySequence(Qt.ALT + Qt.Key_A),
                                          self)
        self.shortcutSelApply.activated.connect(self.add_user_property)

        self.shortcutSelApply = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Delete),
                                          self)
        self.shortcutSelApply.activated.connect(self.remove_user_property)

        self.shortcutSelApply = QShortcut(QKeySequence(Qt.ALT + Qt.Key_R),
                                          self)
        self.shortcutSelApply.activated.connect(self.rename_user_property)

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

        self.Splitter = QSplitter(self)
        self.Splitter.addWidget(self.CmpTabBox)
        self.Splitter.addWidget(self.SelectorBox)
        self.Splitter.addWidget(self.InspectorBox)

        self.centralWidget().layout().addWidget(self.Splitter)

        #----------------------------------------------------
        #
        #     Signals and Slots connections
        #
        self.CmpTable.cells_chosen.connect(self.Inspector.load_cmp)
        self.CmpTable.cells_chosen.connect(self.Selector.comp_template_slot)
        self.CmpTable.file_load.connect(self.file_loaded_slot)
        self.CmpTable.cmps_updated.connect(self.Selector.process_comps_slot)
        self.CmpTable.cmps_selected.connect(self.set_status_text_slot)

        self.SelApplyButton.clicked.connect(self.Selector.apply_slot)
        self.SelClearButton.clicked.connect(self.Selector.clear_slot)
        self.SelTemplateButton.clicked.connect(
            self.Selector.use_comp_as_template_slot)

        self.Selector.select_comps_signal.connect(
            self.CmpTable.select_comps_slot)

        self.Inspector.load_field.connect(self.FieldInspector.load_field_slot)
        self.Inspector.update_comps.connect(self.data_changed_slot)
        self.Inspector.update_comps.connect(self.CmpTable.update_cmp_list_slot)
        self.FieldInspector.data_changed.connect(self.data_changed_slot)
        CmpMgr.file_saved.connect(self.file_saved_slot)

        self.CmpTable.mouse_click.connect(self.mouse_change_tool)
        self.Inspector.mouse_click.connect(self.mouse_change_tool)
        self.FieldInspector.mouse_click.connect(self.mouse_change_tool)

        self.Inspector.header().sectionResized.connect(
            self.FieldInspector.column_resize)

        self.AddUserProperty.clicked.connect(self.add_user_property)
        self.DeleteUserProperty.clicked.connect(self.remove_user_property)
        self.RenameUserProperty.clicked.connect(self.rename_user_property)

        #----------------------------------------------------
        self.ToolList = []
        self.ToolList.append(self.CmpTable)
        self.ToolList.append(self.Selector)
        self.ToolList.append(self.Inspector)
        self.ToolList.append(self.FieldInspector)
        self.ToolIndex = 0

        #----------------------------------------------------
        #
        #    Window
        #
        self.setWindowTitle(self.PROGRAM_NAME)
        Settings = QSettings('kicad-tools', 'Schematic Component Manager')
        #print(Settings.allKeys())
        if Settings.contains('geometry'):
            self.restoreGeometry(Settings.value('geometry'))
        else:
            self.setGeometry(100, 100, 1024, 768)

        if Settings.contains('cmptable'):
            w0, w1 = Settings.value('cmptable')
            self.CmpTable.setColumnWidth(0, int(w0))
            self.CmpTable.setColumnWidth(1, int(w1))

        if Settings.contains('selector'):
            w0, w1 = Settings.value('selector')
            self.Selector.setColumnWidth(0, int(w0))
            self.Selector.setColumnWidth(1, int(w1))

        if Settings.contains('inspector'):
            w0, w1 = Settings.value('inspector')
            self.Inspector.setColumnWidth(0, int(w0))
            self.Inspector.setColumnWidth(1, int(w1))
            self.FieldInspector.setColumnWidth(0, int(w0))
            self.FieldInspector.setColumnWidth(1, int(w1))
            #self.Inspector.setColumnWidth( 2, int(w2) )

        if Settings.contains('splitter'):
            self.Splitter.restoreState(Settings.value('splitter'))

        if Settings.contains('inssplitter'):
            self.InspectorSplit.restoreState(Settings.value('inssplitter'))

        #----------------------------------------------------
        #
        #    Process command line arguments
        #
        if len(sys.argv) > 1:
            fname = sys.argv[1]
            if os.path.exists(fname):
                self.CmpTable.load_file(fname)
            else:
                print('E: input file "' + fname + '"does not exist')

        self.show()
Beispiel #19
0
    def __init__(self, parent):
        QWidget.__init__(self, parent)
        self.parent = parent
        self._layout = QVBoxLayout()
        self.setLayout(self._layout)
        self._layout.setContentsMargins(0, 0, 0, 0)

        # Set up the find box & button
        search_layout = QHBoxLayout()
        self._layout.addLayout(search_layout)
        self.item_search = HistoryLineEdit(parent)
        self.item_search.setMinimumContentsLength(5)
        self.item_search.setSizeAdjustPolicy(
            self.item_search.AdjustToMinimumContentsLengthWithIcon)
        try:
            self.item_search.lineEdit().setPlaceholderText(
                _('Find item in tag browser'))
        except:
            pass  # Using Qt < 4.7
        self.item_search.setToolTip(
            _('Search for items. This is a "contains" search; items containing the\n'
              'text anywhere in the name will be found. You can limit the search\n'
              'to particular categories using syntax similar to search. For example,\n'
              'tags:foo will find foo in any tag, but not in authors etc. Entering\n'
              '*foo will filter all categories at once, showing only those items\n'
              'containing the text "foo"'))
        search_layout.addWidget(self.item_search)
        # Not sure if the shortcut should be translatable ...
        sc = QShortcut(QKeySequence(_('ALT+f')), parent)
        sc.activated.connect(self.set_focus_to_find_box)

        self.search_button = QToolButton()
        self.search_button.setText(_('F&ind'))
        self.search_button.setToolTip(_('Find the first/next matching item'))
        search_layout.addWidget(self.search_button)

        self.expand_button = QToolButton()
        self.expand_button.setText('-')
        self.expand_button.setToolTip(_('Collapse all categories'))
        search_layout.addWidget(self.expand_button)
        search_layout.setStretch(0, 10)
        search_layout.setStretch(1, 1)
        search_layout.setStretch(2, 1)

        self.current_find_position = None
        self.search_button.clicked.connect(self.find)
        self.item_search.initialize('tag_browser_search')
        self.item_search.lineEdit().returnPressed.connect(self.do_find)
        self.item_search.lineEdit().textEdited.connect(self.find_text_changed)
        self.item_search.activated[str].connect(self.do_find)
        self.item_search.completer().setCaseSensitivity(Qt.CaseSensitive)

        parent.tags_view = TagsView(parent)
        self.tags_view = parent.tags_view
        self.expand_button.clicked.connect(self.tags_view.collapseAll)
        self._layout.addWidget(parent.tags_view)

        # Now the floating 'not found' box
        l = QLabel(self.tags_view)
        self.not_found_label = l
        l.setFrameStyle(QFrame.StyledPanel)
        l.setAutoFillBackground(True)
        l.setText(
            '<p><b>' +
            _('No More Matches.</b><p> Click Find again to go to first match'))
        l.setAlignment(Qt.AlignVCenter)
        l.setWordWrap(True)
        l.resize(l.sizeHint())
        l.move(10, 20)
        l.setVisible(False)
        self.not_found_label_timer = QTimer()
        self.not_found_label_timer.setSingleShot(True)
        self.not_found_label_timer.timeout.connect(
            self.not_found_label_timer_event, type=Qt.QueuedConnection)

        parent.alter_tb = l = QPushButton(parent)
        l.setText(_('Alter Tag Browser'))
        l.setIcon(QIcon(I('tags.png')))
        l.m = QMenu()
        l.setMenu(l.m)
        self._layout.addWidget(l)

        sb = l.m.addAction(_('Sort by'))
        sb.m = l.sort_menu = QMenu(l.m)
        sb.setMenu(sb.m)
        sb.bg = QActionGroup(sb)

        # Must be in the same order as db2.CATEGORY_SORTS
        for i, x in enumerate((_('Sort by name'), _('Sort by number of books'),
                               _('Sort by average rating'))):
            a = sb.m.addAction(x)
            sb.bg.addAction(a)
            a.setCheckable(True)
            if i == 0:
                a.setChecked(True)
        sb.setToolTip(_('Set the sort order for entries in the Tag Browser'))
        sb.setStatusTip(sb.toolTip())

        ma = l.m.addAction(_('Search type when selecting multiple items'))
        ma.m = l.match_menu = QMenu(l.m)
        ma.setMenu(ma.m)
        ma.ag = QActionGroup(ma)

        # Must be in the same order as db2.MATCH_TYPE
        for i, x in enumerate(
            (_('Match any of the items'), _('Match all of the items'))):
            a = ma.m.addAction(x)
            ma.ag.addAction(a)
            a.setCheckable(True)
            if i == 0:
                a.setChecked(True)
        ma.setToolTip(
            _('When selecting multiple entries in the Tag Browser '
              'match any or all of them'))
        ma.setStatusTip(ma.toolTip())

        mt = l.m.addAction(_('Manage authors, tags, etc.'))
        mt.setToolTip(
            _('All of these category_managers are available by right-clicking '
              'on items in the tag browser above'))
        mt.m = l.manage_menu = QMenu(l.m)
        mt.setMenu(mt.m)
Beispiel #20
0
class BookInfo(QDialog):

    closed = pyqtSignal(object)

    def __init__(self, parent, view, row, link_delegate):
        QDialog.__init__(self, parent)
        self.normal_brush = QBrush(Qt.white)
        self.marked_brush = QBrush(Qt.lightGray)
        self.marked = None
        self.gui = parent
        self.splitter = QSplitter(self)
        self._l = l = QVBoxLayout(self)
        self.setLayout(l)
        l.addWidget(self.splitter)

        self.cover = CoverView(self)
        self.cover.resizeEvent = self.cover_view_resized
        self.cover.cover_changed.connect(self.cover_changed)
        self.cover_pixmap = None
        self.cover.sizeHint = self.details_size_hint
        self.splitter.addWidget(self.cover)

        self.details = Details(parent.book_details.book_info, self)
        self.details.page().setLinkDelegationPolicy(self.details.page().DelegateAllLinks)
        self.details.linkClicked.connect(self.link_clicked)
        s = self.details.page().settings()
        s.setAttribute(s.JavascriptEnabled, False)
        self.css = css()
        self.link_delegate = link_delegate
        self.details.setAttribute(Qt.WA_OpaquePaintEvent, False)
        palette = self.details.palette()
        self.details.setAcceptDrops(False)
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.details.page().setPalette(palette)

        self.c = QWidget(self)
        self.c.l = l2 = QGridLayout(self.c)
        self.c.setLayout(l2)
        l2.addWidget(self.details, 0, 0, 1, -1)
        self.splitter.addWidget(self.c)

        self.fit_cover = QCheckBox(_('Fit &cover within view'), self)
        self.fit_cover.setChecked(gprefs.get('book_info_dialog_fit_cover', True))
        l2.addWidget(self.fit_cover, l2.rowCount(), 0, 1, -1)
        self.previous_button = QPushButton(QIcon(I('previous.png')), _('&Previous'), self)
        self.previous_button.clicked.connect(self.previous)
        l2.addWidget(self.previous_button, l2.rowCount(), 0)
        self.next_button = QPushButton(QIcon(I('next.png')), _('&Next'), self)
        self.next_button.clicked.connect(self.next)
        l2.addWidget(self.next_button, l2.rowCount() - 1, 1)

        self.view = view
        self.current_row = None
        self.refresh(row)
        self.view.model().new_bookdisplay_data.connect(self.slave)
        self.fit_cover.stateChanged.connect(self.toggle_cover_fit)
        self.ns = QShortcut(QKeySequence('Alt+Right'), self)
        self.ns.activated.connect(self.next)
        self.ps = QShortcut(QKeySequence('Alt+Left'), self)
        self.ps.activated.connect(self.previous)
        self.next_button.setToolTip(_('Next [%s]')%
                unicode(self.ns.key().toString(QKeySequence.NativeText)))
        self.previous_button.setToolTip(_('Previous [%s]')%
                unicode(self.ps.key().toString(QKeySequence.NativeText)))

        geom = QCoreApplication.instance().desktop().availableGeometry(self)
        screen_height = geom.height() - 100
        screen_width = geom.width() - 100
        self.resize(max(int(screen_width/2), 700), screen_height)
        saved_layout = gprefs.get('book_info_dialog_layout', None)
        if saved_layout is not None:
            try:
                self.restoreGeometry(saved_layout[0])
                self.splitter.restoreState(saved_layout[1])
            except Exception:
                pass

    def link_clicked(self, qurl):
        link = unicode(qurl.toString(NO_URL_FORMATTING))
        self.link_delegate(link)

    def done(self, r):
        saved_layout = (bytearray(self.saveGeometry()), bytearray(self.splitter.saveState()))
        gprefs.set('book_info_dialog_layout', saved_layout)
        ret = QDialog.done(self, r)
        self.view.model().new_bookdisplay_data.disconnect(self.slave)
        self.view = self.link_delegate = self.gui = None
        self.closed.emit(self)
        return ret

    def cover_changed(self, data):
        if self.current_row is not None:
            id_ = self.view.model().id(self.current_row)
            self.view.model().db.set_cover(id_, data)
        self.gui.refresh_cover_browser()
        ci = self.view.currentIndex()
        if ci.isValid():
            self.view.model().current_changed(ci, ci)

    def details_size_hint(self):
        return QSize(350, 550)

    def toggle_cover_fit(self, state):
        gprefs.set('book_info_dialog_fit_cover', self.fit_cover.isChecked())
        self.resize_cover()

    def cover_view_resized(self, event):
        QTimer.singleShot(1, self.resize_cover)

    def slave(self, mi):
        self.refresh(mi.row_number, mi)

    def move(self, delta=1):
        idx = self.view.currentIndex()
        if idx.isValid():
            m = self.view.model()
            ni = m.index(idx.row() + delta, idx.column())
            if ni.isValid():
                if self.view.isVisible():
                    self.view.scrollTo(ni)
                self.view.setCurrentIndex(ni)

    def next(self):
        self.move()

    def previous(self):
        self.move(-1)

    def resize_cover(self):
        if self.cover_pixmap is None:
            return
        pixmap = self.cover_pixmap
        if self.fit_cover.isChecked():
            scaled, new_width, new_height = fit_image(pixmap.width(),
                    pixmap.height(), self.cover.size().width()-10,
                    self.cover.size().height()-10)
            if scaled:
                try:
                    dpr = self.devicePixelRatioF()
                except AttributeError:
                    dpr = self.devicePixelRatio()
                pixmap = pixmap.scaled(int(dpr * new_width), int(dpr * new_height),
                        Qt.KeepAspectRatio, Qt.SmoothTransformation)
                pixmap.setDevicePixelRatio(dpr)
        self.cover.set_pixmap(pixmap)
        self.update_cover_tooltip()

    def update_cover_tooltip(self):
        tt = ''
        if self.marked:
            tt = _('This book is marked') if self.marked in {True, 'true'} else _(
                'This book is marked as: %s') % self.marked
            tt += '\n\n'
        if self.cover_pixmap is not None:
            sz = self.cover_pixmap.size()
            tt += _('Cover size: %(width)d x %(height)d pixels')%dict(width=sz.width(), height=sz.height())
        self.cover.setToolTip(tt)

    def refresh(self, row, mi=None):
        if isinstance(row, QModelIndex):
            row = row.row()
        if row == self.current_row and mi is None:
            return
        mi = self.view.model().get_book_display_info(row) if mi is None else mi
        if mi is None:
            # Indicates books was deleted from library, or row numbers have
            # changed
            return

        self.previous_button.setEnabled(False if row == 0 else True)
        self.next_button.setEnabled(False if row == self.view.model().rowCount(QModelIndex())-1 else True)
        self.current_row = row
        self.setWindowTitle(mi.title)
        self.cover_pixmap = QPixmap.fromImage(mi.cover_data[1])
        try:
            dpr = self.devicePixelRatioF()
        except AttributeError:
            dpr = self.devicePixelRatio()
        self.cover_pixmap.setDevicePixelRatio(dpr)
        self.resize_cover()
        html = render_html(mi, self.css, True, self, all_fields=True)
        self.details.setHtml(html)
        self.marked = mi.marked
        self.cover.setBackgroundBrush(self.marked_brush if mi.marked else self.normal_brush)
        self.update_cover_tooltip()
Beispiel #21
0
class QTWSMainWindow(QWidget):
    def __init__(self,
                 app_id,
                 config_filename: str,
                 url: str,
                 app_chooser: AppChooser = None):
        super().__init__()

        self.config = QTWSConfig(config_filename, app_id)
        self.app_chooser = app_chooser
        self.app_settings = QSettings(self.config.name, "Save State", self)

        QTWSPluginManager.instance().load_plugins(self.config)
        self.__init_ui(url)
        self.__init_web_view()
        self.__read_settings()
        self.__init_shortcuts()

        QTWSPluginManager.instance().each(
            lambda plugin: plugin.window_setup(self))

    def closeEvent(self, event: QCloseEvent):
        self.__write_settings()
        if self.app_chooser:
            self.app_chooser.stop_serving()

        super().closeEvent(event)

    def __init_ui(self, url: str = None):
        self.setWindowTitle(self.config.name)

        if not url:
            url = self.config.home

        self.web = QTWSWebView(self.config)
        self.web.load(QUrl(url))

        layout = QVBoxLayout()
        layout.addWidget(self.web)
        layout.setContentsMargins(0, 0, 0, 0)

        self.setLayout(layout)

        self.setWindowIcon(QIcon(os.path.join(__home__, self.config.icon)))
        self.show()

    def __init_web_view(self):
        profile = QWebEngineProfile.defaultProfile()

        profile.setCachePath(profile.cachePath() + "/" + self.config.name)
        profile.setPersistentStoragePath(profile.persistentStoragePath() +
                                         "/" + self.config.name)
        profile.setHttpCacheMaximumSize(self.config.cache_mb * 1024 * 1024)

        self.web.page().fullScreenRequested.connect(
            self.__full_screen_requested)

        if self.config.always_on_top:
            self.setWindowFlags(Qt.WindowStaysOnTopHint)

    def __full_screen_requested(self, request: QWebEngineFullScreenRequest):
        if request.toggleOn():
            self.maximized = self.isMaximized()
            self.showFullScreen()
        else:
            self.web.triggerPageAction(QTWSWebPage.ExitFullScreen)
            if self.maximized:
                self.showNormal()
                self.showMaximized()
            else:
                self.showNormal()

        request.accept()

    def __write_settings(self):
        self.app_settings.setValue("geometry/mainWindowGeometry",
                                   self.saveGeometry())

        if not self.config.save_session:
            return

        site = self.web.url().toString()
        self.app_settings.setValue("site", site)

    def __read_settings(self):
        if not self.config.save_session or self.app_settings.value(
                "state/mainWindowState"):
            return

        if self.config.save_session:
            geometry_data = self.app_settings.value(
                "geometry/mainWindowGeometry")
            if geometry_data:
                self.restoreGeometry(geometry_data)

            site_data = self.app_settings.value("site")
            if site_data and site_data != "":
                self.web.setUrl(QUrl(site_data))

    def __init_shortcuts(self):
        self.__keyF11 = QShortcut(self)
        self.__keyF11.setKey(Qt.Key_F11)
        self.__keyF11.activated.connect(self.__action_full_screen)

        self.__keyCtrlQ = QShortcut(self)
        self.__keyCtrlQ.setKey(Qt.CTRL + Qt.Key_Q)
        self.__keyCtrlQ.activated.connect(self.__action_quit)

        self.__keyCtrlH = QShortcut(self)
        self.__keyCtrlH.setKey(Qt.CTRL + Qt.Key_H)
        self.__keyCtrlH.activated.connect(self.__action_home)

        self.__keyCtrlR = QShortcut(self)
        self.__keyCtrlR.setKey(Qt.CTRL + Qt.Key_R)
        self.__keyCtrlR.activated.connect(self.__action_reload)

        self.__keyF5 = QShortcut(self)
        self.__keyF5.setKey(Qt.Key_F5)
        self.__keyF5.activated.connect(self.__action_reload)

        self.__keyAltLeft = QShortcut(self)
        self.__keyAltLeft.setKey(Qt.ALT + Qt.Key_Left)
        self.__keyAltLeft.activated.connect(self.__action_back)

    def __action_back(self):
        self.web.back()

    def __action_full_screen(self):
        if not self.isFullScreen():
            self.maximized = self.isMaximized()
            self.showFullScreen()
        else:
            self.web.triggerPageAction(QTWSWebPage.ExitFullScreen)
            if self.maximized:
                self.showNormal()
                self.showMaximized()
            else:
                self.showNormal()

    def __action_home(self):
        self.web.setUrl(self.config.home)

    def __action_quit(self):
        self.__write_settings()
        QApplication.quit()

    def __action_reload(self):
        self.web.reload()
Beispiel #22
0
class MetadataSingleDialogBase(ResizableDialog):

    view_format = pyqtSignal(object, object)
    cc_two_column = tweaks["metadata_single_use_2_cols_for_custom_fields"]
    one_line_comments_toolbar = False
    use_toolbutton_for_config_metadata = True

    def __init__(self, db, parent=None):
        self.db = db
        self.changed = set()
        self.books_to_refresh = set()
        self.rows_to_refresh = set()
        ResizableDialog.__init__(self, parent)

    def setupUi(self, *args):  # {{{
        self.resize(990, 670)

        self.download_shortcut = QShortcut(self)
        self.download_shortcut.setKey(QKeySequence("Ctrl+D", QKeySequence.PortableText))
        p = self.parent()
        if hasattr(p, "keyboard"):
            kname = "Interface Action: Edit Metadata (Edit Metadata) : menu action : download"
            sc = p.keyboard.keys_map.get(kname, None)
            if sc:
                self.download_shortcut.setKey(sc[0])

        self.button_box = bb = QDialogButtonBox(self)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)
        self.next_button = QPushButton(QIcon(I("forward.png")), _("Next"), self)
        self.next_button.setShortcut(QKeySequence("Alt+Right"))
        self.next_button.clicked.connect(self.next_clicked)
        self.prev_button = QPushButton(QIcon(I("back.png")), _("Previous"), self)
        self.prev_button.setShortcut(QKeySequence("Alt+Left"))

        self.button_box.addButton(self.prev_button, bb.ActionRole)
        self.button_box.addButton(self.next_button, bb.ActionRole)
        self.prev_button.clicked.connect(self.prev_clicked)
        bb.setStandardButtons(bb.Ok | bb.Cancel)
        bb.button(bb.Ok).setDefault(True)

        self.scroll_area = QScrollArea(self)
        self.scroll_area.setFrameShape(QScrollArea.NoFrame)
        self.scroll_area.setWidgetResizable(True)
        self.central_widget = QTabWidget(self)
        self.scroll_area.setWidget(self.central_widget)

        self.l = QVBoxLayout(self)
        self.setLayout(self.l)
        self.l.addWidget(self.scroll_area)
        ll = self.button_box_layout = QHBoxLayout()
        self.l.addLayout(ll)
        ll.addSpacing(10)
        ll.addWidget(self.button_box)

        self.setWindowIcon(QIcon(I("edit_input.png")))
        self.setWindowTitle(BASE_TITLE)

        self.create_basic_metadata_widgets()

        if len(self.db.custom_column_label_map):
            self.create_custom_metadata_widgets()

        self.do_layout()
        geom = gprefs.get("metasingle_window_geometry3", None)
        if geom is not None:
            self.restoreGeometry(bytes(geom))

    # }}}

    def create_basic_metadata_widgets(self):  # {{{
        self.basic_metadata_widgets = []

        self.languages = LanguagesEdit(self)
        self.basic_metadata_widgets.append(self.languages)

        self.title = TitleEdit(self)
        self.title.textChanged.connect(self.update_window_title)
        self.deduce_title_sort_button = QToolButton(self)
        self.deduce_title_sort_button.setToolTip(
            _(
                "Automatically create the title sort entry based on the current "
                "title entry.\nUsing this button to create title sort will "
                "change title sort from red to green."
            )
        )
        self.deduce_title_sort_button.setWhatsThis(self.deduce_title_sort_button.toolTip())
        self.title_sort = TitleSortEdit(self, self.title, self.deduce_title_sort_button, self.languages)
        self.basic_metadata_widgets.extend([self.title, self.title_sort])

        self.deduce_author_sort_button = b = QToolButton(self)
        b.setToolTip(
            "<p>"
            + _(
                "Automatically create the author sort entry based on the current "
                "author entry. Using this button to create author sort will "
                "change author sort from red to green.  There is a menu of "
                "functions available under this button. Click and hold "
                "on the button to see it."
            )
            + "</p>"
        )
        b.m = m = QMenu()
        ac = m.addAction(QIcon(I("forward.png")), _("Set author sort from author"))
        ac2 = m.addAction(QIcon(I("back.png")), _("Set author from author sort"))
        ac3 = m.addAction(QIcon(I("user_profile.png")), _("Manage authors"))
        ac4 = m.addAction(QIcon(I("next.png")), _("Copy author to author sort"))
        ac5 = m.addAction(QIcon(I("previous.png")), _("Copy author sort to author"))

        b.setMenu(m)
        self.authors = AuthorsEdit(self, ac3)
        self.author_sort = AuthorSortEdit(self, self.authors, b, self.db, ac, ac2, ac4, ac5)
        self.basic_metadata_widgets.extend([self.authors, self.author_sort])

        self.swap_title_author_button = QToolButton(self)
        self.swap_title_author_button.setIcon(QIcon(I("swap.png")))
        self.swap_title_author_button.setToolTip(_("Swap the author and title"))
        self.swap_title_author_button.clicked.connect(self.swap_title_author)

        self.manage_authors_button = QToolButton(self)
        self.manage_authors_button.setIcon(QIcon(I("user_profile.png")))
        self.manage_authors_button.setToolTip(
            "<p>" + _("Manage authors. Use to rename authors and correct " "individual author's sort values") + "</p>"
        )
        self.manage_authors_button.clicked.connect(self.authors.manage_authors)

        self.series = SeriesEdit(self)
        self.clear_series_button = QToolButton(self)
        self.clear_series_button.setToolTip(_("Clear series"))
        self.clear_series_button.clicked.connect(self.series.clear)
        self.series_index = SeriesIndexEdit(self, self.series)
        self.basic_metadata_widgets.extend([self.series, self.series_index])

        self.formats_manager = FormatsManager(self, self.copy_fmt)
        # We want formats changes to be committed before title/author, as
        # otherwise we could have data loss if the title/author changed and the
        # user was trying to add an extra file from the old books directory.
        self.basic_metadata_widgets.insert(0, self.formats_manager)
        self.formats_manager.metadata_from_format_button.clicked.connect(self.metadata_from_format)
        self.formats_manager.cover_from_format_button.clicked.connect(self.cover_from_format)
        self.cover = Cover(self)
        self.cover.download_cover.connect(self.download_cover)
        self.basic_metadata_widgets.append(self.cover)

        self.comments = CommentsEdit(self, self.one_line_comments_toolbar)
        self.basic_metadata_widgets.append(self.comments)

        self.rating = RatingEdit(self)
        self.clear_ratings_button = QToolButton(self)
        self.clear_ratings_button.setToolTip(_("Clear rating"))
        self.clear_ratings_button.setIcon(QIcon(I("trash.png")))
        self.clear_ratings_button.clicked.connect(self.rating.zero)

        self.basic_metadata_widgets.append(self.rating)

        self.tags = TagsEdit(self)
        self.tags_editor_button = QToolButton(self)
        self.tags_editor_button.setToolTip(_("Open Tag Editor"))
        self.tags_editor_button.setIcon(QIcon(I("chapters.png")))
        self.tags_editor_button.clicked.connect(self.tags_editor)
        self.clear_tags_button = QToolButton(self)
        self.clear_tags_button.setToolTip(_("Clear all tags"))
        self.clear_tags_button.setIcon(QIcon(I("trash.png")))
        self.clear_tags_button.clicked.connect(self.tags.clear)
        self.basic_metadata_widgets.append(self.tags)

        self.identifiers = IdentifiersEdit(self)
        self.basic_metadata_widgets.append(self.identifiers)
        self.clear_identifiers_button = QToolButton(self)
        self.clear_identifiers_button.setIcon(QIcon(I("trash.png")))
        self.clear_identifiers_button.setToolTip(_("Clear Ids"))
        self.clear_identifiers_button.clicked.connect(self.identifiers.clear)
        self.paste_isbn_button = QToolButton(self)
        self.paste_isbn_button.setToolTip(
            "<p>" + _("Paste the contents of the clipboard into the " "identifiers box prefixed with isbn:") + "</p>"
        )
        self.paste_isbn_button.setIcon(QIcon(I("edit-paste.png")))
        self.paste_isbn_button.clicked.connect(self.identifiers.paste_isbn)

        self.publisher = PublisherEdit(self)
        self.basic_metadata_widgets.append(self.publisher)

        self.timestamp = DateEdit(self)
        self.pubdate = PubdateEdit(self)
        self.basic_metadata_widgets.extend([self.timestamp, self.pubdate])

        self.fetch_metadata_button = QPushButton(_("&Download metadata"), self)
        self.fetch_metadata_button.clicked.connect(self.fetch_metadata)
        self.download_shortcut.activated.connect(self.fetch_metadata_button.click)
        font = self.fmb_font = QFont()
        font.setBold(True)
        self.fetch_metadata_button.setFont(font)

        if self.use_toolbutton_for_config_metadata:
            self.config_metadata_button = QToolButton(self)
            self.config_metadata_button.setIcon(QIcon(I("config.png")))
        else:
            self.config_metadata_button = QPushButton(self)
            self.config_metadata_button.setText(_("Configure download metadata"))
        self.config_metadata_button.setIcon(QIcon(I("config.png")))
        self.config_metadata_button.clicked.connect(self.configure_metadata)
        self.config_metadata_button.setToolTip(_("Change how calibre downloads metadata"))

    # }}}

    def create_custom_metadata_widgets(self):  # {{{
        self.custom_metadata_widgets_parent = w = QWidget(self)
        layout = QGridLayout()
        w.setLayout(layout)
        self.custom_metadata_widgets, self.__cc_spacers = populate_metadata_page(
            layout, self.db, None, parent=w, bulk=False, two_column=self.cc_two_column
        )
        self.__custom_col_layouts = [layout]

    # }}}

    def set_custom_metadata_tab_order(self, before=None, after=None):  # {{{
        sto = QWidget.setTabOrder
        if getattr(self, "custom_metadata_widgets", []):
            ans = self.custom_metadata_widgets
            for i in range(len(ans) - 1):
                if before is not None and i == 0:
                    pass
                if len(ans[i + 1].widgets) == 2:
                    sto(ans[i].widgets[-1], ans[i + 1].widgets[1])
                else:
                    sto(ans[i].widgets[-1], ans[i + 1].widgets[0])
                for c in range(2, len(ans[i].widgets), 2):
                    sto(ans[i].widgets[c - 1], ans[i].widgets[c + 1])
            if after is not None:
                pass

    # }}}

    def do_view_format(self, path, fmt):
        if path:
            self.view_format.emit(None, path)
        else:
            self.view_format.emit(self.book_id, fmt)

    def copy_fmt(self, fmt, f):
        self.db.copy_format_to(self.book_id, fmt, f, index_is_id=True)

    def do_layout(self):
        raise NotImplementedError()

    def __call__(self, id_):
        self.book_id = id_
        self.books_to_refresh = set([])
        for widget in self.basic_metadata_widgets:
            widget.initialize(self.db, id_)
        for widget in getattr(self, "custom_metadata_widgets", []):
            widget.initialize(id_)
        if callable(self.set_current_callback):
            self.set_current_callback(id_)
        # Commented out as it doesn't play nice with Next, Prev buttons
        # self.fetch_metadata_button.setFocus(Qt.OtherFocusReason)

    # Miscellaneous interaction methods {{{
    def update_window_title(self, *args):
        title = self.title.current_val
        if len(title) > 50:
            title = title[:50] + "\u2026"
        self.setWindowTitle(
            BASE_TITLE
            + " - "
            + title
            + " - "
            + _(" [%(num)d of %(tot)d]") % dict(num=self.current_row + 1, tot=len(self.row_list))
        )

    def swap_title_author(self, *args):
        title = self.title.current_val
        self.title.current_val = authors_to_string(self.authors.current_val)
        self.authors.current_val = string_to_authors(title)
        self.title_sort.auto_generate()
        self.author_sort.auto_generate()

    def tags_editor(self, *args):
        self.tags.edit(self.db, self.book_id)

    def metadata_from_format(self, *args):
        mi, ext = self.formats_manager.get_selected_format_metadata(self.db, self.book_id)
        if mi is not None:
            self.update_from_mi(mi)

    def get_pdf_cover(self):
        pdfpath = self.formats_manager.get_format_path(self.db, self.book_id, "pdf")
        from calibre.gui2.metadata.pdf_covers import PDFCovers

        d = PDFCovers(pdfpath, parent=self)
        if d.exec_() == d.Accepted:
            cpath = d.cover_path
            if cpath:
                with open(cpath, "rb") as f:
                    self.update_cover(f.read(), "PDF")
        d.cleanup()

    def cover_from_format(self, *args):
        ext = self.formats_manager.get_selected_format()
        if ext is None:
            return
        if ext == "pdf":
            return self.get_pdf_cover()
        try:
            mi, ext = self.formats_manager.get_selected_format_metadata(self.db, self.book_id)
        except (IOError, OSError) as err:
            if getattr(err, "errno", None) == errno.EACCES:  # Permission denied
                import traceback

                fname = err.filename if err.filename else "file"
                error_dialog(
                    self,
                    _("Permission denied"),
                    _("Could not open %s. Is it being used by another" " program?") % fname,
                    det_msg=traceback.format_exc(),
                    show=True,
                )
                return
            raise
        if mi is None:
            return
        cdata = None
        if mi.cover and os.access(mi.cover, os.R_OK):
            cdata = open(mi.cover).read()
        elif mi.cover_data[1] is not None:
            cdata = mi.cover_data[1]
        if cdata is None:
            error_dialog(self, _("Could not read cover"), _("Could not read cover from %s format") % ext).exec_()
            return
        self.update_cover(cdata, ext)

    def update_cover(self, cdata, fmt):
        orig = self.cover.current_val
        self.cover.current_val = cdata
        if self.cover.current_val is None:
            self.cover.current_val = orig
            return error_dialog(
                self, _("Could not read cover"), _("The cover in the %s format is invalid") % fmt, show=True
            )
            return

    def update_from_mi(self, mi, update_sorts=True, merge_tags=True, merge_comments=False):
        if not mi.is_null("title"):
            self.title.current_val = mi.title
            if update_sorts:
                self.title_sort.auto_generate()
        if not mi.is_null("authors"):
            self.authors.current_val = mi.authors
        if not mi.is_null("author_sort"):
            self.author_sort.current_val = mi.author_sort
        elif update_sorts:
            self.author_sort.auto_generate()
        if not mi.is_null("rating"):
            try:
                self.rating.current_val = mi.rating
            except:
                pass
        if not mi.is_null("publisher"):
            self.publisher.current_val = mi.publisher
        if not mi.is_null("tags"):
            old_tags = self.tags.current_val
            tags = mi.tags if mi.tags else []
            if old_tags and merge_tags:
                ltags, lotags = {t.lower() for t in tags}, {t.lower() for t in old_tags}
                tags = [t for t in tags if t.lower() in ltags - lotags] + old_tags
            self.tags.current_val = tags
        if not mi.is_null("identifiers"):
            current = self.identifiers.current_val
            current.update(mi.identifiers)
            self.identifiers.current_val = current
        if not mi.is_null("pubdate"):
            self.pubdate.current_val = mi.pubdate
        if not mi.is_null("series") and mi.series.strip():
            self.series.current_val = mi.series
            if mi.series_index is not None:
                self.series_index.reset_original()
                self.series_index.current_val = float(mi.series_index)
        if not mi.is_null("languages"):
            langs = [canonicalize_lang(x) for x in mi.languages]
            langs = [x for x in langs if x is not None]
            if langs:
                self.languages.current_val = langs
        if mi.comments and mi.comments.strip():
            val = mi.comments
            if val and merge_comments:
                cval = self.comments.current_val
                if cval:
                    val = merge_two_comments(cval, val)
            self.comments.current_val = val

    def fetch_metadata(self, *args):
        d = FullFetch(self.cover.pixmap(), self)
        ret = d.start(
            title=self.title.current_val, authors=self.authors.current_val, identifiers=self.identifiers.current_val
        )
        if ret == d.Accepted:
            from calibre.ebooks.metadata.sources.prefs import msprefs

            mi = d.book
            dummy = Metadata(_("Unknown"))
            for f in msprefs["ignore_fields"]:
                if ":" not in f:
                    setattr(mi, f, getattr(dummy, f))
            if mi is not None:
                pd = mi.pubdate
                if pd is not None:
                    # Put the downloaded published date into the local timezone
                    # as we discard time info and the date is timezone
                    # invariant. This prevents the as_local_timezone() call in
                    # update_from_mi from changing the pubdate
                    mi.pubdate = datetime(pd.year, pd.month, pd.day, tzinfo=local_tz)
                self.update_from_mi(mi, merge_comments=msprefs["append_comments"])
            if d.cover_pixmap is not None:
                self.cover.current_val = pixmap_to_data(d.cover_pixmap)

    def configure_metadata(self):
        from calibre.gui2.preferences import show_config_widget

        gui = self.parent()
        show_config_widget("Sharing", "Metadata download", parent=self, gui=gui, never_shutdown=True)

    def download_cover(self, *args):
        from calibre.gui2.metadata.single_download import CoverFetch

        d = CoverFetch(self.cover.pixmap(), self)
        ret = d.start(self.title.current_val, self.authors.current_val, self.identifiers.current_val)
        if ret == d.Accepted:
            if d.cover_pixmap is not None:
                self.cover.current_val = pixmap_to_data(d.cover_pixmap)

    # }}}

    def apply_changes(self):
        self.changed.add(self.book_id)
        if self.db is None:
            # break_cycles has already been called, don't know why this should
            # happen but a user reported it
            return True
        for widget in self.basic_metadata_widgets:
            try:
                if hasattr(widget, "validate_for_commit"):
                    title, msg, det_msg = widget.validate_for_commit()
                    if title is not None:
                        error_dialog(self, title, msg, det_msg=det_msg, show=True)
                        return False
                widget.commit(self.db, self.book_id)
                self.books_to_refresh |= getattr(widget, "books_to_refresh", set())
            except (IOError, OSError) as err:
                if getattr(err, "errno", None) == errno.EACCES:  # Permission denied
                    import traceback

                    fname = getattr(err, "filename", None)
                    p = "Locked file: %s\n\n" % fname if fname else ""
                    error_dialog(
                        self,
                        _("Permission denied"),
                        _("Could not change the on disk location of this" " book. Is it open in another program?"),
                        det_msg=p + traceback.format_exc(),
                        show=True,
                    )
                    return False
                raise
        for widget in getattr(self, "custom_metadata_widgets", []):
            self.books_to_refresh |= widget.commit(self.book_id)

        self.db.commit()
        rows = self.db.refresh_ids(list(self.books_to_refresh))
        if rows:
            self.rows_to_refresh |= set(rows)

        return True

    def accept(self):
        self.save_state()
        if not self.apply_changes():
            return
        ResizableDialog.accept(self)

    def reject(self):
        self.save_state()
        ResizableDialog.reject(self)

    def save_state(self):
        try:
            gprefs["metasingle_window_geometry3"] = bytearray(self.saveGeometry())
        except:
            # Weird failure, see https://bugs.launchpad.net/bugs/995271
            import traceback

            traceback.print_exc()

    # Dialog use methods {{{
    def start(self, row_list, current_row, view_slot=None, set_current_callback=None):
        self.row_list = row_list
        self.current_row = current_row
        if view_slot is not None:
            self.view_format.connect(view_slot)
        self.set_current_callback = set_current_callback
        self.do_one(apply_changes=False)
        ret = self.exec_()
        self.break_cycles()
        return ret

    def next_clicked(self):
        if not self.apply_changes():
            return
        self.do_one(delta=1, apply_changes=False)

    def prev_clicked(self):
        if not self.apply_changes():
            return
        self.do_one(delta=-1, apply_changes=False)

    def do_one(self, delta=0, apply_changes=True):
        if apply_changes:
            self.apply_changes()
        self.current_row += delta
        prev = next_ = None
        if self.current_row > 0:
            prev = self.db.title(self.row_list[self.current_row - 1])
        if self.current_row < len(self.row_list) - 1:
            next_ = self.db.title(self.row_list[self.current_row + 1])

        if next_ is not None:
            tip = (_("Save changes and edit the metadata of %s") + " [Alt+Right]") % next_
            self.next_button.setToolTip(tip)
        self.next_button.setEnabled(next_ is not None)
        if prev is not None:
            tip = (_("Save changes and edit the metadata of %s") + " [Alt+Left]") % prev
            self.prev_button.setToolTip(tip)
        self.prev_button.setEnabled(prev is not None)
        self.button_box.button(self.button_box.Ok).setDefault(True)
        self.button_box.button(self.button_box.Ok).setFocus(Qt.OtherFocusReason)
        self(self.db.id(self.row_list[self.current_row]))

    def break_cycles(self):
        # Break any reference cycles that could prevent python
        # from garbage collecting this dialog
        self.set_current_callback = self.db = None

        def disconnect(signal):
            try:
                signal.disconnect()
            except:
                pass  # Fails if view format was never connected

        disconnect(self.view_format)
        for b in ("next_button", "prev_button"):
            x = getattr(self, b, None)
            if x is not None:
                disconnect(x.clicked)
        for widget in self.basic_metadata_widgets:
            bc = getattr(widget, "break_cycles", None)
            if bc is not None and callable(bc):
                bc()
        for widget in getattr(self, "custom_metadata_widgets", []):
            widget.break_cycles()
Beispiel #23
0
    def __init__(self, parent, view, row, link_delegate):
        QDialog.__init__(self, parent)
        self.normal_brush = QBrush(Qt.white)
        self.marked_brush = QBrush(Qt.lightGray)
        self.marked = None
        self.gui = parent
        self.splitter = QSplitter(self)
        self._l = l = QVBoxLayout(self)
        self.setLayout(l)
        l.addWidget(self.splitter)

        self.cover = CoverView(self, show_size=gprefs['bd_overlay_cover_size'])
        self.cover.resizeEvent = self.cover_view_resized
        self.cover.cover_changed.connect(self.cover_changed)
        self.cover_pixmap = None
        self.cover.sizeHint = self.details_size_hint
        self.splitter.addWidget(self.cover)

        self.details = Details(parent.book_details.book_info, self)
        self.details.anchor_clicked.connect(self.on_link_clicked)
        self.link_delegate = link_delegate
        self.details.setAttribute(Qt.WA_OpaquePaintEvent, False)
        palette = self.details.palette()
        self.details.setAcceptDrops(False)
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.details.setPalette(palette)

        self.c = QWidget(self)
        self.c.l = l2 = QGridLayout(self.c)
        l2.setContentsMargins(0, 0, 0, 0)
        self.c.setLayout(l2)
        l2.addWidget(self.details, 0, 0, 1, -1)
        self.splitter.addWidget(self.c)

        self.fit_cover = QCheckBox(_('Fit &cover within view'), self)
        self.fit_cover.setChecked(
            gprefs.get('book_info_dialog_fit_cover', True))
        self.hl = hl = QHBoxLayout()
        hl.setContentsMargins(0, 0, 0, 0)
        l2.addLayout(hl, l2.rowCount(), 0, 1, -1)
        hl.addWidget(self.fit_cover), hl.addStretch()
        self.clabel = QLabel(
            '<div style="text-align: right"><a href="calibre:conf" title="{}" style="text-decoration: none">{}</a>'
            .format(_('Configure this view'), _('Configure')))
        self.clabel.linkActivated.connect(self.configure)
        hl.addWidget(self.clabel)
        self.previous_button = QPushButton(QIcon(I('previous.png')),
                                           _('&Previous'), self)
        self.previous_button.clicked.connect(self.previous)
        l2.addWidget(self.previous_button, l2.rowCount(), 0)
        self.next_button = QPushButton(QIcon(I('next.png')), _('&Next'), self)
        self.next_button.clicked.connect(self.next)
        l2.addWidget(self.next_button, l2.rowCount() - 1, 1)

        self.view = view
        self.current_row = None
        self.refresh(row)
        self.view.model().new_bookdisplay_data.connect(self.slave)
        self.fit_cover.stateChanged.connect(self.toggle_cover_fit)
        self.ns = QShortcut(QKeySequence('Alt+Right'), self)
        self.ns.activated.connect(self.next)
        self.ps = QShortcut(QKeySequence('Alt+Left'), self)
        self.ps.activated.connect(self.previous)
        self.next_button.setToolTip(
            _('Next [%s]') %
            unicode_type(self.ns.key().toString(QKeySequence.NativeText)))
        self.previous_button.setToolTip(
            _('Previous [%s]') %
            unicode_type(self.ps.key().toString(QKeySequence.NativeText)))

        geom = QCoreApplication.instance().desktop().availableGeometry(self)
        screen_height = geom.height() - 100
        screen_width = geom.width() - 100
        self.resize(max(int(screen_width / 2), 700), screen_height)
        saved_layout = gprefs.get('book_info_dialog_layout', None)
        if saved_layout is not None:
            try:
                self.restoreGeometry(saved_layout[0])
                self.splitter.restoreState(saved_layout[1])
            except Exception:
                pass
Beispiel #24
0
class QTWSMainWindow(QWidget):
    def __init__(self,
                 app_id,
                 config_filename: str,
                 url: str = None,
                 profile: str = None):
        super().__init__()

        self.config = QTWSConfig(config_filename, app_id)
        self.app_settings = QSettings(self.config.name, "Save State", self)

        self._profile_id = profile

        QTWSPluginManager.instance().load_plugins(self.config)
        self.__init_ui(url)
        self.__init_web_view()
        self.__read_settings()
        self.__init_shortcuts()

        self.enter_event_handler = EnterEventHandler()
        self.setMouseTracking(True)
        self.installEventFilter(self.enter_event_handler)
        self.default_flags = self.windowFlags()

        QTWSPluginManager.instance().each(
            lambda plugin: plugin.window_setup(self))

    def closeEvent(self, event: QCloseEvent):
        self.__write_settings()

        QTWSPluginManager.instance().each(
            lambda plugin: plugin.close_event(self, event))

    def quit(self):
        self.__action_quit()

    def profile_id(self):
        return self._profile_id

    def set_always_on_top(self, always_on_top: bool):
        self.setWindowFlag(Qt.WindowStaysOnTopHint, always_on_top)
        self.show()

    def set_maximizable(self, maximizable: bool):
        self.setWindowFlag(Qt.WindowMaximizeButtonHint, maximizable)
        self.show()

    def reset_flags(self):
        self.setWindowFlags(self.default_flags)
        self.show()

    def activate_fullscreen(self):
        if not self.isFullScreen():
            self.maximized = self.isMaximized()
            self.showFullScreen()

    def deactivate_fullscreen(self):
        if self.isFullScreen():
            self.web.triggerPageAction(QTWSWebPage.ExitFullScreen)
            if self.maximized:
                self.showNormal()
                self.showMaximized()
            else:
                self.showNormal()

    def set_mouse_enter_callback(self, callback):
        self.enter_event_handler.set_callback(callback)

    def __init_ui(self, url: str = None):
        self.setWindowTitle(f"{self.config.name}")

        if not url or not self.config.in_scope(url):
            url = self.config.home

        if type(url) == QUrl:
            url = url.toString()

        url = url.replace('silo://', 'https://')

        self.web = QTWSWebView(self.config, self, self._profile_id)
        self.web.load(QUrl(url))

        layout = QVBoxLayout()
        layout.addWidget(self.web)
        layout.setContentsMargins(0, 0, 0, 0)

        self.setLayout(layout)

        self.setWindowIcon(QIcon(self.config.icon))
        QApplication.instance().setDesktopFileName("silo-" +
                                                   self.config.app_id)
        self.show()

        self.maximized = self.isMaximized()

        if self.config.always_on_top:
            self.set_always_on_top(True)

    def __init_web_view(self):
        self.web.page().fullScreenRequested.connect(
            self.__full_screen_requested)

    def __full_screen_requested(self, request: QWebEngineFullScreenRequest):
        if request.toggleOn():
            self.maximized = self.isMaximized()
            self.showFullScreen()
        else:
            self.web.triggerPageAction(QTWSWebPage.ExitFullScreen)
            if self.maximized:
                self.showNormal()
                self.showMaximized()
            else:
                self.showNormal()

        request.accept()

    def __write_settings(self):
        self.app_settings.setValue("geometry/mainWindowGeometry",
                                   self.saveGeometry())

        if not self.config.save_session:
            return

        site = self.web.url().toString()
        self.app_settings.setValue("site", site)

    def __read_settings(self):
        if not self.config.save_session:
            return

        if self.config.save_session:
            geometry_data = self.app_settings.value(
                "geometry/mainWindowGeometry")
            if geometry_data:
                self.restoreGeometry(geometry_data)

            site_data = self.app_settings.value("site")
            if site_data and site_data != "":
                self.web.setUrl(QUrl(site_data))

    def __init_shortcuts(self):
        self.__keyF11 = QShortcut(self)
        self.__keyF11.setKey(Qt.Key_F11)
        self.__keyF11.activated.connect(self.__action_full_screen)

        self.__keyCtrlQ = QShortcut(self)
        self.__keyCtrlQ.setKey(Qt.CTRL + Qt.Key_Q)
        self.__keyCtrlQ.activated.connect(self.__action_quit)

        self.__keyCtrlH = QShortcut(self)
        self.__keyCtrlH.setKey(Qt.CTRL + Qt.Key_H)
        self.__keyCtrlH.activated.connect(self.__action_home)

        self.__keyCtrlR = QShortcut(self)
        self.__keyCtrlR.setKey(Qt.CTRL + Qt.Key_R)
        self.__keyCtrlR.activated.connect(self.__action_reload)

        self.__keyF5 = QShortcut(self)
        self.__keyF5.setKey(Qt.Key_F5)
        self.__keyF5.activated.connect(self.__action_reload)

        self.__keyAltLeft = QShortcut(self)
        self.__keyAltLeft.setKey(Qt.ALT + Qt.Key_Left)
        self.__keyAltLeft.activated.connect(self.__action_back)

        QTWSPluginManager.instance().each(
            lambda plugin: plugin.register_shortcuts(self))

    def __action_back(self):
        self.web.back()

    def __action_full_screen(self):
        if not self.isFullScreen():
            self.activate_fullscreen()
        else:
            self.deactivate_fullscreen()

    def __action_home(self):
        self.web.setUrl(self.config.home)

    def __action_quit(self):
        self.__write_settings()
        QApplication.quit()

    def __action_reload(self):
        self.web.reload()
Beispiel #25
0
    def __init_shortcuts(self):
        self.__keyF11 = QShortcut(self)
        self.__keyF11.setKey(Qt.Key_F11)
        self.__keyF11.activated.connect(self.__action_full_screen)

        self.__keyCtrlQ = QShortcut(self)
        self.__keyCtrlQ.setKey(Qt.CTRL + Qt.Key_Q)
        self.__keyCtrlQ.activated.connect(self.__action_quit)

        self.__keyCtrlH = QShortcut(self)
        self.__keyCtrlH.setKey(Qt.CTRL + Qt.Key_H)
        self.__keyCtrlH.activated.connect(self.__action_home)

        self.__keyCtrlR = QShortcut(self)
        self.__keyCtrlR.setKey(Qt.CTRL + Qt.Key_R)
        self.__keyCtrlR.activated.connect(self.__action_reload)

        self.__keyF5 = QShortcut(self)
        self.__keyF5.setKey(Qt.Key_F5)
        self.__keyF5.activated.connect(self.__action_reload)

        self.__keyAltLeft = QShortcut(self)
        self.__keyAltLeft.setKey(Qt.ALT + Qt.Key_Left)
        self.__keyAltLeft.activated.connect(self.__action_back)

        QTWSPluginManager.instance().each(
            lambda plugin: plugin.register_shortcuts(self))
Beispiel #26
0
    def setup_widgets(self):
        # file editing and tabs
        self.editor_pane = gui_widgets.TabController(self, self.ontologies)
        self.editor_pane.currentChanged.connect(self.__on_tab_change)

        # project navigation
        self.explorer_tab = QTabWidget(self)
        self.project_explorer = gui_widgets.ProjectExplorer(self, self.root_path, self.editor_pane)
        self.explorer_tab.addTab(self.project_explorer, "Directory")
        self.import_explorer = gui_widgets.ImportSidebar(self, self.root_path, self.editor_pane)
        self.explorer_tab.addTab(self.import_explorer, "Imports")

        # informational sidebar
        self.info_bar = gui_widgets.InformationSidebar(self, self.root_path)

        # output
        self.console = gui_widgets.Console(self)

        main_menu = self.menuBar()

        # file menu and associated actions
        file_menu = main_menu.addMenu('File')

        # Create a new tab
        new_action = QAction("New File", self)
        file_menu.addAction(new_action)
        new_action.triggered.connect(self.new_command)

        # Open a file
        open_action = QAction("Open", self)
        file_menu.addAction(open_action)
        open_action.triggered.connect(self.open_command)
        open_shortcut = QShortcut(QKeySequence("Ctrl+O"), self)
        open_shortcut.activated.connect(self.open_command)

        # Save file; if no file, open dialog
        save_action = QAction("Save", self)
        file_menu.addAction(save_action)
        save_action.triggered.connect(self.save_command)
        save_shortcut = QShortcut(QKeySequence("Ctrl+S"), self)
        save_shortcut.activated.connect(self.save_command)

        # Open Save dialog
        saveas_action = QAction("Save As..", self)
        file_menu.addAction(saveas_action)
        saveas_action.triggered.connect(self.saveas_command)

        # Open settings dialog
        settings_action = QAction("Settings..", self)
        file_menu.addAction(settings_action)
        settings_action.triggered.connect(self.settings_command)

        # Open Export dialog
        export_action = QAction("Export.. ", self)
        file_menu.addAction(export_action)
        export_action.triggered.connect(self.export_command)

        # Run menu and associated actions
        run_menu = main_menu.addMenu('Run')

        # Run the parse w/out resolving imports
        parse_action = QAction("Parse (No Imports)", self)
        run_menu.addAction(parse_action)
        parse_action.triggered.connect(self.parse_command)

        # Run the parse w/ imports
        parse_imports_action = QAction("Parse (w/ Imports)", self)
        run_menu.addAction(parse_imports_action)
        parse_imports_action.triggered.connect(self.parse_imports_command)

        run_menu.addSeparator()

        # Run the check consistency dialog
        check_consistency_action = QAction("Check Consistency..", self)
        run_menu.addAction(check_consistency_action)
        check_consistency_action.triggered.connect(self.check_consistency_command)

        # Threads
        self.parse_thread = gui_threads.ParseThread()
        self.parse_thread.finished.connect(self.__on_parse_done)
Beispiel #27
0
    def __init__(self, gui, row, toggle_shortcut):
        self.is_pane = gprefs.get('quickview_is_pane', False)

        if not self.is_pane:
            QDialog.__init__(self, gui, flags=Qt.WindowType.Widget)
        else:
            QDialog.__init__(self, gui)
        Ui_Quickview.__init__(self)
        self.setupUi(self)
        self.isClosed = False
        self.current_book = None
        self.closed_by_button = False

        if self.is_pane:
            self.main_grid_layout.setContentsMargins(0, 0, 0, 0)
        else:
            self.setWindowIcon(self.windowIcon())

        self.books_table_column_widths = None
        try:
            self.books_table_column_widths = \
                        gprefs.get('quickview_dialog_books_table_widths', None)
            if not self.is_pane:
                geom = gprefs.get('quickview_dialog_geometry', None)
                if geom:
                    QApplication.instance().safe_restore_geometry(
                        self, QByteArray(geom))
        except:
            pass

        self.view = gui.library_view
        self.db = self.view.model().db
        self.gui = gui
        self.is_closed = False
        self.current_book_id = None  # the db id of the book used to fill the lh pane
        self.current_column = None  # current logical column in books list
        self.current_key = None  # current lookup key in books list
        self.last_search = None
        self.no_valid_items = False
        self.follow_library_view = True

        self.apply_vls.setCheckState(
            Qt.CheckState.Checked if gprefs['qv_respects_vls'] else Qt.
            CheckState.Unchecked)
        self.apply_vls.stateChanged.connect(self.vl_box_changed)

        self.fm = self.db.field_metadata

        self.items.setSelectionMode(
            QAbstractItemView.SelectionMode.SingleSelection)
        self.items.currentTextChanged.connect(self.item_selected)
        self.items.setProperty('highlight_current_item', 150)
        self.items.itemDoubleClicked.connect(self.item_doubleclicked)
        self.items.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self.items.customContextMenuRequested.connect(
            self.show_item_context_menu)

        focus_filter = WidgetFocusFilter(self.items)
        focus_filter.focus_entered_signal.connect(self.focus_entered)
        self.items.installEventFilter(focus_filter)

        self.tab_pressed_signal.connect(self.tab_pressed)
        return_filter = BooksTableFilter(self.books_table)
        return_filter.return_pressed_signal.connect(self.return_pressed)
        self.books_table.installEventFilter(return_filter)

        focus_filter = WidgetFocusFilter(self.books_table)
        focus_filter.focus_entered_signal.connect(self.focus_entered)
        self.books_table.installEventFilter(focus_filter)

        self.close_button.clicked.connect(self.close_button_clicked)
        self.refresh_button.clicked.connect(self.refill)

        self.tab_order_widgets = [
            self.items, self.books_table, self.lock_qv, self.dock_button,
            self.refresh_button, self.close_button
        ]
        for idx, widget in enumerate(self.tab_order_widgets):
            widget.installEventFilter(
                WidgetTabFilter(widget, idx, self.tab_pressed_signal))

        self.books_table.setSelectionBehavior(
            QAbstractItemView.SelectionBehavior.SelectRows)
        self.books_table.setSelectionMode(
            QAbstractItemView.SelectionMode.SingleSelection)
        self.books_table.setProperty('highlight_current_item', 150)

        # Set up the books table columns
        self.add_columns_to_widget()

        self.books_table_header_height = self.books_table.height()
        self.books_table.cellDoubleClicked.connect(self.book_doubleclicked)
        self.books_table.currentCellChanged.connect(
            self.books_table_cell_changed)
        self.books_table.cellClicked.connect(
            self.books_table_set_search_string)
        self.books_table.cellActivated.connect(
            self.books_table_set_search_string)
        self.books_table.sortByColumn(0, Qt.SortOrder.AscendingOrder)

        # get the standard table row height. Do this here because calling
        # resizeRowsToContents can word wrap long cell contents, creating
        # double-high rows
        self.books_table.setRowCount(1)
        self.books_table.setItem(0, 0, TableItem('A', ''))
        self.books_table.resizeRowsToContents()
        self.books_table_row_height = self.books_table.rowHeight(0)
        self.books_table.setRowCount(0)

        # Add the data
        self.refresh(row)

        self.view.clicked.connect(self.slave)
        self.view.selectionModel().currentColumnChanged.connect(
            self.column_slave)
        QCoreApplication.instance().aboutToQuit.connect(self.save_state)
        self.view.model().new_bookdisplay_data.connect(self.book_was_changed)

        self.close_button.setDefault(False)
        self.close_button_tooltip = _(
            'The Quickview shortcut ({0}) shows/hides the Quickview panel')
        if self.is_pane:
            self.dock_button.setText(_('Undock'))
            self.dock_button.setToolTip(
                _('Show the Quickview panel in its own floating window'))
            self.dock_button.setIcon(QIcon(I('arrow-up.png')))
            # Remove the ampersands from the buttons because shortcuts exist.
            self.lock_qv.setText(_('Lock Quickview contents'))
            self.refresh_button.setText(_('Refresh'))
            self.gui.quickview_splitter.add_quickview_dialog(self)
            self.close_button.setVisible(False)
        else:
            self.dock_button.setToolTip(
                _('Embed the quickview panel into the main calibre window'))
            self.dock_button.setIcon(QIcon(I('arrow-down.png')))
        self.set_focus()

        self.books_table.horizontalHeader().sectionResized.connect(
            self.section_resized)
        self.dock_button.clicked.connect(self.show_as_pane_changed)
        self.view.model().search_done.connect(self.check_for_no_items)

        # Enable the refresh button only when QV is locked
        self.refresh_button.setEnabled(False)
        self.lock_qv.stateChanged.connect(self.lock_qv_changed)

        self.view_icon = QIcon(I('view.png'))
        self.view_plugin = self.gui.iactions['View']
        self.edit_metadata_icon = QIcon(I('edit_input.png'))
        self.quickview_icon = QIcon(I('quickview.png'))
        self.select_book_icon = QIcon(I('library.png'))
        self.search_icon = QIcon(I('search.png'))
        self.books_table.setContextMenuPolicy(
            Qt.ContextMenuPolicy.CustomContextMenu)
        self.books_table.customContextMenuRequested.connect(
            self.show_context_menu)

        # Add the quickview toggle as a shortcut for the close button
        # Don't add it if it identical to the current &X shortcut because that
        # breaks &X
        if (not self.is_pane and toggle_shortcut
                and self.close_button.shortcut() != toggle_shortcut):
            toggle_sc = QShortcut(toggle_shortcut, self.close_button)
            toggle_sc.activated.connect(lambda: self.close_button_clicked())
            toggle_sc.setEnabled(True)
            self.close_button.setToolTip(
                _('Alternate shortcut: ') + toggle_shortcut.toString())
Beispiel #28
0
class MainWindow(QMainWindow):

    #    class EventFilter(QObject):
    #        def __init__(self, parent):
    #            super().__init__(parent)
    #
    #        def eventFilter(self, obj, e):
    #            #print(obj.metaObject().className())
    #
    #            if e.type() == QEvent.KeyPress or e.type() == QEvent.ShortcutOverride:
    #                key = e.key()
    #                mod = e.modifiers()
    #
    #                print(str(e) + ' ' + str(e.type()) )
    #
    #                if mod == Qt.AltModifier:
    #                    print('*'*30)
    #                    print('alt pressed')
    #                    if key == Qt.Key_Left or key == Qt.Key_Right:
    #                        print('alt-left') if key == Qt.Key_Left else print('alt-right')
    ##                       action = QAbstractItemView.MoveLeft if key == Qt.Key_Left else QAbstractItemView.MoveRight
    ##                       idx = obj.moveCursor(action, Qt.NoModifier)
    ##                       item = obj.itemFromIndex(idx)
    ##                       obj.setCurrentItem(item)
    #                        return True
    #
    #            return False

    PROGRAM_NAME = 'KiCad Schematic Component Manager'

    #--------------------------------------------------------------------------------
    class EventFilter(QObject):
        def __init__(self, parent):
            super().__init__(parent)

        def eventFilter(self, obj, e):
            if e.type() == QEvent.KeyPress or e.type(
            ) == QEvent.ShortcutOverride:
                key = e.key()
                mod = e.modifiers()

                #print(obj.focusWidget().metaObject().className())

            return False

    #--------------------------------------------------------------------------------
    def scroll_left(self):
        print('alt-left')
        if self.ToolIndex == 3 or self.ToolIndex == 2:
            self.ToolList[self.ToolIndex].finish_edit()

        self.ToolIndex -= 1
        if self.ToolIndex < 0:
            self.ToolIndex = len(self.ToolList) - 1

        print('Tool Index: ' + str(self.ToolIndex))
        self.ToolList[self.ToolIndex].setFocus()

    #--------------------------------------------------------------------------------
    def scroll_right(self):
        print('alt-right')
        if self.ToolIndex == 3 or self.ToolIndex == 2:
            self.ToolList[self.ToolIndex].finish_edit()

        self.ToolIndex += 1
        if self.ToolIndex == len(self.ToolList):
            self.ToolIndex = 0

        print('Tool Index: ' + str(self.ToolIndex))
        self.ToolList[self.ToolIndex].setFocus()

    #--------------------------------------------------------------------------------
    def mouse_change_tool(self, s):
        print('Tool ' + s)
        if s == 'CmpTable':
            self.ToolIndex = 0
        elif s == 'Selector':
            self.ToolIndex = 1
        elif s == 'Inspector':
            self.ToolIndex = 2
        elif s == 'FieldInspector':
            self.ToolIndex = 3

        if self.ToolIndex != 3:
            self.ToolList[3].finish_edit(
            )  # save field properties when leave field inspector

    #--------------------------------------------------------------------------------
    def add_user_property(self):
        self.Inspector.save_cmps()
        self.FieldInspector.save_fields()

        self.Inspector.add_property()

    #--------------------------------------------------------------------------------
    def remove_user_property(self):
        #self.Inspector.save_cmps()
        self.FieldInspector.save_fields()

        self.Inspector.remove_property()

    #--------------------------------------------------------------------------------
    def rename_user_property(self):
        #self.Inspector.save_cmps()
        self.FieldInspector.save_fields()

        self.Inspector.rename_property()

    #--------------------------------------------------------------------------------
    def __init__(self):
        super().__init__()

        self.initUI()

        self.installEventFilter(self.EventFilter(self))

        self.setFocusPolicy(Qt.WheelFocus)
        self.setTabOrder(self.CmpTable, self.Inspector)
        self.setTabOrder(self.Inspector, self.Selector)
        self.setTabOrder(self.Selector, self.FieldInspector)
        #self.setTabOrder(self.FieldInspector, self.CmpTable)

        #----------------------------------------------------
        #
        #   Application Hotkeys
        #
        self.shortcutLeft = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Left), self)
        self.shortcutRight = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Right),
                                       self)
        self.shortcutLeft.setContext(Qt.ApplicationShortcut)
        self.shortcutRight.setContext(Qt.ApplicationShortcut)
        self.shortcutLeft.activated.connect(self.scroll_left)
        self.shortcutRight.activated.connect(self.scroll_right)

    #--------------------------------------------------------------------------------
    def initUI(self):

        #----------------------------------------------------
        #
        #    Main Window
        #
        work_zone = QWidget(self)
        Layout = QHBoxLayout(work_zone)
        self.setCentralWidget(work_zone)

        openAction = QAction(QIcon(os.path.join(resources_path, 'open24.png')),
                             'Open', self)
        openAction.setShortcut('Ctrl+O')
        openAction.setStatusTip('Open Schematic File')
        openAction.triggered.connect(self.open_file)

        saveAction = QAction(QIcon(os.path.join(resources_path, 'save24.png')),
                             'Save', self)
        saveAction.setShortcut('Ctrl+S')
        saveAction.setStatusTip('Save Schematic File')
        saveAction.triggered.connect(self.save_file)

        saveAsAction = QAction(
            QIcon(os.path.join(resources_path, 'save-as24.png')), 'Save As...',
            self)
        saveAsAction.setShortcut('Ctrl+Shift+S')
        saveAsAction.setStatusTip('Save Schematic File As...')
        saveAsAction.triggered.connect(self.save_file_as)

        exitAction = QAction(QIcon(os.path.join(resources_path, 'exit24.png')),
                             'Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)

        settingsAction = QAction(
            QIcon(os.path.join(resources_path, 'settings24.png')), 'Settings',
            self)
        settingsAction.setShortcut('Ctrl+Alt+S')
        settingsAction.setStatusTip('Edit settings')
        settingsAction.triggered.connect(self.edit_settings)

        helpAction = QAction(
            QIcon(os.path.join(resources_path, 'help_book24.png')),
            'User\'s Manual', self)
        helpAction.setShortcut('F1')
        helpAction.setStatusTip('User\'s Manual')
        helpAction.triggered.connect(self.show_user_manual_slot)

        helpSDAction = QAction(
            QIcon(os.path.join(resources_path, 'gear24.png')),
            'Settings Dialog', self)
        helpSDAction.setShortcut('Ctrl+F1')
        helpSDAction.setStatusTip('Settings Dialog Help')
        helpSDAction.triggered.connect(self.show_setting_dialog_help_slot)

        helpHKAction = QAction(
            QIcon(os.path.join(resources_path, 'rocket24.png')), 'Hotkeys',
            self)
        helpHKAction.setShortcut('Shift+F1')
        helpHKAction.setStatusTip('Hotkeys Help')
        helpHKAction.triggered.connect(self.show_hotkeys_help_slot)

        self.statusBar().showMessage('Ready')

        #--------------------------------------------
        #
        #    Main Menu
        #
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(openAction)
        fileMenu.addAction(saveAction)
        fileMenu.addAction(saveAsAction)
        fileMenu.addAction(exitAction)

        #--------------------------------------------
        #
        #    Options Menu
        #
        optionsMenu = menubar.addMenu('&Options')
        optionsMenu.addAction(settingsAction)

        #--------------------------------------------
        #
        #    Help Menu
        #
        helpMenu = menubar.addMenu('&Help')
        helpMenu.addAction(helpAction)
        helpMenu.addAction(helpSDAction)
        helpMenu.addAction(helpHKAction)

        #--------------------------------------------
        #
        #    Toolbar
        #
        toolbar = self.addToolBar('Exit')
        toolbar.addAction(exitAction)
        toolbar.addAction(openAction)
        toolbar.addAction(saveAction)
        toolbar.addAction(saveAsAction)
        toolbar.addAction(settingsAction)
        toolbar.addAction(helpAction)

        #----------------------------------------------------
        #
        #    Settings Dialog
        #

        #----------------------------------------------------
        #
        #    Components Table
        #
        self.CmpTabBox = QGroupBox('Components', self)
        self.CmpTabLayout = QVBoxLayout(self.CmpTabBox)
        self.CmpTabLayout.setContentsMargins(4, 10, 4, 4)
        self.CmpTabLayout.setSpacing(10)

        self.CmpTabLayout.setSizeConstraint(QVBoxLayout.SetMaximumSize)

        self.CmpTable = ComponentsTable(self)
        #self.CmpChooseButton = QPushButton('Choose', self)

        self.CmpTabLayout.addWidget(self.CmpTable)
        #self.CmpTabLayout.addWidget(self.CmpChooseButton)

        #----------------------------------------------------
        #
        #    Selector
        #
        self.SelectorBox = QGroupBox('Selector', self)
        self.SelectorLayout = QVBoxLayout(self.SelectorBox)
        self.SelectorLayout.setContentsMargins(4, 10, 4, 4)
        self.SelectorLayout.setSpacing(2)

        self.SelectorBtnWidget = QWidget(self)
        self.SelectorBtnLayout = QHBoxLayout(self.SelectorBtnWidget)
        self.SelectorBtnLayout.setContentsMargins(4, 10, 4, 4)
        self.SelectorBtnLayout.setSpacing(10)

        self.Selector = Selector(self)

        self.SelApplyButton = QPushButton('Apply', self)
        self.SelApplyButton.setToolTip(
            'Alt+S: Apply selection patterns to components')

        self.SelClearButton = QPushButton('Clear', self)
        self.SelClearButton.setToolTip('Alt+C: Clear selection patterns')

        self.SelTemplateButton = QPushButton('Use Component', self)
        self.SelTemplateButton.setToolTip(
            'Alt+T: Use Selected Component As Template')

        self.SelectorLayout.addWidget(self.Selector)
        self.SelectorBtnLayout.addWidget(self.SelTemplateButton)
        self.SelectorBtnLayout.addWidget(self.SelApplyButton)
        self.SelectorBtnLayout.addWidget(self.SelClearButton)
        self.SelectorLayout.addWidget(self.SelectorBtnWidget)

        self.shortcutSelApply = QShortcut(QKeySequence(Qt.ALT + Qt.Key_S),
                                          self)
        self.shortcutSelApply.activated.connect(self.Selector.apply_slot)

        self.shortcutSelClear = QShortcut(QKeySequence(Qt.ALT + Qt.Key_C),
                                          self)
        self.shortcutSelClear.activated.connect(self.Selector.clear_slot)

        self.shortcutSelTemplate = QShortcut(QKeySequence(Qt.ALT + Qt.Key_T),
                                             self)
        self.shortcutSelTemplate.activated.connect(
            self.Selector.use_comp_as_template_slot)

        #----------------------------------------------------
        #
        #    Inspector
        #
        self.Inspector = Inspector(self)
        self.FieldInspector = FieldInspector(self)

        self.InspectorBtnWidget = QWidget(self)
        self.InspectorBtnLayout = QHBoxLayout(self.InspectorBtnWidget)
        self.InspectorBtnLayout.setContentsMargins(4, 10, 4, 4)
        self.InspectorBtnLayout.setSpacing(10)

        self.AddUserProperty = QPushButton('Add Property', self)
        self.AddUserProperty.setToolTip('Alt+A: Add new user property')
        self.DeleteUserProperty = QPushButton('Delete Property', self)
        self.DeleteUserProperty.setToolTip('Alt+Delete: Delete user property')
        self.RenameUserProperty = QPushButton('Rename Property', self)
        self.RenameUserProperty.setToolTip('Alt+R: Rename user property')

        self.InspectorBox = QGroupBox('Inspector', self)
        self.InspectorSplit = QSplitter(Qt.Vertical, self)
        self.InspectorLayout = QVBoxLayout(self.InspectorBox)
        self.InspectorLayout.setContentsMargins(4, 10, 4, 4)
        self.InspectorLayout.setSpacing(2)

        self.InspectorSplit.addWidget(self.Inspector)
        self.InspectorSplit.addWidget(self.FieldInspector)
        self.InspectorLayout.addWidget(self.InspectorSplit)

        self.InspectorBtnLayout.addWidget(self.AddUserProperty)
        self.InspectorBtnLayout.addWidget(self.DeleteUserProperty)
        self.InspectorBtnLayout.addWidget(self.RenameUserProperty)

        self.InspectorLayout.addWidget(self.InspectorBtnWidget)

        self.shortcutSelApply = QShortcut(QKeySequence(Qt.ALT + Qt.Key_A),
                                          self)
        self.shortcutSelApply.activated.connect(self.add_user_property)

        self.shortcutSelApply = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Delete),
                                          self)
        self.shortcutSelApply.activated.connect(self.remove_user_property)

        self.shortcutSelApply = QShortcut(QKeySequence(Qt.ALT + Qt.Key_R),
                                          self)
        self.shortcutSelApply.activated.connect(self.rename_user_property)

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

        self.Splitter = QSplitter(self)
        self.Splitter.addWidget(self.CmpTabBox)
        self.Splitter.addWidget(self.SelectorBox)
        self.Splitter.addWidget(self.InspectorBox)

        self.centralWidget().layout().addWidget(self.Splitter)

        #----------------------------------------------------
        #
        #     Signals and Slots connections
        #
        self.CmpTable.cells_chosen.connect(self.Inspector.load_cmp)
        self.CmpTable.cells_chosen.connect(self.Selector.comp_template_slot)
        self.CmpTable.file_load.connect(self.file_loaded_slot)
        self.CmpTable.cmps_updated.connect(self.Selector.process_comps_slot)
        self.CmpTable.cmps_selected.connect(self.set_status_text_slot)

        self.SelApplyButton.clicked.connect(self.Selector.apply_slot)
        self.SelClearButton.clicked.connect(self.Selector.clear_slot)
        self.SelTemplateButton.clicked.connect(
            self.Selector.use_comp_as_template_slot)

        self.Selector.select_comps_signal.connect(
            self.CmpTable.select_comps_slot)

        self.Inspector.load_field.connect(self.FieldInspector.load_field_slot)
        self.Inspector.update_comps.connect(self.data_changed_slot)
        self.Inspector.update_comps.connect(self.CmpTable.update_cmp_list_slot)
        self.FieldInspector.data_changed.connect(self.data_changed_slot)
        CmpMgr.file_saved.connect(self.file_saved_slot)

        self.CmpTable.mouse_click.connect(self.mouse_change_tool)
        self.Inspector.mouse_click.connect(self.mouse_change_tool)
        self.FieldInspector.mouse_click.connect(self.mouse_change_tool)

        self.Inspector.header().sectionResized.connect(
            self.FieldInspector.column_resize)

        self.AddUserProperty.clicked.connect(self.add_user_property)
        self.DeleteUserProperty.clicked.connect(self.remove_user_property)
        self.RenameUserProperty.clicked.connect(self.rename_user_property)

        #----------------------------------------------------
        self.ToolList = []
        self.ToolList.append(self.CmpTable)
        self.ToolList.append(self.Selector)
        self.ToolList.append(self.Inspector)
        self.ToolList.append(self.FieldInspector)
        self.ToolIndex = 0

        #----------------------------------------------------
        #
        #    Window
        #
        self.setWindowTitle(self.PROGRAM_NAME)
        Settings = QSettings('kicad-tools', 'Schematic Component Manager')
        #print(Settings.allKeys())
        if Settings.contains('geometry'):
            self.restoreGeometry(Settings.value('geometry'))
        else:
            self.setGeometry(100, 100, 1024, 768)

        if Settings.contains('cmptable'):
            w0, w1 = Settings.value('cmptable')
            self.CmpTable.setColumnWidth(0, int(w0))
            self.CmpTable.setColumnWidth(1, int(w1))

        if Settings.contains('selector'):
            w0, w1 = Settings.value('selector')
            self.Selector.setColumnWidth(0, int(w0))
            self.Selector.setColumnWidth(1, int(w1))

        if Settings.contains('inspector'):
            w0, w1 = Settings.value('inspector')
            self.Inspector.setColumnWidth(0, int(w0))
            self.Inspector.setColumnWidth(1, int(w1))
            self.FieldInspector.setColumnWidth(0, int(w0))
            self.FieldInspector.setColumnWidth(1, int(w1))
            #self.Inspector.setColumnWidth( 2, int(w2) )

        if Settings.contains('splitter'):
            self.Splitter.restoreState(Settings.value('splitter'))

        if Settings.contains('inssplitter'):
            self.InspectorSplit.restoreState(Settings.value('inssplitter'))

        #----------------------------------------------------
        #
        #    Process command line arguments
        #
        if len(sys.argv) > 1:
            fname = sys.argv[1]
            if os.path.exists(fname):
                self.CmpTable.load_file(fname)
            else:
                print('E: input file "' + fname + '"does not exist')

        self.show()

    #---------------------------------------------------------------------------
    def closeEvent(self, event):
        Settings = QSettings('kicad-tools', 'Schematic Component Manager')
        Settings.setValue('geometry', self.saveGeometry())
        Settings.setValue(
            'cmptable',
            [self.CmpTable.columnWidth(0),
             self.CmpTable.columnWidth(1)])
        Settings.setValue(
            'selector',
            [self.Selector.columnWidth(0),
             self.Selector.columnWidth(1)])
        Settings.setValue(
            'inspector',
            [self.Inspector.columnWidth(0),
             self.Inspector.columnWidth(1)])
        Settings.setValue('splitter', self.Splitter.saveState())
        Settings.setValue('inssplitter', self.InspectorSplit.saveState())
        QWidget.closeEvent(self, event)

    #---------------------------------------------------------------------------
    def open_file(self):
        #filename = QFileDialog.getOpenFileName(self, 'Open schematic file', '/opt/cad/kicad', 'KiCad Schematic Files (*.sch)')
        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFile)
        dialog.setNameFilter('KiCad Schematic Files (*.sch)')

        filenames = []
        if dialog.exec_():
            filenames = dialog.selectedFiles()
        if len(filenames) == 0:
            return

        CmpMgr.set_curr_file_path(filenames[0])
        self.CmpTable.load_file(filenames[0])

    #---------------------------------------------------------------------------
    def save_file(self):
        self.FieldInspector.save_fields()
        self.Inspector.save_cmps()

        curr_file = CmpMgr.curr_file_path()
        message = 'Save File "' + curr_file + '"'
        print(message)
        self.statusBar().showMessage(message)

        CmpMgr.save_file(curr_file)

    #---------------------------------------------------------------------------
    def save_file_as(self):
        self.Inspector.save_cmps()
        self.FieldInspector.save_fields()
        filenames = QFileDialog.getSaveFileName(
            self, 'Save File As...', '', 'KiCad Schematic Files (*.sch)')

        if filenames[0] == '':
            return

        print('Save File As "' + filenames[0] + '"')
        CmpMgr.save_file(filenames[0])
        CmpMgr.set_curr_file_path(filenames[0])

    #---------------------------------------------------------------------------
    def file_loaded_slot(self):
        text = CmpMgr.curr_file_path()
        self.set_title(text)

    #---------------------------------------------------------------------------
    def data_changed_slot(self):
        text = CmpMgr.curr_file_path() + ' *'
        self.set_title(text)

    #---------------------------------------------------------------------------
    def file_saved_slot(self):
        text = CmpMgr.curr_file_path()
        self.set_title(text)

    #---------------------------------------------------------------------------
    def set_title(self, text=''):
        text = ' - ' + text if len(text) > 0 else ''
        self.setWindowTitle(self.PROGRAM_NAME + ' v' + VERSION + text)

    #---------------------------------------------------------------------------
    def set_status_text_slot(self, text):
        self.statusBar().showMessage(text)

    #---------------------------------------------------------------------------
    def edit_settings(self):
        print('edit settings')
        SettingsDialog = TSettingsDialog(self)
        SettingsDialog.resize(400, 400)
        SettingsDialog.Tabs.setMinimumWidth(800)
        SettingsDialog.show()

    #---------------------------------------------------------------------------
    def show_user_manual_slot(self):
        help = THelpForm(self, 'User\'s Manual', 'main.html')

    #---------------------------------------------------------------------------
    def show_setting_dialog_help_slot(self):
        help = THelpForm(self, 'Settings Dialog', 'settings.html')

    #---------------------------------------------------------------------------
    def show_hotkeys_help_slot(self):
        help = THelpForm(self, 'Hotkeys', 'hotkeys.html')
Beispiel #29
0
    def __init__(self, parent, view, row, link_delegate):
        QDialog.__init__(self, parent)
        self.normal_brush = QBrush(Qt.white)
        self.marked_brush = QBrush(Qt.lightGray)
        self.marked = None
        self.gui = parent
        self.splitter = QSplitter(self)
        self._l = l = QVBoxLayout(self)
        self.setLayout(l)
        l.addWidget(self.splitter)

        self.cover = CoverView(self)
        self.cover.resizeEvent = self.cover_view_resized
        self.cover.cover_changed.connect(self.cover_changed)
        self.cover_pixmap = None
        self.cover.sizeHint = self.details_size_hint
        self.splitter.addWidget(self.cover)

        self.details = Details(parent.book_details.book_info, self)
        self.details.page().setLinkDelegationPolicy(
            self.details.page().DelegateAllLinks)
        self.details.linkClicked.connect(self.link_clicked)
        s = self.details.page().settings()
        s.setAttribute(s.JavascriptEnabled, False)
        self.css = css()
        self.link_delegate = link_delegate
        self.details.setAttribute(Qt.WA_OpaquePaintEvent, False)
        palette = self.details.palette()
        self.details.setAcceptDrops(False)
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.details.page().setPalette(palette)

        self.c = QWidget(self)
        self.c.l = l2 = QGridLayout(self.c)
        self.c.setLayout(l2)
        l2.addWidget(self.details, 0, 0, 1, -1)
        self.splitter.addWidget(self.c)

        self.fit_cover = QCheckBox(_('Fit &cover within view'), self)
        self.fit_cover.setChecked(
            gprefs.get('book_info_dialog_fit_cover', True))
        l2.addWidget(self.fit_cover, l2.rowCount(), 0, 1, -1)
        self.previous_button = QPushButton(QIcon(I('previous.png')),
                                           _('&Previous'), self)
        self.previous_button.clicked.connect(self.previous)
        l2.addWidget(self.previous_button, l2.rowCount(), 0)
        self.next_button = QPushButton(QIcon(I('next.png')), _('&Next'), self)
        self.next_button.clicked.connect(self.next)
        l2.addWidget(self.next_button, l2.rowCount() - 1, 1)

        self.view = view
        self.current_row = None
        self.refresh(row)
        self.view.model().new_bookdisplay_data.connect(self.slave)
        self.fit_cover.stateChanged.connect(self.toggle_cover_fit)
        self.ns = QShortcut(QKeySequence('Alt+Right'), self)
        self.ns.activated.connect(self.next)
        self.ps = QShortcut(QKeySequence('Alt+Left'), self)
        self.ps.activated.connect(self.previous)
        self.next_button.setToolTip(
            _('Next [%s]') %
            unicode(self.ns.key().toString(QKeySequence.NativeText)))
        self.previous_button.setToolTip(
            _('Previous [%s]') %
            unicode(self.ps.key().toString(QKeySequence.NativeText)))

        geom = QCoreApplication.instance().desktop().availableGeometry(self)
        screen_height = geom.height() - 100
        screen_width = geom.width() - 100
        self.resize(max(int(screen_width / 2), 700), screen_height)
        saved_layout = gprefs.get('book_info_dialog_layout', None)
        if saved_layout is not None:
            try:
                self.restoreGeometry(saved_layout[0])
                self.splitter.restoreState(saved_layout[1])
            except Exception:
                pass
Beispiel #30
0
    def __init__(self, parent, view, row, link_delegate):
        QDialog.__init__(self, parent)
        self.normal_brush = QBrush(Qt.white)
        self.marked_brush = QBrush(Qt.lightGray)
        self.marked = None
        self.gui = parent
        self.splitter = QSplitter(self)
        self._l = l = QVBoxLayout(self)
        self.setLayout(l)
        l.addWidget(self.splitter)

        self.cover = CoverView(self)
        self.cover.resizeEvent = self.cover_view_resized
        self.cover.cover_changed.connect(self.cover_changed)
        self.cover_pixmap = None
        self.cover.sizeHint = self.details_size_hint
        self.splitter.addWidget(self.cover)

        self.details = Details(parent.book_details.book_info, self)
        self.details.page().setLinkDelegationPolicy(self.details.page().DelegateAllLinks)
        self.details.linkClicked.connect(self.link_clicked)
        s = self.details.page().settings()
        s.setAttribute(s.JavascriptEnabled, False)
        self.css = css()
        self.link_delegate = link_delegate
        self.details.setAttribute(Qt.WA_OpaquePaintEvent, False)
        palette = self.details.palette()
        self.details.setAcceptDrops(False)
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.details.page().setPalette(palette)

        self.c = QWidget(self)
        self.c.l = l2 = QGridLayout(self.c)
        self.c.setLayout(l2)
        l2.addWidget(self.details, 0, 0, 1, -1)
        self.splitter.addWidget(self.c)

        self.fit_cover = QCheckBox(_('Fit &cover within view'), self)
        self.fit_cover.setChecked(gprefs.get('book_info_dialog_fit_cover', True))
        l2.addWidget(self.fit_cover, l2.rowCount(), 0, 1, -1)
        self.previous_button = QPushButton(QIcon(I('previous.png')), _('&Previous'), self)
        self.previous_button.clicked.connect(self.previous)
        l2.addWidget(self.previous_button, l2.rowCount(), 0)
        self.next_button = QPushButton(QIcon(I('next.png')), _('&Next'), self)
        self.next_button.clicked.connect(self.next)
        l2.addWidget(self.next_button, l2.rowCount() - 1, 1)

        self.view = view
        self.current_row = None
        self.refresh(row)
        self.view.model().new_bookdisplay_data.connect(self.slave)
        self.fit_cover.stateChanged.connect(self.toggle_cover_fit)
        self.ns = QShortcut(QKeySequence('Alt+Right'), self)
        self.ns.activated.connect(self.next)
        self.ps = QShortcut(QKeySequence('Alt+Left'), self)
        self.ps.activated.connect(self.previous)
        self.next_button.setToolTip(_('Next [%s]')%
                unicode(self.ns.key().toString(QKeySequence.NativeText)))
        self.previous_button.setToolTip(_('Previous [%s]')%
                unicode(self.ps.key().toString(QKeySequence.NativeText)))

        geom = QCoreApplication.instance().desktop().availableGeometry(self)
        screen_height = geom.height() - 100
        screen_width = geom.width() - 100
        self.resize(max(int(screen_width/2), 700), screen_height)
        saved_layout = gprefs.get('book_info_dialog_layout', None)
        if saved_layout is not None:
            try:
                self.restoreGeometry(saved_layout[0])
                self.splitter.restoreState(saved_layout[1])
            except Exception:
                pass
Beispiel #31
0
 def register_shortcuts(self, window):
     self.__keyCtrlF = QShortcut(window)
     self.__keyCtrlF.setKey(Qt.CTRL + Qt.Key_F)
     self.__keyCtrlF.activated.connect(lambda: self.__activate_floating())
Beispiel #32
0
class MetadataSingleDialogBase(ResizableDialog):

    view_format = pyqtSignal(object, object)
    cc_two_column = tweaks['metadata_single_use_2_cols_for_custom_fields']
    one_line_comments_toolbar = False
    use_toolbutton_for_config_metadata = True

    def __init__(self, db, parent=None, editing_multiple=False):
        self.db = db
        self.changed = set()
        self.books_to_refresh = set()
        self.rows_to_refresh = set()
        self.metadata_before_fetch = None
        self.editing_multiple = editing_multiple
        self.comments_edit_state_at_apply = {}
        ResizableDialog.__init__(self, parent)

    def setupUi(self, *args):  # {{{
        self.resize(990, 670)

        self.download_shortcut = QShortcut(self)
        self.download_shortcut.setKey(QKeySequence('Ctrl+D',
            QKeySequence.PortableText))
        p = self.parent()
        if hasattr(p, 'keyboard'):
            kname = u'Interface Action: Edit Metadata (Edit Metadata) : menu action : download'
            sc = p.keyboard.keys_map.get(kname, None)
            if sc:
                self.download_shortcut.setKey(sc[0])
        self.swap_title_author_shortcut = s = QShortcut(self)
        s.setKey(QKeySequence('Alt+Down', QKeySequence.PortableText))

        self.button_box = bb = QDialogButtonBox(self)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)
        self.next_button = QPushButton(QIcon(I('forward.png')), _('Next'),
                self)
        self.next_button.setShortcut(QKeySequence('Alt+Right'))
        self.next_button.clicked.connect(self.next_clicked)
        self.prev_button = QPushButton(QIcon(I('back.png')), _('Previous'),
                self)
        self.prev_button.setShortcut(QKeySequence('Alt+Left'))

        self.button_box.addButton(self.prev_button, bb.ActionRole)
        self.button_box.addButton(self.next_button, bb.ActionRole)
        self.prev_button.clicked.connect(self.prev_clicked)
        bb.setStandardButtons(bb.Ok|bb.Cancel)
        bb.button(bb.Ok).setDefault(True)

        self.scroll_area = QScrollArea(self)
        self.scroll_area.setFrameShape(QScrollArea.NoFrame)
        self.scroll_area.setWidgetResizable(True)
        self.central_widget = QTabWidget(self)
        self.scroll_area.setWidget(self.central_widget)

        self.l = QVBoxLayout(self)
        self.setLayout(self.l)
        self.l.addWidget(self.scroll_area)
        ll = self.button_box_layout = QHBoxLayout()
        self.l.addLayout(ll)
        ll.addSpacing(10)
        ll.addWidget(self.button_box)

        self.setWindowIcon(QIcon(I('edit_input.png')))
        self.setWindowTitle(BASE_TITLE)

        self.create_basic_metadata_widgets()

        if len(self.db.custom_column_label_map):
            self.create_custom_metadata_widgets()
        self.comments_edit_state_at_apply = {self.comments:None}

        self.do_layout()
        geom = gprefs.get('metasingle_window_geometry3', None)
        if geom is not None:
            self.restoreGeometry(bytes(geom))
    # }}}

    def create_basic_metadata_widgets(self):  # {{{
        self.basic_metadata_widgets = []

        self.languages = LanguagesEdit(self)
        self.basic_metadata_widgets.append(self.languages)

        self.title = TitleEdit(self)
        self.title.textChanged.connect(self.update_window_title)
        self.deduce_title_sort_button = QToolButton(self)
        self.deduce_title_sort_button.setToolTip(
            _('Automatically create the title sort entry based on the current '
                'title entry.\nUsing this button to create title sort will '
                'change title sort from red to green.'))
        self.deduce_title_sort_button.setWhatsThis(
                self.deduce_title_sort_button.toolTip())
        self.title_sort = TitleSortEdit(self, self.title,
                self.deduce_title_sort_button, self.languages)
        self.basic_metadata_widgets.extend([self.title, self.title_sort])

        self.deduce_author_sort_button = b = RightClickButton(self)
        b.setToolTip('<p>' +
            _('Automatically create the author sort entry based on the current '
              'author entry. Using this button to create author sort will '
              'change author sort from red to green.  There is a menu of '
              'functions available under this button. Click and hold '
              'on the button to see it.') + '</p>')
        if isosx:
            # Workaround for https://bugreports.qt-project.org/browse/QTBUG-41017
            class Menu(QMenu):

                def mouseReleaseEvent(self, ev):
                    ac = self.actionAt(ev.pos())
                    if ac is not None:
                        ac.trigger()
                    return QMenu.mouseReleaseEvent(self, ev)
            b.m = m = Menu()
        else:
            b.m = m = QMenu()
        ac = m.addAction(QIcon(I('forward.png')), _('Set author sort from author'))
        ac2 = m.addAction(QIcon(I('back.png')), _('Set author from author sort'))
        ac3 = m.addAction(QIcon(I('user_profile.png')), _('Manage authors'))
        ac4 = m.addAction(QIcon(I('next.png')),
                _('Copy author to author sort'))
        ac5 = m.addAction(QIcon(I('previous.png')),
                _('Copy author sort to author'))

        b.setMenu(m)
        self.authors = AuthorsEdit(self, ac3)
        self.author_sort = AuthorSortEdit(self, self.authors, b, self.db, ac,
                ac2, ac4, ac5)
        self.basic_metadata_widgets.extend([self.authors, self.author_sort])

        self.swap_title_author_button = QToolButton(self)
        self.swap_title_author_button.setIcon(QIcon(I('swap.png')))
        self.swap_title_author_button.setToolTip(_(
            'Swap the author and title') + ' [%s]' % self.swap_title_author_shortcut.key().toString(QKeySequence.NativeText))
        self.swap_title_author_button.clicked.connect(self.swap_title_author)
        self.swap_title_author_shortcut.activated.connect(self.swap_title_author_button.click)

        self.manage_authors_button = QToolButton(self)
        self.manage_authors_button.setIcon(QIcon(I('user_profile.png')))
        self.manage_authors_button.setToolTip('<p>' + _(
            'Manage authors. Use to rename authors and correct '
            'individual author\'s sort values') + '</p>')
        self.manage_authors_button.clicked.connect(self.authors.manage_authors)

        self.series = SeriesEdit(self)
        self.clear_series_button = QToolButton(self)
        self.clear_series_button.setToolTip(
               _('Clear series'))
        self.clear_series_button.clicked.connect(self.series.clear)
        self.series_index = SeriesIndexEdit(self, self.series)
        self.basic_metadata_widgets.extend([self.series, self.series_index])

        self.formats_manager = FormatsManager(self, self.copy_fmt)
        # We want formats changes to be committed before title/author, as
        # otherwise we could have data loss if the title/author changed and the
        # user was trying to add an extra file from the old books directory.
        self.basic_metadata_widgets.insert(0, self.formats_manager)
        self.formats_manager.metadata_from_format_button.clicked.connect(
                self.metadata_from_format)
        self.formats_manager.cover_from_format_button.clicked.connect(
                self.cover_from_format)
        self.cover = Cover(self)
        self.cover.download_cover.connect(self.download_cover)
        self.basic_metadata_widgets.append(self.cover)

        self.comments = CommentsEdit(self, self.one_line_comments_toolbar)
        self.basic_metadata_widgets.append(self.comments)

        self.rating = RatingEdit(self)
        self.clear_ratings_button = QToolButton(self)
        self.clear_ratings_button.setToolTip(_('Clear rating'))
        self.clear_ratings_button.setIcon(QIcon(I('trash.png')))
        self.clear_ratings_button.clicked.connect(self.rating.zero)

        self.basic_metadata_widgets.append(self.rating)

        self.tags = TagsEdit(self)
        self.tags_editor_button = QToolButton(self)
        self.tags_editor_button.setToolTip(_('Open Tag Editor'))
        self.tags_editor_button.setIcon(QIcon(I('chapters.png')))
        self.tags_editor_button.clicked.connect(self.tags_editor)
        self.clear_tags_button = QToolButton(self)
        self.clear_tags_button.setToolTip(_('Clear all tags'))
        self.clear_tags_button.setIcon(QIcon(I('trash.png')))
        self.clear_tags_button.clicked.connect(self.tags.clear)
        self.basic_metadata_widgets.append(self.tags)

        self.identifiers = IdentifiersEdit(self)
        self.basic_metadata_widgets.append(self.identifiers)
        self.clear_identifiers_button = QToolButton(self)
        self.clear_identifiers_button.setIcon(QIcon(I('trash.png')))
        self.clear_identifiers_button.setToolTip(_('Clear Ids'))
        self.clear_identifiers_button.clicked.connect(self.identifiers.clear)
        self.paste_isbn_button = QToolButton(self)
        self.paste_isbn_button.setToolTip('<p>' +
                    _('Paste the contents of the clipboard into the '
                      'identifiers box prefixed with isbn:') + '</p>')
        self.paste_isbn_button.setIcon(QIcon(I('edit-paste.png')))
        self.paste_isbn_button.clicked.connect(self.identifiers.paste_isbn)

        self.publisher = PublisherEdit(self)
        self.basic_metadata_widgets.append(self.publisher)

        self.timestamp = DateEdit(self)
        self.pubdate = PubdateEdit(self)
        self.basic_metadata_widgets.extend([self.timestamp, self.pubdate])

        self.fetch_metadata_button = b = RightClickButton(self)
        # The following rigmarole is needed so that Qt gives the button the
        # same height as the other buttons in the dialog. There is no way to
        # center the text in a QToolButton with an icon, so we cant just set an
        # icon
        b.setIcon(QIcon(I('download-metadata.png')))
        b.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        b.setMinimumHeight(b.sizeHint().height())
        b.setIcon(QIcon())
        b.setText(_('&Download metadata')), b.setPopupMode(b.DelayedPopup)
        b.setToolTip(_('Download metadata for this book [%s]') % self.download_shortcut.key().toString(QKeySequence.NativeText))
        b.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed))
        self.fetch_metadata_button.clicked.connect(self.fetch_metadata)
        self.fetch_metadata_menu = m = QMenu(self.fetch_metadata_button)
        m.addAction(QIcon(I('edit-undo.png')), _('Undo last metadata download'), self.undo_fetch_metadata)
        self.fetch_metadata_button.setMenu(m)
        self.download_shortcut.activated.connect(self.fetch_metadata_button.click)
        font = self.fmb_font = QFont()
        font.setBold(True)
        self.fetch_metadata_button.setFont(font)

        if self.use_toolbutton_for_config_metadata:
            self.config_metadata_button = QToolButton(self)
            self.config_metadata_button.setIcon(QIcon(I('config.png')))
        else:
            self.config_metadata_button = QPushButton(self)
            self.config_metadata_button.setText(_('Configure download metadata'))
        self.config_metadata_button.setIcon(QIcon(I('config.png')))
        self.config_metadata_button.clicked.connect(self.configure_metadata)
        self.config_metadata_button.setToolTip(
            _('Change how calibre downloads metadata'))

    # }}}

    def create_custom_metadata_widgets(self):  # {{{
        self.custom_metadata_widgets_parent = w = QWidget(self)
        layout = QGridLayout()
        w.setLayout(layout)
        self.custom_metadata_widgets, self.__cc_spacers = \
            populate_metadata_page(layout, self.db, None, parent=w, bulk=False,
                two_column=self.cc_two_column)
        self.__custom_col_layouts = [layout]
        for widget in self.custom_metadata_widgets:
            if isinstance(widget, Comments):
                self.comments_edit_state_at_apply[widget] = None
    # }}}

    def set_custom_metadata_tab_order(self, before=None, after=None):  # {{{
        sto = QWidget.setTabOrder
        if getattr(self, 'custom_metadata_widgets', []):
            ans = self.custom_metadata_widgets
            for i in range(len(ans)-1):
                if before is not None and i == 0:
                    pass
                if len(ans[i+1].widgets) == 2:
                    sto(ans[i].widgets[-1], ans[i+1].widgets[1])
                else:
                    sto(ans[i].widgets[-1], ans[i+1].widgets[0])
                for c in range(2, len(ans[i].widgets), 2):
                    sto(ans[i].widgets[c-1], ans[i].widgets[c+1])
            if after is not None:
                pass
    # }}}

    def do_view_format(self, path, fmt):
        if path:
            self.view_format.emit(None, path)
        else:
            self.view_format.emit(self.book_id, fmt)

    def copy_fmt(self, fmt, f):
        self.db.copy_format_to(self.book_id, fmt, f, index_is_id=True)

    def do_layout(self):
        raise NotImplementedError()

    def __call__(self, id_):
        self.book_id = id_
        self.books_to_refresh = set([])
        self.metadata_before_fetch = None
        for widget in self.basic_metadata_widgets:
            widget.initialize(self.db, id_)
        for widget in getattr(self, 'custom_metadata_widgets', []):
            widget.initialize(id_)
        if callable(self.set_current_callback):
            self.set_current_callback(id_)
        # Commented out as it doesn't play nice with Next, Prev buttons
        # self.fetch_metadata_button.setFocus(Qt.OtherFocusReason)

    # Miscellaneous interaction methods {{{
    def update_window_title(self, *args):
        title = self.title.current_val
        if len(title) > 50:
            title = title[:50] + u'\u2026'
        self.setWindowTitle(BASE_TITLE + ' - ' +
                title + ' - ' +
                _(' [%(num)d of %(tot)d]')%dict(num=self.current_row+1,
                tot=len(self.row_list)))

    def swap_title_author(self, *args):
        title = self.title.current_val
        self.title.current_val = authors_to_string(self.authors.current_val)
        self.authors.current_val = string_to_authors(title)
        self.title_sort.auto_generate()
        self.author_sort.auto_generate()

    def tags_editor(self, *args):
        self.tags.edit(self.db, self.book_id)

    def metadata_from_format(self, *args):
        mi, ext = self.formats_manager.get_selected_format_metadata(self.db,
                self.book_id)
        if mi is not None:
            self.update_from_mi(mi)

    def get_pdf_cover(self):
        pdfpath = self.formats_manager.get_format_path(self.db, self.book_id,
                                                       'pdf')
        from calibre.gui2.metadata.pdf_covers import PDFCovers
        d = PDFCovers(pdfpath, parent=self)
        if d.exec_() == d.Accepted:
            cpath = d.cover_path
            if cpath:
                with open(cpath, 'rb') as f:
                    self.update_cover(f.read(), 'PDF')
        d.cleanup()

    def cover_from_format(self, *args):
        ext = self.formats_manager.get_selected_format()
        if ext is None:
            return
        if ext == 'pdf':
            return self.get_pdf_cover()
        try:
            mi, ext = self.formats_manager.get_selected_format_metadata(self.db,
                    self.book_id)
        except (IOError, OSError) as err:
            if getattr(err, 'errno', None) == errno.EACCES:  # Permission denied
                import traceback
                fname = err.filename if err.filename else 'file'
                error_dialog(self, _('Permission denied'),
                        _('Could not open %s. Is it being used by another'
                        ' program?')%fname, det_msg=traceback.format_exc(),
                        show=True)
                return
            raise
        if mi is None:
            return
        cdata = None
        if mi.cover and os.access(mi.cover, os.R_OK):
            cdata = open(mi.cover).read()
        elif mi.cover_data[1] is not None:
            cdata = mi.cover_data[1]
        if cdata is None:
            error_dialog(self, _('Could not read cover'),
                         _('Could not read cover from %s format')%ext).exec_()
            return
        self.update_cover(cdata, ext)

    def update_cover(self, cdata, fmt):
        orig = self.cover.current_val
        self.cover.current_val = cdata
        if self.cover.current_val is None:
            self.cover.current_val = orig
            return error_dialog(self, _('Could not read cover'),
                         _('The cover in the %s format is invalid')%fmt,
                         show=True)
            return

    def update_from_mi(self, mi, update_sorts=True, merge_tags=True, merge_comments=False):
        fw = self.focusWidget()
        if not mi.is_null('title'):
            self.title.set_value(mi.title)
            if update_sorts:
                self.title_sort.auto_generate()
        if not mi.is_null('authors'):
            self.authors.set_value(mi.authors)
        if not mi.is_null('author_sort'):
            self.author_sort.set_value(mi.author_sort)
        elif update_sorts and not mi.is_null('authors'):
            self.author_sort.auto_generate()
        if not mi.is_null('rating'):
            try:
                self.rating.set_value(mi.rating)
            except:
                pass
        if not mi.is_null('publisher'):
            self.publisher.set_value(mi.publisher)
        if not mi.is_null('tags'):
            old_tags = self.tags.current_val
            tags = mi.tags if mi.tags else []
            if old_tags and merge_tags:
                ltags, lotags = {t.lower() for t in tags}, {t.lower() for t in
                        old_tags}
                tags = [t for t in tags if t.lower() in ltags-lotags] + old_tags
            self.tags.set_value(tags)
        if not mi.is_null('identifiers'):
            current = self.identifiers.current_val
            current.update(mi.identifiers)
            self.identifiers.set_value(current)
        if not mi.is_null('pubdate'):
            self.pubdate.set_value(mi.pubdate)
        if not mi.is_null('series') and mi.series.strip():
            self.series.set_value(mi.series)
            if mi.series_index is not None:
                self.series_index.reset_original()
                self.series_index.set_value(float(mi.series_index))
        if not mi.is_null('languages'):
            langs = [canonicalize_lang(x) for x in mi.languages]
            langs = [x for x in langs if x is not None]
            if langs:
                self.languages.set_value(langs)
        if mi.comments and mi.comments.strip():
            val = mi.comments
            if val and merge_comments:
                cval = self.comments.current_val
                if cval:
                    val = merge_two_comments(cval, val)
            self.comments.set_value(val)
        if fw is not None:
            fw.setFocus(Qt.OtherFocusReason)

    def fetch_metadata(self, *args):
        d = FullFetch(self.cover.pixmap(), self)
        ret = d.start(title=self.title.current_val, authors=self.authors.current_val,
                identifiers=self.identifiers.current_val)
        if ret == d.Accepted:
            self.metadata_before_fetch = {f:getattr(self, f).current_val for f in fetched_fields}
            from calibre.ebooks.metadata.sources.prefs import msprefs
            mi = d.book
            dummy = Metadata(_('Unknown'))
            for f in msprefs['ignore_fields']:
                if ':' not in f:
                    setattr(mi, f, getattr(dummy, f))
            if mi is not None:
                pd = mi.pubdate
                if pd is not None:
                    # Put the downloaded published date into the local timezone
                    # as we discard time info and the date is timezone
                    # invariant. This prevents the as_local_timezone() call in
                    # update_from_mi from changing the pubdate
                    mi.pubdate = datetime(pd.year, pd.month, pd.day,
                            tzinfo=local_tz)
                self.update_from_mi(mi, merge_comments=msprefs['append_comments'])
            if d.cover_pixmap is not None:
                self.metadata_before_fetch['cover'] = self.cover.current_val
                self.cover.current_val = pixmap_to_data(d.cover_pixmap)

    def undo_fetch_metadata(self):
        if self.metadata_before_fetch is None:
            return error_dialog(self, _('No downloaded metadata'), _(
                'There is no downloaded metadata to undo'), show=True)
        for field, val in self.metadata_before_fetch.iteritems():
            getattr(self, field).current_val = val
        self.metadata_before_fetch = None

    def configure_metadata(self):
        from calibre.gui2.preferences import show_config_widget
        gui = self.parent()
        show_config_widget('Sharing', 'Metadata download', parent=self,
                gui=gui, never_shutdown=True)

    def download_cover(self, *args):
        from calibre.gui2.metadata.single_download import CoverFetch
        d = CoverFetch(self.cover.pixmap(), self)
        ret = d.start(self.title.current_val, self.authors.current_val,
                self.identifiers.current_val)
        if ret == d.Accepted:
            if d.cover_pixmap is not None:
                self.cover.current_val = pixmap_to_data(d.cover_pixmap)

    # }}}

    def to_book_metadata(self):
        mi = Metadata(_('Unknown'))
        if self.db is None:
            return mi
        mi.set_all_user_metadata(self.db.field_metadata.custom_field_metadata())
        for widget in self.basic_metadata_widgets:
            widget.apply_to_metadata(mi)
        for widget in getattr(self, 'custom_metadata_widgets', []):
            widget.apply_to_metadata(mi)
        return mi

    def apply_changes(self):
        self.changed.add(self.book_id)
        if self.db is None:
            # break_cycles has already been called, don't know why this should
            # happen but a user reported it
            return True
        self.comments_edit_state_at_apply = {w:w.tab for w in self.comments_edit_state_at_apply}
        for widget in self.basic_metadata_widgets:
            try:
                if hasattr(widget, 'validate_for_commit'):
                    title, msg, det_msg = widget.validate_for_commit()
                    if title is not None:
                        error_dialog(self, title, msg, det_msg=det_msg, show=True)
                        return False
                widget.commit(self.db, self.book_id)
                self.books_to_refresh |= getattr(widget, 'books_to_refresh', set())
            except (IOError, OSError) as err:
                if getattr(err, 'errno', None) == errno.EACCES:  # Permission denied
                    import traceback
                    fname = getattr(err, 'filename', None)
                    p = 'Locked file: %s\n\n'%fname if fname else ''
                    error_dialog(self, _('Permission denied'),
                            _('Could not change the on disk location of this'
                                ' book. Is it open in another program?'),
                            det_msg=p+traceback.format_exc(), show=True)
                    return False
                raise
        for widget in getattr(self, 'custom_metadata_widgets', []):
            self.books_to_refresh |= widget.commit(self.book_id)

        self.db.commit()
        rows = self.db.refresh_ids(list(self.books_to_refresh))
        if rows:
            self.rows_to_refresh |= set(rows)

        return True

    def accept(self):
        self.save_state()
        if not self.apply_changes():
            return
        if self.editing_multiple and self.current_row != len(self.row_list) - 1:
            num = len(self.row_list) - 1 - self.current_row
            from calibre.gui2 import question_dialog
            if not question_dialog(
                    self, _('Are you sure?'),
                    _('There are still %d more books to edit in this set.'
                      ' Are you sure you want to stop? Use the Next button'
                      ' instead of the OK button to move through books in the set.') % num,
                    yes_text=_('&Stop editing'), no_text=_('&Continue editing'),
                    yes_icon='dot_red.png', no_icon='dot_green.png',
                    default_yes=False, skip_dialog_name='edit-metadata-single-confirm-ok-on-multiple'):
                return self.do_one(delta=1, apply_changes=False)
        ResizableDialog.accept(self)

    def reject(self):
        self.save_state()
        ResizableDialog.reject(self)

    def save_state(self):
        try:
            gprefs['metasingle_window_geometry3'] = bytearray(self.saveGeometry())
        except:
            # Weird failure, see https://bugs.launchpad.net/bugs/995271
            import traceback
            traceback.print_exc()

    # Dialog use methods {{{
    def start(self, row_list, current_row, view_slot=None,
            set_current_callback=None):
        self.row_list = row_list
        self.current_row = current_row
        if view_slot is not None:
            self.view_format.connect(view_slot)
        self.set_current_callback = set_current_callback
        self.do_one(apply_changes=False)
        ret = self.exec_()
        self.break_cycles()
        return ret

    def next_clicked(self):
        if not self.apply_changes():
            return
        self.do_one(delta=1, apply_changes=False)

    def prev_clicked(self):
        if not self.apply_changes():
            return
        self.do_one(delta=-1, apply_changes=False)

    def do_one(self, delta=0, apply_changes=True):
        if apply_changes:
            self.apply_changes()
        self.current_row += delta
        self.update_window_title()
        prev = next_ = None
        if self.current_row > 0:
            prev = self.db.title(self.row_list[self.current_row-1])
        if self.current_row < len(self.row_list) - 1:
            next_ = self.db.title(self.row_list[self.current_row+1])

        if next_ is not None:
            tip = (_('Save changes and edit the metadata of %s')+
                    ' [Alt+Right]')%next_
            self.next_button.setToolTip(tip)
        self.next_button.setEnabled(next_ is not None)
        if prev is not None:
            tip = (_('Save changes and edit the metadata of %s')+
                    ' [Alt+Left]')%prev
            self.prev_button.setToolTip(tip)
        self.prev_button.setEnabled(prev is not None)
        self.button_box.button(self.button_box.Ok).setDefault(True)
        self.button_box.button(self.button_box.Ok).setFocus(Qt.OtherFocusReason)
        self(self.db.id(self.row_list[self.current_row]))
        for w, state in self.comments_edit_state_at_apply.iteritems():
            if state == 'code':
                w.tab = 'code'

    def break_cycles(self):
        # Break any reference cycles that could prevent python
        # from garbage collecting this dialog
        self.set_current_callback = self.db = None
        self.metadata_before_fetch = None
        def disconnect(signal):
            try:
                signal.disconnect()
            except:
                pass  # Fails if view format was never connected
        disconnect(self.view_format)
        for b in ('next_button', 'prev_button'):
            x = getattr(self, b, None)
            if x is not None:
                disconnect(x.clicked)
        for widget in self.basic_metadata_widgets:
            bc = getattr(widget, 'break_cycles', None)
            if bc is not None and callable(bc):
                bc()
        for widget in getattr(self, 'custom_metadata_widgets', []):
            widget.break_cycles()
Beispiel #33
0
class FloatingWindow(QTWSPlugin):
    def __init__(self, config):
        super().__init__("FloatingWindow")
        self.window = None
        self.config = config
        self.floating_toggle = None
        self.is_window_floating = False
        self.message_box_shown = False

    def window_setup(self, window: QTWSMainWindow):
        self.window = window

    def register_shortcuts(self, window):
        self.__keyCtrlF = QShortcut(window)
        self.__keyCtrlF.setKey(Qt.CTRL + Qt.Key_F)
        self.__keyCtrlF.activated.connect(lambda: self.__activate_floating())

    def add_menu_items(self, menu: QMenu):
        self.floating_toggle = None
        self.floating_toggle = QAction(QIcon.fromTheme("file-zoom-out"),
                                       "Enable floating window")

        self.floating_toggle.triggered.connect(
            lambda: self.__activate_floating())
        menu.addAction(self.floating_toggle)

    def close_event(self, window: QTWSMainWindow, event):
        if self.is_window_floating:
            self.__deactivate_floating()
            event.ignore()

    def __activate_floating(self):
        if self.is_window_floating:
            return

        self.screen = QApplication.instance().primaryScreen().geometry()

        self.previous_x = self.window.x()
        self.previous_y = self.window.y()

        self.previous_width = self.window.width()
        self.previous_height = self.window.height()
        self.previous_max_width = self.window.maximumWidth()
        self.previous_max_height = self.window.maximumHeight()

        self.previously_maximized = self.window.isMaximized()
        self.previously_fullscreen = self.window.isFullScreen()

        self.window.set_always_on_top(True)
        self.window.setMaximumWidth(self.screen.width() / 2)
        self.window.setMaximumHeight(self.screen.height() / 2)

        self.window.resize(self.screen.width() / 3, self.screen.height() / 3)
        self.window.set_mouse_enter_callback(lambda e: self.__on_focus(e))
        self.window.set_maximizable(False)
        self.__on_focus(None)
        self.is_window_floating = True

        if not self.message_box_shown:
            box = QMessageBox()
            box.setWindowTitle("Floating mode activated")
            box.setText("Just close the window to disable the floating mode.")
            box.setIcon(QMessageBox.Information)
            box.exec_()
            self.message_box_shown = True

    def __deactivate_floating(self):
        self.window.setMaximumWidth(self.previous_max_width)
        self.window.setMaximumHeight(self.previous_max_height)

        self.window.resize(self.previous_width, self.previous_height)
        self.window.move(self.previous_x, self.previous_y)

        if not self.config.always_on_top:
            self.window.set_always_on_top(False)

        self.window.set_maximizable(True)
        self.window.set_mouse_enter_callback(None)
        self.is_window_floating = False

        self.window.showNormal()
        if self.previously_maximized:
            self.window.showMaximized()

        if self.previously_fullscreen:
            self.window.activate_fullscreen()

    def __on_focus(self, event):
        self.screen = QApplication.instance().primaryScreen().geometry()

        y = self.screen.height() - self.window.height()
        if event is not None and event.globalX() < self.window.width():
            x = self.screen.width() - self.window.width()
            self.window.move(x, y)
        else:
            self.window.move(0, y)
Beispiel #34
0
    def __init__(self):
        QWidget.__init__(self, None)
        # Set pixmaps resource before Main Window initialized
        self._resource = os.path.join(ctx.consts.theme_dir, ctx.flags.theme,
                                      ctx.consts.pixmaps_resource_file)
        if os.path.exists(self._resource):
            resource = QResource()
            resource.registerResource(self._resource)
        else:
            raise yali.Error, _("Pixmaps resources file doesn't exists")

        self.ui = Ui_YaliMain()
        self.ui.setupUi(self)

        self.font = 10
        self.animation_type = None

        self.screens = None
        self.screens_content = None

        self.pds_helper = HelpWidget(self.ui.scrollAreaWidgetContents)

        # shortcut to open help
        self.help_shortcut = QShortcut(QKeySequence(Qt.Key_F1), self)

        # shortcut to open debug window
        #self.debugShortCut = QtWidgets.QShortcut(QtWidgets.QKeySequence(Qt.Key_F2),self)

        # something funny
        self.tetris_shortcut = QShortcut(QKeySequence(Qt.Key_F6), self)
        self.cursor_shortcut = QShortcut(QKeySequence(Qt.Key_F7), self)
        self.theme_shortcut = QShortcut(QKeySequence(Qt.Key_F8), self)

        # shortcut to open a console
        self.console_shortcut = QShortcut(QKeySequence(Qt.Key_F11), self)

        # set style
        self._style = os.path.join(ctx.consts.theme_dir, ctx.flags.theme,
                                   ctx.consts.style_file)
        if os.path.exists(self._style):
            self.updateStyle()
        else:
            raise yali.Error, _("Style file doesn't exists")

        # set screens content
        release_file = os.path.join(ctx.consts.branding_dir,
                                    ctx.flags.branding,
                                    ctx.consts.release_file)
        if os.path.exists(release_file):
            self.screens_content = yali.util.parse_branding_screens(
                release_file)
        else:
            raise yali.Error, _("Release file doesn't exists")

        # move one step at a time
        self.step_increment = 1

        # ToolButton Popup Menu
        self.menu = QMenu()
        self.shutdown = self.menu.addAction(
            QIcon(QPixmap(":/images/system-shutdown.png")),
            _("Turn Off Computer"))
        self.reboot = self.menu.addAction(
            QIcon(QPixmap(":/images/system-reboot.png")),
            _("Restart Computer"))
        self.restart = self.menu.addAction(
            QIcon(QPixmap(":/images/system-yali-reboot.png")),
            _("Restart YALI"))
        #self.menu.setDefaultAction(self.shutdown)
        self.ui.system_menu.setMenu(self.menu)
        self.ui.system_menu.setDefaultAction(self.shutdown)

        # Main Slots
        self.help_shortcut.activated.connect(self.pds_helper.toggleHelp)
        #self.debugShortCut.activated.connect(self.toggleDebug)
        self.console_shortcut.activated.connect(self.toggleConsole)
        self.cursor_shortcut.activated.connect(self.toggleCursor)
        self.theme_shortcut.activated.connect(self.toggleTheme)
        self.tetris_shortcut.activated.connect(self.toggleTetris)
        self.ui.buttonNext.clicked.connect(self.slotNext)
        self.ui.buttonBack.clicked.connect(self.slotBack)
        self.ui.toggleHelp.clicked.connect(self.pds_helper.toggleHelp)
        if not ctx.flags.install_type == ctx.STEP_FIRST_BOOT:
            self.ui.releaseNotes.clicked.connect(self.showReleaseNotes)
        else:
            self.ui.releaseNotes.hide()
        self.menu.triggered[QAction].connect(self.slotMenu)

        self.cmb = _("right")
        self.dont_ask_again = False
        self.terminal = None
        self.tetris = None

        self.ui.helpContentFrame.hide()

        self.effect = QGraphicsOpacityEffect(self)
        self.ui.mainStack.setGraphicsEffect(self.effect)
        self.effect.setOpacity(1.0)

        self.anime = QTimer(self)
        self.anime.timeout.connect(self.animate)
Beispiel #35
0
class BookInfo(QDialog):

    closed = pyqtSignal(object)

    def __init__(self, parent, view, row, link_delegate):
        QDialog.__init__(self, parent)
        self.normal_brush = QBrush(Qt.white)
        self.marked_brush = QBrush(Qt.lightGray)
        self.marked = None
        self.gui = parent
        self.splitter = QSplitter(self)
        self._l = l = QVBoxLayout(self)
        self.setLayout(l)
        l.addWidget(self.splitter)

        self.cover = CoverView(self)
        self.cover.resizeEvent = self.cover_view_resized
        self.cover.cover_changed.connect(self.cover_changed)
        self.cover_pixmap = None
        self.cover.sizeHint = self.details_size_hint
        self.splitter.addWidget(self.cover)

        self.details = QWebView(self)
        self.details.sizeHint = self.details_size_hint
        self.details.page().setLinkDelegationPolicy(
            self.details.page().DelegateAllLinks)
        self.details.linkClicked.connect(self.link_clicked)
        s = self.details.page().settings()
        s.setAttribute(s.JavascriptEnabled, False)
        self.css = css()
        self.link_delegate = link_delegate
        self.details.setAttribute(Qt.WA_OpaquePaintEvent, False)
        palette = self.details.palette()
        self.details.setAcceptDrops(False)
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.details.page().setPalette(palette)

        self.c = QWidget(self)
        self.c.l = l2 = QGridLayout(self.c)
        self.c.setLayout(l2)
        l2.addWidget(self.details, 0, 0, 1, -1)
        self.splitter.addWidget(self.c)

        self.fit_cover = QCheckBox(_('Fit &cover within view'), self)
        self.fit_cover.setChecked(
            gprefs.get('book_info_dialog_fit_cover', True))
        l2.addWidget(self.fit_cover, l2.rowCount(), 0, 1, -1)
        self.previous_button = QPushButton(QIcon(I('previous.png')),
                                           _('&Previous'), self)
        self.previous_button.clicked.connect(self.previous)
        l2.addWidget(self.previous_button, l2.rowCount(), 0)
        self.next_button = QPushButton(QIcon(I('next.png')), _('&Next'), self)
        self.next_button.clicked.connect(self.next)
        l2.addWidget(self.next_button, l2.rowCount() - 1, 1)

        self.view = view
        self.current_row = None
        self.refresh(row)
        self.view.model().new_bookdisplay_data.connect(self.slave)
        self.fit_cover.stateChanged.connect(self.toggle_cover_fit)
        self.ns = QShortcut(QKeySequence('Alt+Right'), self)
        self.ns.activated.connect(self.next)
        self.ps = QShortcut(QKeySequence('Alt+Left'), self)
        self.ps.activated.connect(self.previous)
        self.next_button.setToolTip(
            _('Next [%s]') %
            unicode(self.ns.key().toString(QKeySequence.NativeText)))
        self.previous_button.setToolTip(
            _('Previous [%s]') %
            unicode(self.ps.key().toString(QKeySequence.NativeText)))

        geom = QCoreApplication.instance().desktop().availableGeometry(self)
        screen_height = geom.height() - 100
        screen_width = geom.width() - 100
        self.resize(max(int(screen_width / 2), 700), screen_height)
        saved_layout = gprefs.get('book_info_dialog_layout', None)
        if saved_layout is not None:
            try:
                self.restoreGeometry(saved_layout[0])
                self.splitter.restoreState(saved_layout[1])
            except Exception:
                pass

    def link_clicked(self, qurl):
        link = unicode(qurl.toString(QUrl.None))
        self.link_delegate(link)

    def done(self, r):
        saved_layout = (bytearray(self.saveGeometry()),
                        bytearray(self.splitter.saveState()))
        gprefs.set('book_info_dialog_layout', saved_layout)
        ret = QDialog.done(self, r)
        self.view.model().new_bookdisplay_data.disconnect(self.slave)
        self.view = self.link_delegate = self.gui = None
        self.closed.emit(self)
        return ret

    def cover_changed(self, data):
        if self.current_row is not None:
            id_ = self.view.model().id(self.current_row)
            self.view.model().db.set_cover(id_, data)
        if self.gui.cover_flow:
            self.gui.cover_flow.dataChanged()
        ci = self.view.currentIndex()
        if ci.isValid():
            self.view.model().current_changed(ci, ci)

    def details_size_hint(self):
        return QSize(350, 550)

    def toggle_cover_fit(self, state):
        gprefs.set('book_info_dialog_fit_cover', self.fit_cover.isChecked())
        self.resize_cover()

    def cover_view_resized(self, event):
        QTimer.singleShot(1, self.resize_cover)

    def slave(self, mi):
        self.refresh(mi.row_number, mi)

    def move(self, delta=1):
        idx = self.view.currentIndex()
        if idx.isValid():
            m = self.view.model()
            ni = m.index(idx.row() + delta, idx.column())
            if ni.isValid():
                if self.view.isVisible():
                    self.view.scrollTo(ni)
                self.view.setCurrentIndex(ni)

    def next(self):
        self.move()

    def previous(self):
        self.move(-1)

    def resize_cover(self):
        if self.cover_pixmap is None:
            return
        pixmap = self.cover_pixmap
        if self.fit_cover.isChecked():
            scaled, new_width, new_height = fit_image(
                pixmap.width(), pixmap.height(),
                self.cover.size().width() - 10,
                self.cover.size().height() - 10)
            if scaled:
                pixmap = pixmap.scaled(new_width, new_height,
                                       Qt.KeepAspectRatio,
                                       Qt.SmoothTransformation)
        self.cover.set_pixmap(pixmap)
        self.update_cover_tooltip()

    def update_cover_tooltip(self):
        tt = ''
        if self.marked:
            tt = _('This book is marked') if self.marked in {
                True, 'true'
            } else _('This book is marked as: %s') % self.marked
            tt += '\n\n'
        if self.cover_pixmap is not None:
            sz = self.cover_pixmap.size()
            tt += _('Cover size: %(width)d x %(height)d') % dict(
                width=sz.width(), height=sz.height())
        self.cover.setToolTip(tt)

    def refresh(self, row, mi=None):
        if isinstance(row, QModelIndex):
            row = row.row()
        if row == self.current_row and mi is None:
            return
        mi = self.view.model().get_book_display_info(row) if mi is None else mi
        if mi is None:
            # Indicates books was deleted from library, or row numbers have
            # changed
            return

        self.previous_button.setEnabled(False if row == 0 else True)
        self.next_button.setEnabled(False if row ==
                                    self.view.model().rowCount(QModelIndex()) -
                                    1 else True)
        self.current_row = row
        self.setWindowTitle(mi.title)
        self.cover_pixmap = QPixmap.fromImage(mi.cover_data[1])
        self.resize_cover()
        html = render_html(mi, self.css, True, self, all_fields=True)
        self.details.setHtml(html)
        self.marked = mi.marked
        self.cover.setBackgroundBrush(
            self.marked_brush if mi.marked else self.normal_brush)
        self.update_cover_tooltip()
Beispiel #36
0
class BookInfo(QDialog):

    closed = pyqtSignal(object)

    def __init__(self, parent, view, row, link_delegate):
        QDialog.__init__(self, parent)
        self.normal_brush = QBrush(Qt.white)
        self.marked_brush = QBrush(Qt.lightGray)
        self.marked = None
        self.gui = parent
        self.splitter = QSplitter(self)
        self._l = l = QVBoxLayout(self)
        self.setLayout(l)
        l.addWidget(self.splitter)

        self.cover = CoverView(self, show_size=gprefs['bd_overlay_cover_size'])
        self.cover.resizeEvent = self.cover_view_resized
        self.cover.cover_changed.connect(self.cover_changed)
        self.cover_pixmap = None
        self.cover.sizeHint = self.details_size_hint
        self.splitter.addWidget(self.cover)

        self.details = Details(parent.book_details.book_info, self)
        self.details.anchor_clicked.connect(self.on_link_clicked)
        self.link_delegate = link_delegate
        self.details.setAttribute(Qt.WA_OpaquePaintEvent, False)
        palette = self.details.palette()
        self.details.setAcceptDrops(False)
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.details.setPalette(palette)

        self.c = QWidget(self)
        self.c.l = l2 = QGridLayout(self.c)
        l2.setContentsMargins(0, 0, 0, 0)
        self.c.setLayout(l2)
        l2.addWidget(self.details, 0, 0, 1, -1)
        self.splitter.addWidget(self.c)

        self.fit_cover = QCheckBox(_('Fit &cover within view'), self)
        self.fit_cover.setChecked(
            gprefs.get('book_info_dialog_fit_cover', True))
        self.hl = hl = QHBoxLayout()
        hl.setContentsMargins(0, 0, 0, 0)
        l2.addLayout(hl, l2.rowCount(), 0, 1, -1)
        hl.addWidget(self.fit_cover), hl.addStretch()
        self.clabel = QLabel(
            '<div style="text-align: right"><a href="calibre:conf" title="{}" style="text-decoration: none">{}</a>'
            .format(_('Configure this view'), _('Configure')))
        self.clabel.linkActivated.connect(self.configure)
        hl.addWidget(self.clabel)
        self.previous_button = QPushButton(QIcon(I('previous.png')),
                                           _('&Previous'), self)
        self.previous_button.clicked.connect(self.previous)
        l2.addWidget(self.previous_button, l2.rowCount(), 0)
        self.next_button = QPushButton(QIcon(I('next.png')), _('&Next'), self)
        self.next_button.clicked.connect(self.next)
        l2.addWidget(self.next_button, l2.rowCount() - 1, 1)

        self.view = view
        self.current_row = None
        self.refresh(row)
        self.view.model().new_bookdisplay_data.connect(self.slave)
        self.fit_cover.stateChanged.connect(self.toggle_cover_fit)
        self.ns = QShortcut(QKeySequence('Alt+Right'), self)
        self.ns.activated.connect(self.next)
        self.ps = QShortcut(QKeySequence('Alt+Left'), self)
        self.ps.activated.connect(self.previous)
        self.next_button.setToolTip(
            _('Next [%s]') %
            unicode_type(self.ns.key().toString(QKeySequence.NativeText)))
        self.previous_button.setToolTip(
            _('Previous [%s]') %
            unicode_type(self.ps.key().toString(QKeySequence.NativeText)))

        geom = QCoreApplication.instance().desktop().availableGeometry(self)
        screen_height = geom.height() - 100
        screen_width = geom.width() - 100
        self.resize(max(int(screen_width / 2), 700), screen_height)
        saved_layout = gprefs.get('book_info_dialog_layout', None)
        if saved_layout is not None:
            try:
                self.restoreGeometry(saved_layout[0])
                self.splitter.restoreState(saved_layout[1])
            except Exception:
                pass

    def configure(self):
        d = Configure(get_gui().current_db, self)
        if d.exec_() == d.Accepted:
            if self.current_row is not None:
                mi = self.view.model().get_book_display_info(self.current_row)
                if mi is not None:
                    self.refresh(self.current_row, mi=mi)

    def on_link_clicked(self, qurl):
        link = unicode_type(qurl.toString(NO_URL_FORMATTING))
        self.link_delegate(link)

    def done(self, r):
        saved_layout = (bytearray(self.saveGeometry()),
                        bytearray(self.splitter.saveState()))
        gprefs.set('book_info_dialog_layout', saved_layout)
        ret = QDialog.done(self, r)
        self.view.model().new_bookdisplay_data.disconnect(self.slave)
        self.view = self.link_delegate = self.gui = None
        self.closed.emit(self)
        return ret

    def cover_changed(self, data):
        if self.current_row is not None:
            id_ = self.view.model().id(self.current_row)
            self.view.model().db.set_cover(id_, data)
        self.gui.refresh_cover_browser()
        ci = self.view.currentIndex()
        if ci.isValid():
            self.view.model().current_changed(ci, ci)

    def details_size_hint(self):
        return QSize(350, 550)

    def toggle_cover_fit(self, state):
        gprefs.set('book_info_dialog_fit_cover', self.fit_cover.isChecked())
        self.resize_cover()

    def cover_view_resized(self, event):
        QTimer.singleShot(1, self.resize_cover)

    def slave(self, mi):
        self.refresh(mi.row_number, mi)

    def move(self, delta=1):
        idx = self.view.currentIndex()
        if idx.isValid():
            m = self.view.model()
            ni = m.index(idx.row() + delta, idx.column())
            if ni.isValid():
                if self.view.isVisible():
                    self.view.scrollTo(ni)
                self.view.setCurrentIndex(ni)

    def next(self):
        self.move()

    def previous(self):
        self.move(-1)

    def resize_cover(self):
        if self.cover_pixmap is None:
            return
        pixmap = self.cover_pixmap
        if self.fit_cover.isChecked():
            scaled, new_width, new_height = fit_image(
                pixmap.width(), pixmap.height(),
                self.cover.size().width() - 10,
                self.cover.size().height() - 10)
            if scaled:
                try:
                    dpr = self.devicePixelRatioF()
                except AttributeError:
                    dpr = self.devicePixelRatio()
                pixmap = pixmap.scaled(int(dpr * new_width),
                                       int(dpr * new_height),
                                       Qt.KeepAspectRatio,
                                       Qt.SmoothTransformation)
                pixmap.setDevicePixelRatio(dpr)
        self.cover.set_pixmap(pixmap)
        self.update_cover_tooltip()

    def update_cover_tooltip(self):
        tt = ''
        if self.marked:
            tt = _('This book is marked') if self.marked in {
                True, 'true'
            } else _('This book is marked as: %s') % self.marked
            tt += '\n\n'
        if self.cover_pixmap is not None:
            sz = self.cover_pixmap.size()
            tt += _('Cover size: %(width)d x %(height)d pixels') % dict(
                width=sz.width(), height=sz.height())
        self.cover.setToolTip(tt)
        self.cover.pixmap_size = sz.width(), sz.height()

    def refresh(self, row, mi=None):
        if isinstance(row, QModelIndex):
            row = row.row()
        if row == self.current_row and mi is None:
            return
        mi = self.view.model().get_book_display_info(row) if mi is None else mi
        if mi is None:
            # Indicates books was deleted from library, or row numbers have
            # changed
            return

        self.previous_button.setEnabled(False if row == 0 else True)
        self.next_button.setEnabled(False if row ==
                                    self.view.model().rowCount(QModelIndex()) -
                                    1 else True)
        self.current_row = row
        self.setWindowTitle(mi.title)
        self.cover_pixmap = QPixmap.fromImage(mi.cover_data[1])
        try:
            dpr = self.devicePixelRatioF()
        except AttributeError:
            dpr = self.devicePixelRatio()
        self.cover_pixmap.setDevicePixelRatio(dpr)
        self.resize_cover()
        html = render_html(mi,
                           True,
                           self,
                           pref_name='popup_book_display_fields')
        set_html(mi, html, self.details)
        self.marked = mi.marked
        self.cover.setBackgroundBrush(
            self.marked_brush if mi.marked else self.normal_brush)
        self.update_cover_tooltip()
Beispiel #37
0
 def register_shortcuts(self, window):
     self.__keyCtrlP = QShortcut(window)
     self.__keyCtrlP.setKey(Qt.CTRL + Qt.Key_P)
     self.__keyCtrlP.activated.connect(
         lambda: self.__show_profile_manager())