Example #1
1
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.title = 'To The Beat'
        self.can_start = {'vid_chooser_list': False, 'music_file_textbox': False, 'output_file_textbox': False, 'isRendering': False}
        self.vids = []
        self.was_canceled = False
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)

        self.central_widget = QWidget()
        self.layout = QVBoxLayout()

        self.tabs = QTabWidget()
        self.inputTab = QWidget()
        self.inputLayout = QVBoxLayout()
        self.inputTab.setLayout(self.inputLayout)
        self.optionsTab = QWidget()
        self.optionsGrid = QGridLayout()
        self.optionsLayout = QVBoxLayout()
        self.optionsTab.setLayout(self.optionsLayout)

        self.tabs.addTab(self.inputTab, 'Input')
        self.tabs.addTab(self.optionsTab, 'Options')
        
        # Video chooser
        self.vid_chooser_list = QListWidget()
        self.vid_chooser_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.vid_chooser_list.setIconSize(QSize(320/3, 240/3))
        self.vid_chooser_list.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
        self.vid_chooser_model = self.vid_chooser_list.model()
        self.vid_chooser_model.rowsInserted.connect(self.changeVidChooserBtnState)
        self.vid_chooser_model.rowsRemoved.connect(self.changeVidChooserBtnState)

        self.vid_add_btn = QPushButton('Add')
        self.vid_add_btn.clicked.connect(self.addVideos)
        self.vid_rm_btn = QPushButton('Remove')
        self.vid_rm_btn.clicked.connect(self.removeVideos)
        self.vid_up_btn = QPushButton('Up')
        self.vid_up_btn.clicked.connect(self.moveVideosUp)
        self.vid_down_btn = QPushButton('Down')
        self.vid_down_btn.clicked.connect(self.moveVideosDown)

        self.vid_chooser_btn_layout = QVBoxLayout()
        self.vid_chooser_btn_layout.setContentsMargins(0, 0, 0, 0)
        self.vid_chooser_btn_layout.setSpacing(0)
        self.vid_chooser_btn_layout.addWidget(self.vid_add_btn)
        self.vid_chooser_btn_layout.addWidget(self.vid_rm_btn)
        self.vid_chooser_btn_layout.addWidget(self.vid_up_btn)
        self.vid_chooser_btn_layout.addWidget(self.vid_down_btn)
        self.vid_chooser_btn_layout.addStretch(0)

        self.vid_chooser_layout = QHBoxLayout()
        self.vid_chooser_layout.addWidget(self.vid_chooser_list)
        self.vid_chooser_layout.addLayout(self.vid_chooser_btn_layout)

        self.vid_chooser_group_box = QGroupBox('Video files')
        self.vid_chooser_group_box.setLayout(self.vid_chooser_layout)

        # Music chooser
        self.music_file_textbox = QLineEdit()
        self.music_file_textbox.textChanged.connect(self.musicFileTextboxChanged)
        self.music_file_browse_btn = QPushButton('Browse')
        self.music_file_browse_btn.clicked.connect(self.browseMusicFile)

        self.music_chooser_layout = QHBoxLayout()
        self.music_chooser_layout.addWidget(self.music_file_textbox)
        self.music_chooser_layout.addWidget(self.music_file_browse_btn)

        self.music_chooser_group_box = QGroupBox('Music')
        self.music_chooser_group_box.setLayout(self.music_chooser_layout)

        # Output vid chooser
        self.output_file_textbox = QLineEdit()
        self.output_file_textbox.textChanged.connect(self.outputFileTextboxChanged)
        self.output_file_browse_btn = QPushButton('Browse')
        self.output_file_browse_btn.clicked.connect(self.browseOutputFile)

        self.output_chooser_layout = QHBoxLayout()
        self.output_chooser_layout.addWidget(self.output_file_textbox)
        self.output_chooser_layout.addWidget(self.output_file_browse_btn)

        self.output_chooser_group_box = QGroupBox('Output')
        self.output_chooser_group_box.setLayout(self.output_chooser_layout)

        # OPTIONS
        split_beat_tooltip = 'Change this option to change when in the music the video cuts to another clip. Multiples of 3 and 4 work best for most music.'
        self.split_beat_spinbox = QSpinBox()
        self.split_beat_spinbox.setMinimum(1)
        self.split_beat_spinbox.setValue(4)
        self.split_beat_spinbox.setPrefix('Cut every ')
        self.split_beat_spinbox.setSuffix(' beats')
        self.split_beat_spinbox.setToolTip(split_beat_tooltip)

        sep_tooltip = 'Clips from the same video must be at least this many seconds apart.'
        self.sep_spinbox = QSpinBox()
        self.sep_spinbox.setMinimum(1)
        self.sep_spinbox.setValue(5)
        self.sep_spinbox.setSuffix(' seconds')
        self.sep_spinbox.setToolTip(sep_tooltip)

        # TODO: Add a button in this combobox that says 'Custom resolution', and it pops up with a dialog box allowing you to input custom resolution
        resolution_tooltip = 'Sets the output resolution of the video. Select "Custom resolution" to set your own. Higher resolutions will take longer to render.'
        self.resolution_combobox = QComboBox()
        self.resolution_combobox.addItems([
            '1280 x 720 (720p)',
            '1920 x 1080 (1080p)',
            '3840 x 2160 (4K)',
            'Custom resolution'
        ])
        self.resolution_combobox.insertSeparator(3)
        self.resolution_combobox.setToolTip(resolution_tooltip)

        fps_tooltip = 'Sets the output frames per second of the video. The default value of 30fps should work well for most videos.'
        self.fps_spinbox = QSpinBox()
        self.fps_spinbox.setMinimum(1)
        self.fps_spinbox.setValue(30)
        self.fps_spinbox.setSuffix(' fps')
        self.fps_spinbox.setToolTip(fps_tooltip)

        preset_tooltip = 'Sets the FFmpeg render preset. Faster presets will result in faster render times but bigger file sizes.'
        self.preset_combobox = QComboBox()
        self.preset_combobox.addItems([
            'ultrafast', 
            'superfast',
            'veryfast',
            'faster',
            'fast',
            'medium',
            'slow',
            'slower',
            'veryslow'
        ])
        self.preset_combobox.setCurrentIndex(0) #ultrafast
        self.preset_combobox.setToolTip(preset_tooltip)

        self.options = [
            [QLabel('Beat to cut at'), self.split_beat_spinbox],
            [QLabel('Minimum separation time'), self.sep_spinbox],
            [QLabel('Frames per second'), self.fps_spinbox],
            [QLabel('Resolution'), self.resolution_combobox],
            [QLabel('FFmpeg render preset'), self.preset_combobox]
        ]

        for r, row in enumerate(self.options):
            for c, widget in enumerate(row):
                self.optionsGrid.addWidget(widget, r, c)
        
        self.optionsLayout.addWidget(QLabel('Hover over an option to learn more about it'))
        self.optionsLayout.addLayout(self.optionsGrid)
        self.optionsLayout.addStretch()

        # Start button (create video?)
        # Maybe make button bigger vertically so it's more obvious?
        self.start_btn = QPushButton('Start')
        self.start_btn.clicked.connect(self.start)
        self.changeVidChooserBtnState()

        self.stop_btn = QPushButton('Cancel')
        self.stop_btn.clicked.connect(self.stop)
        self.stop_btn.hide()
        
        self.progress_bar = QProgressBar()
        self.progress_bar.setMaximum(100)
        self.progress_bar.setValue(0)
        self.progress_bar.hide()

        # Add everything to the main layout
        self.inputLayout.addWidget(self.vid_chooser_group_box)
        self.inputLayout.addWidget(self.music_chooser_group_box)

        self.layout.addWidget(self.tabs)
        self.layout.addWidget(self.output_chooser_group_box)
        self.layout.addWidget(self.start_btn)
        self.layout.addWidget(self.stop_btn)
        self.layout.addWidget(self.progress_bar)

        self.central_widget.setLayout(self.layout)
        self.setCentralWidget(self.central_widget)

        self.show()

    def checkCanStart(self):
        if self.can_start['vid_chooser_list'] and self.can_start['music_file_textbox'] and self.can_start['output_file_textbox'] and not self.can_start['isRendering']:
            self.start_btn.setEnabled(True)
        else:
            self.start_btn.setEnabled(False)
    
    def changeVidChooserBtnState(self):
        if len(self.vid_chooser_list) > 0:
            self.vid_rm_btn.setEnabled(True)
            self.vid_up_btn.setEnabled(True)
            self.vid_down_btn.setEnabled(True)

            self.can_start['vid_chooser_list'] = True
        else:
            self.vid_rm_btn.setEnabled(False)
            self.vid_up_btn.setEnabled(False)
            self.vid_down_btn.setEnabled(False)

            self.can_start['vid_chooser_list'] = False
        
        self.checkCanStart()

    def musicFileTextboxChanged(self):
        if len(self.music_file_textbox.text()) > 0:
            self.can_start['music_file_textbox'] = True
        else:
            self.can_start['music_file_textbox'] = False
        
        self.checkCanStart()

    def outputFileTextboxChanged(self):
        if len(self.output_file_textbox.text()) > 0:
            self.can_start['output_file_textbox'] = True
        else:
            self.can_start['output_file_textbox'] = False
        
        self.checkCanStart()

    def addVideos(self):
        file_names = QFileDialog.getOpenFileNames(self, 'Select video files', '', (
            'Video and Image files (*.mp4 *.avi *.mov *.flv *.wmv *.png *.jpg *.bpm *.tiff *.gif *.webp)'
        ))[0]

        QApplication.setOverrideCursor(Qt.WaitCursor)
        with tempfile.TemporaryDirectory() as dir:
            for i, name in enumerate(file_names):
                thumbnail_name = f'{dir}/{str(uuid.uuid4())}.jpg'
                tothebeat.createThumbnail(name, thumbnail_name)

                short_name = name.split('/')[-1]
                self.vid_chooser_list.addItem(QListWidgetItem(QIcon(thumbnail_name), short_name))
                self.vids.append(name)
        QApplication.restoreOverrideCursor()

    def removeVideos(self):
        for selected_widget in self.vid_chooser_list.selectedItems():
            index = self.vid_chooser_list.row(selected_widget)
            self.vid_chooser_list.takeItem(index)
            self.vids.pop(index)

    def moveVideosUp(self):
        selected_rows = [self.vid_chooser_list.row(selected_widget) for selected_widget in self.vid_chooser_list.selectedItems()]
        selected_rows.sort()

        if 0 not in selected_rows:
            for row in selected_rows:
                widget = self.vid_chooser_list.takeItem(row)
                self.vid_chooser_list.insertItem(row-1, widget)
                widget.setSelected(True)
                
                self.vids.insert(row-1, self.vids.pop(row))

    def moveVideosDown(self):
        selected_rows = [self.vid_chooser_list.row(selected_widget) for selected_widget in self.vid_chooser_list.selectedItems()]
        selected_rows.sort(reverse=True)
        
        if len(self.vid_chooser_list)-1 not in selected_rows:
            for row in selected_rows:
                widget = self.vid_chooser_list.takeItem(row)
                self.vid_chooser_list.insertItem(row+1, widget)
                widget.setSelected(True)

                self.vids.insert(row+1, self.vids.pop(row))

    def browseMusicFile(self):
        file_name = QFileDialog.getOpenFileName(self, 'Select a music file', '', 'Audio files (*.3gp *.aa *.aac *.aax *.act *.aiff *.amr *.ape *.au *.awb *.dct *.dss *.dvf *.flac *.gsm *.iklax *.ivs *.m4a *.m4b *.m4p *.mmf *.mp3 *.mpc *.msv *.nmf *.nsf *.ogg *.oga *.mogg *.opus *.ra *.rm *.raw *.sln *.tt *.vox *.wav *.webm *.wma *.wv)')[0]
        self.music_file_textbox.setText(file_name)

    def browseOutputFile(self):
        file_name = QFileDialog.getSaveFileName(self, 'Save output video as...', '', 'Video files (*.mp4 *.avi *.mov *.flv *.wmv)')[0]
        self.output_file_textbox.setText(file_name)

    def start(self):
        self.output_file_name = self.output_file_textbox.text()
        resolution = self.resolution_combobox.currentText().split('(')[0].strip().split('x')
        resolution_w = int(resolution[0].strip())
        resolution_h = int(resolution[1].strip())
        sep = self.sep_spinbox.value()
        fps = self.fps_spinbox.value()
        split_every_n_beat = self.split_beat_spinbox.value()
        preset = self.preset_combobox.currentText()

        self.progress_bar.show()
        self.progress_bar.setValue(0)

        self.render_thread = RenderVideoThread(
            self.music_file_textbox.text(),
            self.output_file_name,
            resolution_w,
            resolution_h,
            sep=sep,
            fps=fps,
            split_every_n_beat=split_every_n_beat,
            preset=preset,
            vids=self.vids
        )
        self.render_thread.setProgress.connect(self.setProgress)
        self.render_thread.showErrorMessage.connect(self.showErrorMessage)
        self.render_thread.canceled.connect(self.canceled)
        self.render_thread.finished.connect(self.done)
        self.render_thread.start()

        #self.stop_btn.clicked.connect(self.render_thread.terminate)
        self.stop_btn.show()

        self.can_start['isRendering'] = True
        self.checkCanStart()

    def stop(self):
        ans = QMessageBox.warning(None, 'Cancel render', 'Are you sure you want to cancel the rendering of this video?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if ans == QMessageBox.Yes:
            self.render_thread.stop(canceled=True)
            self.render_thread.wait()

    def setProgress(self, progress):
        self.progress_bar.setValue(progress)

    def showErrorMessage(self, error_log_path):
        QMessageBox.critical(self, 'Something went wrong!', f'The video could not be rendered for some reason. A log of the error can be found at: {error_log_path}')
        self.render_thread.stop()
        self.render_thread.wait()

    def canceled(self):
        self.was_canceled = True
        QMessageBox.information(self, 'Canceled', 'The rendering of the video has been successfully canceled.')

    def done(self):
        if os.path.isfile(self.output_file_name) and not self.was_canceled:
            self.progress_bar.setValue(100)
            QMessageBox.information(self, 'Render complete!', f'Video has been successfully rendered to {self.output_file_name}!')
        self.was_canceled = False
        self.progress_bar.hide()
        self.progress_bar.setValue(0)
        self.stop_btn.hide()
        self.can_start['isRendering'] = False
        self.checkCanStart()
Example #2
0
class FileChooser(QWidget):
    fileOpened = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.folderBox = QComboBox(self)
        self.explorerTree = FileTreeView(self)
        self.explorerTree.doubleClickCallback = self._fileOpened
        self.explorerModel = QFileSystemModel(self)
        self.explorerModel.setFilter(
            QDir.AllDirs | QDir.Files | QDir.NoDotAndDotDot)
        self.explorerModel.setNameFilters(["*.py"])
        self.explorerModel.setNameFilterDisables(False)
        self.explorerTree.setModel(self.explorerModel)
        for index in range(1, self.explorerModel.columnCount()):
            self.explorerTree.hideColumn(index)
        self.setCurrentFolder()
        self.folderBox.currentIndexChanged[int].connect(
            self.updateCurrentFolder)

        layout = QVBoxLayout(self)
        layout.addWidget(self.folderBox)
        layout.addWidget(self.explorerTree)
        layout.setContentsMargins(5, 5, 0, 0)

    def _fileOpened(self, modelIndex):
        path = self.explorerModel.filePath(modelIndex)
        if os.path.isfile(path):
            self.fileOpened.emit(path)

    def currentFolder(self):
        return self.explorerModel.rootPath()

    def setCurrentFolder(self, path=None):
        if path is None:
            app = QApplication.instance()
            path = app.getScriptsDirectory()
        else:
            assert os.path.isdir(path)
        self.explorerModel.setRootPath(path)
        self.explorerTree.setRootIndex(self.explorerModel.index(path))
        self.folderBox.blockSignals(True)
        self.folderBox.clear()
        style = self.style()
        dirIcon = style.standardIcon(style.SP_DirIcon)
        self.folderBox.addItem(dirIcon, os.path.basename(path))
        self.folderBox.insertSeparator(1)
        self.folderBox.addItem(self.tr("Browse…"))
        self.folderBox.setCurrentIndex(0)
        self.folderBox.blockSignals(False)

    def updateCurrentFolder(self, index):
        if index < self.folderBox.count() - 1:
            return
        path = QFileDialog.getExistingDirectory(
            self, self.tr("Choose Directory"), self.currentFolder(),
            QFileDialog.ShowDirsOnly)
        if path:
            QSettings().setValue("scripting/path", path)
            self.setCurrentFolder(path)
Example #3
0
 def createEditor(self, parent, option, index):  # residNum,residNum_color, residName, atomName, atomNum, X,Y,Z
     if index.column() == residNum:
         spinbox = QSpinBox(parent)
         spinbox.setRange(1, 200000)
         spinbox.setSingleStep(1)
         spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
         return spinbox
     elif index.column() == residName:
         combobox = QComboBox(parent)
         combobox.addItems(comboBoxList)
         combobox.insertSeparator(23)
         combobox.setEditable(True)
         return combobox
     elif index.column() == atomName:
         editor = QLineEdit(parent)
         editor.returnPressed.connect(self.commitAndCloseEditor)
         return editor
     elif index.column() == atomNum:
         spinbox = QSpinBox(parent)
         spinbox.setRange(1, 200000)
         spinbox.setSingleStep(1)
         spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
         return spinbox
     elif index.column() in (X, Y, Z):  ###this works
         dspinbox = QDoubleSpinBox(parent)
         dspinbox.setRange(-200000, 200000)
         dspinbox.setSingleStep(0.1)
         dspinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
         return dspinbox
     else:
         return QStyledItemDelegate.createEditor(self, parent, option,
                                                 index)
 def createEditor(self, parent, *args):
     editor = QComboBox(parent)
     editor.addItems(self.type_names)
     editor.insertSeparator(len(self.type_names))
     if self.custom_types:
         editor.addItems(self.custom_types)
         editor.insertSeparator(
             len(self.type_names) + len(self.custom_types) + 1)
     editor.addItem(self.tr("custom"))
     return editor
Example #5
0
    def g_type_combobox(self, type_str, root=False):
        cb = QComboBox()
        items = [list, dict]
        if not root:
            items.append(self.lang.node_none)
            for item in [str, int, bool, None.__class__]:
                items.append(item)

        items = [type_map.get(item, item) for item in items]
        for index, item in enumerate(items):
            if item == self.lang.node_none:
                cb.insertSeparator(index)
            else:
                cb.insertItem(index, item)
        cb.setCurrentText(type_str)

        return cb
Example #6
0
class Choices(QWidget):
    def __init__(self, encoder, optname, attrname, choices, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.encoder = encoder
        self.optname = optname
        self.attrname = attrname

        layout = QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        self.label = QLabel(optname, self)
        layout.addWidget(self.label)

        layout.addStretch()

        self.selection = QComboBox(self)
        layout.addWidget(self.selection)

        self.selection.addItem("Not set", None)
        self.selection.insertSeparator(1)

        currentvalue = getattr(encoder, attrname)

        for choice in choices:
            if isinstance(choice, (list, tuple)):
                name, value, *_ = choice

            elif isinstance(choice, str):
                name = value = choice

            elif isinstance(choice, int):
                value = choice
                name = f"{choice}"

            self.selection.addItem(name, value)

            if currentvalue == value:
                self.selection.setCurrentIndex(self.selection.count() - 1)

        self.selection.currentIndexChanged.connect(self.indexChanged)

    def indexChanged(self, value):
        data = self.selection.currentData()
        setattr(self.encoder, self.attrname, data)
Example #7
0
    def init_widget(self):
        """
        현재 위젯의 모양등을 초기화
        """
        self.setWindowTitle("QComboBox Widget")
        form_lbx = QBoxLayout(QBoxLayout.TopToBottom, parent=self)
        self.setLayout(form_lbx)

        lb = QLabel()

        qb = QComboBox()
        qb.addItem("Banana")  # 단일 아이템 추가시
        qb.addItems(["Apple", "Tomato", "Carrot"])  # 다수 아이템 추가시
        qb.insertSeparator(2)  # 구분 선
        qb.currentTextChanged.connect(lb.setText)  # 현재 인덱스의 데이터가 바뀔 때

        form_lbx.addWidget(qb)
        form_lbx.addWidget(lb)
Example #8
0
 def createEditor(self, parent, option, index):
     if index.column() == ATOM:
         combobox = QComboBox(parent)
         combobox.addItems(['ATOM', 'HETATM'])
         combobox.setEditable(True)
         return combobox
     elif index.column() == serial:
         spinbox = QSpinBox(parent)
         spinbox.setRange(1, 200000)
         spinbox.setSingleStep(1)
         spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
         return spinbox
     elif index.column() == name:
         editor = QLineEdit(parent)
         editor.returnPressed.connect(self.commitAndCloseEditor)
         return editor
     elif index.column() == resName:
         combobox = QComboBox(parent)
         combobox.addItems(comboBoxList)
         combobox.insertSeparator(23)
         combobox.setEditable(True)
         return combobox
         # editor = QLineEdit(parent)
         # editor.returnPressed.connect(self.commitAndCloseEditor)
         # return editor
     elif index.column() == ChainID:
         editor = QLineEdit(parent)
         editor.returnPressed.connect(self.commitAndCloseEditor)
         return editor
     elif index.column() == resNum:
         spinbox = QSpinBox(parent)
         spinbox.setRange(1, 200000)
         spinbox.setSingleStep(1)
         spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
         return spinbox
     elif index.column() in (X, Y, Z, occupancy, charge):  ###this works
         dspinbox = QDoubleSpinBox(parent)
         dspinbox.setRange(-200000, 200000)
         dspinbox.setSingleStep(0.1)
         dspinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
         return dspinbox
     else:
         return QStyledItemDelegate.createEditor(self, parent, option,
                                                 index)
Example #9
0
    def __init__(self):
        super(MainWindow, self).__init__()

        self.ports = serial.listports()
        self.port = None

        # remove close & maximize window buttons
        #self.setWindowFlags(Qt.CustomizeWindowHint|Qt.WindowMinimizeButtonHint)
        self.setMinimumSize(850, 450)

        self.mdiArea = QMdiArea()
        self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.setCentralWidget(self.mdiArea)

        self.mdiArea.subWindowActivated.connect(self.updateMenus)
        self.mdiArea.setViewMode(QMdiArea.TabbedView)

        self.windowMapper = QSignalMapper(self)
        self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow)

        self.child = None

        self.createActions()
        self.createMenus()
        self.createStatusBar()
        self.updateMenus()
        self.readSettings()
        self.setWindowTitle("VISCAM")

        mytoolbar = QToolBar()
        ports_menu = QComboBox()
        ports_menu.addItem('Output Port')
        ports_menu.insertSeparator(1)
        for port in self.ports:
            ports_menu.addItem(port)
        self.ports_menu = ports_menu
        ports_menu.currentTextChanged.connect(self.setActivePort)
        mytoolbar.addWidget(ports_menu)
        mytoolbar.addSeparator()
        mytoolbar.setMovable(False)
        mytoolbar.setFixedHeight(60)
        self.addToolBar(Qt.TopToolBarArea, mytoolbar)
Example #10
0
 def createEditor(self, parent, option, index):
     if index.column() == ATOM:
         combobox = QComboBox(parent)
         combobox.addItems(["ATOM", "HETATM"])
         combobox.setEditable(True)
         return combobox
     elif index.column() == serial:
         spinbox = QSpinBox(parent)
         spinbox.setRange(1, 200000)
         spinbox.setSingleStep(1)
         spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
         return spinbox
     elif index.column() == name:
         editor = QLineEdit(parent)
         editor.returnPressed.connect(self.commitAndCloseEditor)
         return editor
     elif index.column() == resName:
         combobox = QComboBox(parent)
         combobox.addItems(comboBoxList)
         combobox.insertSeparator(23)
         combobox.setEditable(True)
         return combobox
         # editor = QLineEdit(parent)
         # editor.returnPressed.connect(self.commitAndCloseEditor)
         # return editor
     elif index.column() == ChainID:
         editor = QLineEdit(parent)
         editor.returnPressed.connect(self.commitAndCloseEditor)
         return editor
     elif index.column() == resNum:
         spinbox = QSpinBox(parent)
         spinbox.setRange(1, 200000)
         spinbox.setSingleStep(1)
         spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
         return spinbox
     elif index.column() in (X, Y, Z, occupancy, charge):  ###this works
         dspinbox = QDoubleSpinBox(parent)
         dspinbox.setRange(-200000, 200000)
         dspinbox.setSingleStep(0.1)
         dspinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
         return dspinbox
     else:
         return QStyledItemDelegate.createEditor(self, parent, option, index)
Example #11
0
    def recreate_sequence(self):
        self.layout.removeWidget(self.btn_plus)
        for w in self.widgets:
            self.layout.removeWidget(w)
            w.deleteLater()
        self.widgets.clear()

        for item in self.act.sequence:
            w = QComboBox()
            w.view().setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
            w.setStyleSheet("QComboBox { combobox-popup: 0; }")
            w.addItem(tr("MacroEditor", "Remove"))
            w.insertSeparator(1)
            for k in MACRO_SEQUENCE_KEYCODES:
                w.addItem(k.label.replace("\n", ""))
            w.setCurrentIndex(2 + MACRO_SEQUENCE_KEYCODES.index(item))
            w.currentIndexChanged.connect(self.on_change)
            self.layout.addWidget(w)
            self.widgets.append(w)
        self.layout.addWidget(self.btn_plus)
Example #12
0
    def createEditor(self, parent, option, index):
        obj = index.data(Qt.UserRole)

        if isinstance(obj, SimpleTag):
            widget = QComboBox(parent)
            widget.setEditable(True)

            for k, (section, items) in enumerate(SECTIONS):
                if k > 0:
                    widget.insertSeparator(len(widget))

                for item in items:
                    widget.addItem(titlecase(item.replace("_", " ")), item)

        elif isinstance(obj, Tag):
            widget = QComboBox(parent)

            for (type, typeValue) in TYPES:
                widget.addItem(f"{titlecase(type)} ({typeValue})", [
                               type, typeValue])

        return widget
Example #13
0
    def createEditor(self, parent, option, index):
        editor = QComboBox(parent)

        editor.addItem("Unknown (und)", None)
        editor.insertSeparator(editor.count())

        common_langs = ["eng", "deu", "ita", "spa", "fra", "por", "nld",
                        "swe", "nor", "fin", "pol", "ron", "rus", "tur",
                        "vie", "kor", "arz", "pes", "hin", "zho", "jpn"]

        for key in common_langs:
            lang = LANGUAGES[key]
            editor.addItem(f"{lang} ({key})", key)

        editor.insertSeparator(editor.count())

        for key, lang in sorted(LANGUAGES.items(), key=lambda item: item[1]):
            if key in common_langs:
                continue
            editor.addItem(f"{lang} ({key})", key)

        return editor
Example #14
0
 def c_combobox(self, text, choices, confkey, restart=False, tip=None):
     label = QLabel(text)
     combobox = QComboBox()
     combobox.restart_required = restart
     combobox.label_text = text
     if tip:
         combobox.setToolTip(tip)
     for name, key in choices:
         if name and key:
             combobox.addItem(name, key)
     i = 0
     for idx, item in enumerate(choices):
         name, key = item
         if not name and not key:
             combobox.insertSeparator(idx + i)
             i += 1
     self.comboboxes[combobox] = confkey
     layout = make_layout(self, Qt.Horizontal, label, combobox)
     layout.addStretch(1)
     widget = QWidget(self)
     widget.label = label
     widget.combobox = combobox
     widget.setLayout(layout)
     return widget
Example #15
0
class CSVOptionsWindow(QWidget):
    def __init__(self, mainwindow):
        QWidget.__init__(self, mainwindow, Qt.Window)
        self._setupUi()
        self.doc = mainwindow.doc
        self.model = mainwindow.model.csv_options
        self.tableModel = CSVOptionsTableModel(self.model, self.tableView)
        self.model.view = self
        self.encodingComboBox.addItems(SUPPORTED_ENCODINGS)

        self.cancelButton.clicked.connect(self.hide)
        self.continueButton.clicked.connect(self.model.continue_import)
        self.targetComboBox.currentIndexChanged.connect(
            self.targetIndexChanged)
        self.layoutComboBox.currentIndexChanged.connect(
            self.layoutIndexChanged)
        self.rescanButton.clicked.connect(self.rescanClicked)

    def _setupUi(self):
        self.setWindowTitle(tr("CSV Options"))
        self.resize(526, 369)
        self.verticalLayout = QVBoxLayout(self)
        msg = tr(
            "Specify which CSV columns correspond to which transaction fields. You must also "
            "uncheck the \"Import\" column for lines that don\'t represent a transaction "
            "(header, footer, comments).")
        self.label = QLabel(msg)
        self.label.setWordWrap(True)
        self.verticalLayout.addWidget(self.label)
        self.gridLayout = QGridLayout()
        self.label_2 = QLabel(tr("Layout:"))
        self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1)
        self.layoutComboBox = QComboBox(self)
        self.layoutComboBox.setMinimumSize(QtCore.QSize(160, 0))
        self.gridLayout.addWidget(self.layoutComboBox, 0, 1, 1, 1)
        self.label_4 = QLabel(tr("Delimiter:"))
        self.gridLayout.addWidget(self.label_4, 0, 3, 1, 1)
        self.fieldSeparatorEdit = QLineEdit(self)
        self.fieldSeparatorEdit.setMaximumSize(QtCore.QSize(30, 16777215))
        self.gridLayout.addWidget(self.fieldSeparatorEdit, 0, 4, 1, 1)
        self.targetComboBox = QComboBox(self)
        self.gridLayout.addWidget(self.targetComboBox, 1, 1, 1, 1)
        self.label_3 = QLabel(tr("Target:"))
        self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1)
        self.encodingComboBox = QComboBox(self)
        self.gridLayout.addWidget(self.encodingComboBox, 1, 4, 1, 1)
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem, 2, 2, 1, 1)
        self.horizontalLayout_2 = QHBoxLayout()
        self.horizontalLayout_2.setSpacing(0)
        spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                  QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem1)
        self.rescanButton = QPushButton(tr("Rescan"))
        sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.rescanButton.sizePolicy().hasHeightForWidth())
        self.rescanButton.setSizePolicy(sizePolicy)
        self.horizontalLayout_2.addWidget(self.rescanButton)
        self.gridLayout.addLayout(self.horizontalLayout_2, 2, 3, 1, 2)
        self.label_5 = QLabel(tr("Encoding:"))
        self.gridLayout.addWidget(self.label_5, 1, 3, 1, 1)
        self.verticalLayout.addLayout(self.gridLayout)
        self.tableView = QTableView(self)
        self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tableView.setShowGrid(False)
        self.tableView.horizontalHeader().setHighlightSections(False)
        self.tableView.verticalHeader().setVisible(False)
        self.tableView.verticalHeader().setDefaultSectionSize(18)
        self.verticalLayout.addWidget(self.tableView)
        self.horizontalLayout = QHBoxLayout()
        spacerItem2 = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                  QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem2)
        self.cancelButton = QPushButton(tr("Cancel"))
        self.cancelButton.setShortcut("Esc")
        self.horizontalLayout.addWidget(self.cancelButton)
        self.continueButton = QPushButton(tr("Continue Import"))
        self.continueButton.setDefault(True)
        self.horizontalLayout.addWidget(self.continueButton)
        self.verticalLayout.addLayout(self.horizontalLayout)

    # --- Private
    def _newLayout(self):
        title = tr("New Layout")
        msg = tr("Choose a name for your new layout:")
        name, ok = QInputDialog.getText(self, title, msg)
        if ok and name:
            self.model.new_layout(name)

    def _renameLayout(self):
        title = tr("Rename Layout")
        msg = tr("Choose a name for your layout:")
        name, ok = QInputDialog.getText(self, title, msg)
        if ok and name:
            self.model.rename_selected_layout(name)

    # --- Event Handling
    def layoutIndexChanged(self, index):
        # This one is a little complicated. We want to only be able to select the layouts. If
        # anything else is clicked, we revert back to the old index. If the item has user data,
        # it means that an action has to be performed.
        if index < 0:
            return
        elif index < len(self.model.layout_names):
            layout_name = None if index == 0 else str(
                self.layoutComboBox.itemText(index))
            self.model.select_layout(layout_name)
        else:
            self.layoutComboBox.setCurrentIndex(
                self.layoutComboBox.findText(self.model.layout.name))
            data = str(self.layoutComboBox.itemData(index))
            if data == NEW_LAYOUT:
                self._newLayout()
            elif data == RENAME_LAYOUT:
                self._renameLayout()
            elif data == DELETE_LAYOUT:
                self.model.delete_selected_layout()

    def rescanClicked(self):
        self.model.encoding_index = self.encodingComboBox.currentIndex()
        self.model.field_separator = str(self.fieldSeparatorEdit.text())
        self.model.rescan()

    def targetIndexChanged(self, index):
        self.model.selected_target_index = index

    # --- model --> view
    # hide() is called from the model, but is already covered by QWidget
    def refresh_columns(self):
        self.tableModel.beginResetModel()
        self.tableModel.endResetModel()

    def refresh_columns_name(self):
        self.tableModel.refreshColumnsName()

    def refresh_layout_menu(self):
        self.layoutComboBox.currentIndexChanged.disconnect(
            self.layoutIndexChanged)
        self.layoutComboBox.clear()
        self.layoutComboBox.addItems(self.model.layout_names)
        self.layoutComboBox.insertSeparator(self.layoutComboBox.count())
        self.layoutComboBox.addItem(tr("New Layout..."), NEW_LAYOUT)
        self.layoutComboBox.addItem(tr("Rename Selected Layout..."),
                                    RENAME_LAYOUT)
        self.layoutComboBox.addItem(tr("Delete Selected Layout"),
                                    DELETE_LAYOUT)
        self.layoutComboBox.setCurrentIndex(
            self.layoutComboBox.findText(self.model.layout.name))
        self.layoutComboBox.currentIndexChanged.connect(
            self.layoutIndexChanged)

    def refresh_lines(self):
        self.tableModel.beginResetModel()
        self.tableModel.endResetModel()
        self.fieldSeparatorEdit.setText(self.model.field_separator)

    def refresh_targets(self):
        self.targetComboBox.currentIndexChanged.disconnect(
            self.targetIndexChanged)
        self.targetComboBox.clear()
        self.targetComboBox.addItems(self.model.target_account_names)
        self.targetComboBox.currentIndexChanged.connect(
            self.targetIndexChanged)

    def show(self):
        # For non-modal dialogs, show() is not enough to bring the window at the forefront, we have
        # to call raise() as well
        QWidget.show(self)
        self.raise_()

    def show_message(self, msg):
        title = "Warning"
        QMessageBox.warning(self, title, msg)
Example #16
0
class TextEditor(QWidget):
    '''Class creating a TextEditor object.'''
    def __init__(self,
                 txt_width=500,
                 txt_height=220,
                 txt_text=tr('Text :'),
                 parent=None):
        '''Create the text.'''

        #------ini
        super().__init__(parent)

        self.fn = tr('-- Select a file --')
        self.lst_f_hist = []

        self.style = GuiStyle().style_sheet

        #------widgets
        #---layout
        main_lay = QGridLayout()
        main_lay.setRowStretch(0, 1)
        self.setLayout(main_lay)

        #---text
        #-Radio button
        self.rb_txt = QRadioButton(txt_text)
        self.rb_txt.setChecked(True)
        main_lay.addWidget(self.rb_txt, 0, 0)

        #-font
        self.fixed_font = QFont('monospace')
        self.fixed_font.setStyleHint(QFont.TypeWriter)

        #-text
        self.txt = QTextEdit()
        self.txt.setMinimumSize(txt_width, txt_height)
        self.txt.setAcceptRichText(False)
        self.txt.setStyleSheet(self.style)
        self.txt.setObjectName('orange_border_hover')
        self.txt.setFont(self.fixed_font)
        main_lay.addWidget(self.txt, 0, 1, 1, 7)

        #---clear
        self.bt_clear = QPushButton(tr('Clear'))
        self.bt_clear.setMaximumSize(len(tr('Clear')) * 13, 50)
        self.bt_clear.clicked.connect(self.clear)
        main_lay.addWidget(self.bt_clear, 0, 0, alignment=Qt.AlignTop)

        #---file
        #-radio button
        self.rb_fn = QRadioButton(tr('File') + ' :')
        main_lay.addWidget(self.rb_fn, 1, 0)

        #-option menu files
        self.lst_f = (tr('-- Select a file --'), *list_files())
        self.opt_fn = QComboBox()
        self.opt_fn.addItems(self.lst_f)
        self.opt_fn.insertSeparator(1)
        self.opt_fn.activated[str].connect(self.select_fn)
        main_lay.addWidget(self.opt_fn, 1, 1, 1, 2)

        #-buttons
        self.bt_select = QPushButton(tr('Select a file ...'))
        self.bt_select.setMaximumSize(len(tr('Select a file ...')) * 13, 50)
        self.bt_select.clicked.connect(self.select_fn)
        main_lay.addWidget(self.bt_select, 1, 3)

        self.bt_select_load = QPushButton(tr('Select and load') + ' ▲')
        self.bt_select_load.setMaximumSize(
            (len(tr('Select and load')) + 2) * 13, 50)
        self.bt_select_load.clicked.connect(self.select_load_fn)
        main_lay.addWidget(self.bt_select_load, 1, 4)

        self.bt_load = QPushButton(tr('Load') + ' ▲')
        self.bt_load.setMaximumSize((len(tr('Load')) + 2) * 13, 50)
        self.bt_load.clicked.connect(self.load_fn)
        main_lay.addWidget(self.bt_load, 1, 5)

        self.bt_save = QPushButton(tr('Save') + ' ▼')
        self.bt_save.setMaximumSize((len(tr('Save')) + 2) * 13, 50)
        self.bt_save.clicked.connect(self.save_fn)
        main_lay.addWidget(self.bt_save, 1, 6)

        self.bt_reload = QPushButton(tr('Reload'))
        self.bt_reload.setMaximumSize(len(tr('Reload')) * 13, 50)
        self.bt_reload.clicked.connect(self.reload)
        main_lay.addWidget(self.bt_reload, 1, 7, alignment=Qt.AlignRight)

        #-encoding
        self.rb_encod = QRadioButton(tr('Text encoding :'))
        main_lay.addWidget(self.rb_encod, 2, 1)
        self.opt_encod = QComboBox()
        self.opt_encod.addItems(lst_encod)
        main_lay.addWidget(self.opt_encod, 2, 2)

        rb_lay = QHBoxLayout()
        main_lay.addLayout(rb_lay, 2, 3, 1, 3)

        #-binary mode
        self.rb_bin = QRadioButton(tr('Binary mode'))
        rb_lay.addWidget(self.rb_bin)

        #-hexa mode
        self.rb_hexa = QRadioButton(tr('Hexa mode'))
        rb_lay.addWidget(self.rb_hexa)

        #-bytes mode
        self.rb_bytes = QRadioButton(tr('Bytes mode'))
        rb_lay.addWidget(self.rb_bytes)

        self.rb_txt.toggled.connect(self.check_bytes)
        self.rb_fn.toggled.connect(self.check_bytes)
        self.rb_fn.toggled.connect(self.select_fn_rb)
        self.rb_bytes.toggled.connect(self.check_bytes)

        self.rb_bt_grp1 = QButtonGroup()
        self.rb_bt_grp1.addButton(self.rb_txt)
        self.rb_bt_grp1.addButton(self.rb_fn)

        self.rb_bt_grp2 = QButtonGroup()
        self.rb_bt_grp2.addButton(self.rb_encod)
        self.rb_bt_grp2.addButton(self.rb_bin)
        self.rb_bt_grp2.addButton(self.rb_hexa)
        self.rb_bt_grp2.addButton(self.rb_bytes)

        #------show
        self.setMinimumSize(txt_width + 100, txt_height + 110)

        self.check_bytes()

    #------check
    def check_bytes(self):
        '''
        Check the bytes mode checkbutton's status to dislable or not the encoding menu,
        and check the radiobuttons to dislable or not the bytes checkbuttons.
        '''

        if self.rb_txt.isChecked():
            self.opt_encod.setDisabled(False)
            self.rb_bytes.setDisabled(True)
            self.rb_bytes.setChecked(False)

        elif self.rb_fn.isChecked():
            self.rb_bytes.setDisabled(False)

            if self.rb_bytes.isChecked():
                self.opt_encod.setDisabled(True)

            else:
                self.opt_encod.setDisabled(False)

    #------clear
    def clear(self):
        '''Clear the text widget.'''

        if self.txt.toPlainText() != '':
            sure = QMessageBox.question(self, tr('Sure') + ' ?', '<h2>' + tr('Are you sure ?') + '</h2>', \
                QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Yes)

            if sure != QMessageBox.Yes:
                return None

            self.txt.clear()

    #------select_fn_rb
    def select_fn_rb(self):
        '''
        Activated when pressing the radio button "plain file".
        If no file is selected, launch select_fn.
        '''

        if self.opt_fn.currentText() == tr('-- Select a file --'):
            self.select_fn()

        self.rb_bytes.setChecked(True)
        self.check_bytes()

    #---------select file "fn"
    def select_fn(self, fn=False):
        '''
        Select a file using the PyQt5 file dialog.

        fn : the filename. It is given when choosing with the combo box.
        '''

        if fn == False:
            fn = QFileDialog.getOpenFileName(self, tr('Open file'),
                                             getcwd())[0]

        if fn in ((), ''):  #cancel
            fn = tr('-- Select a file --')
            self.fn = fn
            self.rb_txt.setChecked(True)
            self.rb_fn.setChecked(False)
            return None

        self.fn = fn

        f = fn.split('/')[-1]

        if f not in self.lst_f:
            if len(self.lst_f_hist) == 0:
                self.opt_fn.insertSeparator(10000)

            if fn not in self.lst_f_hist:
                self.lst_f_hist.append(fn)

            self.opt_fn.addItem(fn)
            self.opt_fn.setCurrentText(fn)

        else:
            self.opt_fn.setCurrentText(f)

    #------select and load
    def select_load_fn(self):
        '''Uses the functions select and load.'''

        self.select_fn()
        self.load_fn()

    #------load file "fn"
    def load_fn(self):
        '''Load the selected file to the text widget.'''

        #self.fn = self.opt_fn.currentText()

        if self.fn == tr('-- Select a file --'):
            QMessageBox.warning(QWidget(), '!!! ' + tr('No file selected') + ' !!!', \
                '<h1>' + tr('Please select a file') + ' !</h1>\n' + tr('Or use the button "Select and load"'))

            return -3

        try:
            if self.rb_encod.isChecked():
                with open(self.fn,
                          mode='r',
                          encoding=str(self.opt_encod.currentText())) as f:
                    file_content = f.read()

            else:
                with open(self.fn, mode='rb') as f:
                    file_content = f.read()
                if self.rb_hexa.isChecked() or self.rb_bin.isChecked():
                    file_content = file_content.hex()
                    if self.rb_bin.isChecked():
                        d = {
                            '0': '0000',
                            '1': '0001',
                            '2': '0010',
                            '3': '0011',
                            '4': '0100',
                            '5': '0101',
                            '6': '0110',
                            '7': '0111',
                            '8': '1000',
                            '9': '1001',
                            'a': '1010',
                            'b': '1011',
                            'c': '1100',
                            'd': '1101',
                            'e': '1110',
                            'f': '1111'
                        }
                        for k in d:
                            file_content = file_content.replace(k, d[k])

        except FileNotFoundError:
            QMessageBox.critical(
                QWidget(), '!!! ' + tr('Error') + ' !!!',
                '<h2>' + tr('The file was NOT found') + ' !!!</h2>')
            return -1  #stop

        except UnicodeDecodeError:
            QMessageBox.critical(QWidget(), '!!! ' + tr('Encoding error') + ' !!!', \
                '<h2>' + tr('The file can\'t be decoded with this encoding') + ' !!!</h2>\n' + tr('Try bytes mode'))

            return -2  #stop

        txt = self.txt.toPlainText()

        if txt != '':
            sure = QMessageBox.question(self, '!!! ' + tr('Erase Text data') + ' !!!', \
                '<h2>' + tr('Text is detected in the box ! Remplace by the file\'s data ?') + '</h2>', \
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

            if sure != QMessageBox.Yes:
                return -3  #stop

        if type(file_content) == str:
            self.txt.setPlainText(file_content)

        elif type(file_content) == bytes:
            try:
                self.txt.setPlainText(file_content.decode())

            except UnicodeDecodeError:
                QMessageBox.critical(
                    None, '!!! ' + tr('Decoding error') + ' !!!', '<h2>' +
                    tr("The file can't be decoded in bytes mode") + '!</h2>')
                return -2

    #------save in file "fn"
    def save_fn(self, data=False):
        '''
        Save the content of the text widget in a file.

        data : the text to write. If False, write text which is in the text widget. Default is False.

        return -3 if canceled or aborted, -2 if an encoding error occur, None otherwise.
        '''

        if self.fn == tr('-- Select a file --'):
            filename = QFileDialog.getSaveFileName(self, tr('Save file'),
                                                   getcwd())[0]

            if filename in ((), ''):
                return -3  #Canceled
        else:
            filename = self.fn

        try:
            if not self.rb_bytes.isChecked():
                with open(filename,
                          'r',
                          encoding=str(self.opt_encod.currentText())) as f:
                    line = f.readline()

            else:
                with open(filename, mode='rb') as f:
                    line = f.readline()

        except FileNotFoundError:  #the file can be created, it don't exists
            pass

        except UnicodeDecodeError:
            pass

        else:
            if line not in ('', '\n'):
                sure = QMessageBox.question(self, '!!! ' + tr('Erase file data') + ' !!!', \
                    '<h2>' + tr('The selected file is NOT empty') + ' !!!</h2>\n<h3>' + tr('Overwrite with text data ?') + '</h3>', \
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

                if sure != QMessageBox.Yes:
                    return -3  #Aborted

        if data == False:
            txt = self.txt.toPlainText()

        else:
            txt = data

        if txt == '':
            emp = QMessageBox.question(self, tr('Text is empty'), \
                '<h2>' + tr('There is no text in the box') + '.\n' + tr('Write anyway ?') + '</h2>', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

            if emp != QMessageBox.Yes:
                return -3  #Aborted

        if self.rb_encod.isChecked():
            with open(filename,
                      'w',
                      encoding=str(self.opt_encod.currentText())) as f:
                if type(txt) == str:
                    f.write(txt)

                else:
                    f.write(txt.decode())

        else:
            try:
                if not self.rb_bytes.isChecked():
                    if self.rb_bin.isChecked():
                        if len(txt) % 8 != 0:
                            QMessageBox.critical(QWidget(), '!!! ' + tr('Value Error') + ' !!!', \
                    '<h2>' + tr('The number of binary digits is not a multiple of 8') + ' !!!</h2>')
                            return -2  #stop

                        else:
                            d = {
                                '0000': '0',
                                '0001': '1',
                                '0010': '2',
                                '0011': '3',
                                '0100': '4',
                                '0101': '5',
                                '0110': '6',
                                '0111': '7',
                                '1000': '8',
                                '1001': '9',
                                '1010': 'a',
                                '1011': 'b',
                                '1100': 'c',
                                '1101': 'd',
                                '1110': 'e',
                                '1111': 'f'
                            }
                            txt2 = ""
                            for k in range(len(txt) // 4):
                                if txt[k * 4:k * 4 + 4] not in d:
                                    QMessageBox.critical(QWidget(), '!!! ' + tr('Value Error') + ' !!!', \
                                    '<h2>' + tr('A binary number is composed only of 0 and 1') + ' !!!</h2>')
                                    return -2  #stop
                                else:
                                    txt2 += d[txt[k * 4:k * 4 + 4]]
                            txt = txt2

                    try:
                        if len(txt) % 2 != 0:
                            QMessageBox.critical(QWidget(), '!!! ' + tr('Value Error') + ' !!!', \
                    "<h2>The number of hexadecimal digits is not a multiple of 2 !!!</h2>")
                            return -2  #stop
                        txt = bytes.fromhex(txt)
                    except ValueError:
                        QMessageBox.critical(QWidget(), '!!! ' + tr('Value Error') + ' !!!', \
                    '<h2>' + tr('Error in the conversion of hexadecimal to bytes') + ' !!!</h2>')
                        return -2  #stop

                with open(filename, mode='wb') as f:
                    if type(txt) == str:
                        f.write(
                            txt.encode(
                                encoding=str(self.opt_encod.currentText())))

                    else:
                        f.write(txt)

            except UnicodeEncodeError:
                QMessageBox.critical(QWidget(), '!!! ' + tr('Encoding error') + ' !!!', \
                    '<h2>' + tr("The file can't be encoded with this encoding") + ' !!!</h2>')
                return -2  #stop

        self.reload()
        QMessageBox.about(
            QWidget(),
            tr('Done') + ' !',
            '<h2>' + tr('Your text has been be wrote') + ' !</h2>')

    #------read_file
    def read_file(self, fn, bytes_md=False, encod='utf-8', silent=True):
        '''
        Read the content of a file and return its content in a string.

        fn : filename ;
        bytes_md : the bytes mode. Should be False for text (default) or True for binary (bytes) ;
        encod : the encoding. Should be "utf-8", "latin-1", "ascii". Default is "utf-8" ;
        silent : should be a bool. If False, show error message box in case if one occur.

        return -1 if the file "fn" was not found, -2 if an encoding error occur, the text otherwise.
        '''

        if bytes_md not in (True, False):
            return 'The bytes_md should be "True" or "False", but "' + str(
                bytes_md) + '" was found !!!'

        try:
            if not bytes_md:  #text
                with open(fn, mode='r', encoding=encod) as file:
                    txt = file.read()

            else:
                with open(fn, mode='rb') as file:
                    txt = file.read()

        except FileNotFoundError:
            if not silent:
                QMessageBox.critical(QWidget(), '!!! ' + tr('File error') + ' !!!', \
                    '<h2>' + tr('The file') + ' "' + str(fn) + '"' + tr(' was NOT found') + ' !!!</h2>')
            return -1

        except UnicodeDecodeError:
            if not silent:
                QMessageBox.critical(QWidget(), '!!! ' + tr('Encoding error') + ' !!!', \
                    '<h2>' + tr('The file can\'t be decoded with this encoding') + ' !!!</h2>')
            return -2

        return txt

    #------reload
    def reload(self):
        '''
        Function which reload the files combo boxes.
        It can be used if a new file was copied while running, for example.
        '''

        self.lst_f = (tr('-- Select a file --'), *list_files(),
                      *self.lst_f_hist)

        self.opt_fn.clear()
        self.opt_fn.addItems((tr('-- Select a file --'), *list_files()))
        self.opt_fn.insertSeparator(1)
        self.opt_fn.insertSeparator(10000)
        if len(self.lst_f_hist) > 0:
            self.opt_fn.addItems(self.lst_f_hist)
            self.opt_fn.insertSeparator(20000)

        if self.fn not in self.lst_f:
            self.fn = tr('-- Select a file --')
            self.opt_fn.setCurrentText(tr('-- Select a file --'))

        else:
            self.opt_fn.setCurrentText(self.fn)

    #------get encoding
    def get_encod(self):
        '''Return the currend selected encoding.'''

        return self.opt_encod.currentText()

    #------get bytes mode
    def get_bytes(self):
        '''Return the bytes, either 't' for text, or 'b' for bytes.'''

        return ('t', 'b')[self.rb_bytes.isChecked()]

    #------getText
    def getText(self, silent=False, from_=None):
        '''
        Return the text selected by the user.

        silent : should be a bool. If False, show popup pointing out the error, if one occur ;
        from_ : where read. Can be None, 'text', 'file'. if None, check the radiobutton. Default is None.

        Return :
            -1 if the file was not found ;
            -2 if an encoding error occur ;
            -3 if aborted ;
            The text otherwise.
        '''

        if from_ not in (None, 'text', 'file'):
            raise ValueError(
                tr('Parameter "from_" should be None, "text" or "file", but') +
                ' "' + str(from_) + '" ' + tr('was found') + ' !!!')

        txt_t = self.txt.toPlainText()

        if self.opt_fn.currentText() != tr('-- Select a file --'):
            txt_f = self.read_file(self.opt_fn.currentText(), \
                self.rb_bytes.isChecked(), self.opt_encod.currentText())

        else:
            txt_f = None

        if from_ == 'text':
            return txt_t

        elif from_ == 'file':
            return txt_f

        if self.rb_txt.isChecked():  # Text is in the text widget
            if txt_t == '' and txt_f not in (None, ''):
                rep = QMessageBox.question(self, '!!! ' + tr('Text is empty') + ' !!!', \
                    '<h3>' + tr('The text widget seem to be empty') + '.</h3>\n<h2>' + tr('Read the file ?') + '</h2>', \
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)

                if rep == QMessageBox.Yes:
                    return txt_f

                else:
                    return -3  # Abort

            elif txt_t == '':
                if not silent:
                    QMessageBox.critical(QWidget(), '!!! ' + tr('Text is empty') + ' !!!', \
                        '<h2>' + tr('The text widget is empty') + ' !!!</h2>')
                return -3  #Abort

            return txt_t

        else:  # Text is in the file
            if txt_f == -1:
                if not silent:
                    QMessageBox.critical(QWidget(), '!!! ' + tr('File error') + ' !!!', \
                        '<h2>' + tr('The file') + ' "' + str(fn) + '" ' + tr('was NOT found') + ' !!!</h2>')
                return -1

            elif txt_f == -2:
                if not silent:
                    QMessageBox.critical(QWidget(), '!!! ' + tr('Encoding error') + ' !!!', \
                        '<h2>' + tr("The file can't be decoded with this encoding") + ' !!!</h2>')
                return -2

            if txt_f == None and txt_t != '':
                rep = QMessageBox.question(self, '!!! ' + tr('No file selected') + ' !!!', \
                    '<h3>' + tr('You did not select a file') + ' !!!</h3>\n<h2>' + tr('Read the text widget ?') + '</h2>', \
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)

                if rep == QMessageBox.Yes:
                    return txt_t

                else:
                    return -3  # Abort

            elif txt_f == None:
                if not silent:
                    QMessageBox.critical(QWidget(), '!!! ' + tr('No file selected') + ' !!!', \
                        '<h2>' + tr('Please select a file') + ' !</h2>')
                return -3

            if txt_f in ('', b'') and txt_t != '':
                rep = QMessageBox.question(self, '!!! ' + tr('File is empty') + ' !!!', \
                    '<h3>' + tr('The file seem to be empty') + '.</h3>\n<h2>' + tr('Read the text widget ?') + '</h2>', \
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)

                if rep == QMessageBox.Yes:
                    return txt_t

                else:
                    return -3  # Abort

            elif txt_f in ('', b''):
                if not silent:
                    QMessageBox.critical(
                        QWidget(), '!!! ' + tr('File is empty') + ' !!!',
                        '<h2>' + tr('The file is empty') + ' !!!</h2>')
                return -3

            return txt_f

    def setText(self, txt):
        '''Fill the text widget or the file with txt, according to the radiobuttons.'''

        txt_t = self.txt.toPlainText()

        if self.opt_fn.currentText() != tr('-- Select a file --'):
            txt_f = self.read_file(self.opt_fn.currentText(), \
                self.rb_bytes.isChecked(), self.opt_encod.currentText())

        else:
            txt_f = None

        if self.rb_txt.isChecked():  # The text widget is chosen
            if txt_t != '' and txt_f == '':
                rep = QMessageBox.question(self, '!!! ' + tr('Text is not empty') + ' !!!', \
                    '<h2>' + tr('The text widget is not empty, but the file is') + '.</h2>\n<h3>' + tr('Write the file (Yes) or overwrite text (Ignore) ?') + '</h3>', \
                    QMessageBox.Yes | QMessageBox.Ignore | QMessageBox.Cancel, QMessageBox.Ignore)

                if rep == QMessageBox.Yes:
                    self.save_fn(txt)

                elif rep == QMessageBox.Ignore:
                    self.txt.setPlainText(txt)

                else:
                    return -3  # Abort

            else:
                self.txt.setPlainText(txt)

        else:  # The file is chosen
            if txt_f == -1:
                rep = QMessageBox.question(self, '!!! ' + tr('File error') + ' !!!', \
                    '<h2>' + tr('The file') + ' "' + str(fn) + '" ' + tr('was NOT found') + ' !!!</h2>\n<h3>' + tr('Write in the text widget ?') + '</h3>', \
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)

                if rep == QMessageBox.Yes:
                    self.txt.setPlainText(txt)

                else:
                    return -1

            else:
                self.save_fn(txt)
Example #17
0
class QualityRateControlTab(QWidget):
    optionchanged = pyqtSignal()

    def __init__(self, encoder, *args, **kwargs):
        super(QualityRateControlTab, self).__init__(*args, **kwargs)
        self.encoder = encoder

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

        self.rateControlSelection = QComboBox(self)
        self.rateControlSelection.addItem("Not set")
        self.rateControlSelection.insertSeparator(1)
        self.rateControlSelection.addItem("Bitrate", 0)
        self.rateControlSelection.addItem("CRF", 1)
        self.rateControlSelection.addItem("QP", 2)
        self.rateControlSelection.addItem("Lossless", 3)

        self.bitrateSpinBox = QSpinBox(self)
        self.bitrateSpinBox.setMinimum(200)
        self.bitrateSpinBox.setValue(8000)
        self.bitrateSpinBox.setSuffix("kbps")
        self.bitrateSpinBox.setMaximum(60000)
        self.bitrateSpinBox.setSingleStep(100)
        self.bitrateSpinBox.setHidden(True)

        self.crfSpinBox = QDoubleSpinBox(self)
        self.crfSpinBox.setMinimum(0)
        self.crfSpinBox.setValue(28)
        self.crfSpinBox.setMaximum(51)
        self.crfSpinBox.setSingleStep(0.1)
        self.crfSpinBox.setDecimals(2)
        self.crfSpinBox.setHidden(True)

        self.qpSpinBox = QSpinBox(self)
        self.qpSpinBox.setMinimum(0)
        self.qpSpinBox.setValue(22)
        self.qpSpinBox.setMaximum(54)
        self.qpSpinBox.setSingleStep(1)
        self.qpSpinBox.setHidden(True)

        self.rcSpacer = QWidget(self)
        self.rcSpacer.setHidden(True)

        self.bitrateSpinBox.setFixedWidth(96)
        self.crfSpinBox.setFixedWidth(96)
        self.qpSpinBox.setFixedWidth(96)
        self.rcSpacer.setFixedWidth(96)

        if encoder.bitrate is not None:
            idx = self.rateControlSelection.findData(0)
            self.rateControlSelection.setCurrentIndex(idx)
            self.bitrateSpinBox.setValue(encoder.bitrate)
            self.bitrateSpinBox.setVisible(True)

        elif encoder.crf is not None:
            idx = self.rateControlSelection.findData(1)
            self.rateControlSelection.setCurrentIndex(idx)
            self.crfSpinBox.setValue(encoder.crf)
            self.crfSpinBox.setVisible(True)

        elif encoder.qp is not None:
            idx = self.rateControlSelection.findData(2)
            self.rateControlSelection.setCurrentIndex(idx)
            self.qpSpinBox.setValue(encoder.qp)
            self.qpSpinBox.setVisible(True)

        elif encoder.lossless:
            idx = self.rateControlSelection.findData(3)
            self.rateControlSelection.setCurrentIndex(idx)

        else:
            self.rateControlSelection.setCurrentIndex(0)
            self.rcSpacer.setVisible(True)

        self.rateControlSelection.currentIndexChanged.connect(
            self.onRateControlModeChange)
        self.bitrateSpinBox.valueChanged.connect(self.setBitrate)
        self.crfSpinBox.valueChanged.connect(self.setCRF)
        self.qpSpinBox.valueChanged.connect(self.setQP)

        hlayout = QHBoxLayout()
        hlayout.addWidget(QLabel("Rate Control"))
        hlayout.addStretch()
        hlayout.addWidget(self.rateControlSelection)
        hlayout.addWidget(self.bitrateSpinBox)
        hlayout.addWidget(self.crfSpinBox)
        hlayout.addWidget(self.qpSpinBox)
        hlayout.addWidget(self.rcSpacer)
        layout.addLayout(hlayout)

        self.aqmotion = BoolOption(encoder, "AQ Motion", "aq-motion", self)
        self.aqmotion.stateChanged.connect(self.optionchanged.emit)
        self.aqmotion.setToolTip("""
            <b>--aq-motion, --no-aq-motion</b>
            <p>Adjust the AQ offsets based on the relative motion of each
            block with respect to the motion of the frame. The more the
            relative motion of the block, the more quantization is used.</p>
            <p>Default disabled. <b>Experimental Feature.</b></p>
            """)
        layout.addWidget(self.aqmotion)

        self.aqmode = Choices(
            encoder, "AQ Mode", "aq-mode",
            [("Disabled", 0), ("AQ Enabled", 1),
             ("AQ enabled with auto-variance", 2),
             ("AQ enabled with auto-variance and bias to dark scenes", 3),
             ("AQ enabled with auto-variance and edge information", 4)], self)
        self.aqmode.selection.currentIndexChanged.connect(
            self.optionchanged.emit)
        self.aqmode.setToolTip("""
            <b>--aq-mode &lt;0|1|2|3|4&gt;</b>
            <p>Adaptive Quantization operating mode. Raise or lower per-block
            quantization based on complexity analysis of the source image. The
            more complex the block, the more quantization is used. These
            offsets the tendency of the encoder to spend too many bits on
            complex areas and not enough in flat areas.</p>
            """)
        layout.addWidget(self.aqmode)

        self.aqstrength = FloatOption(encoder, "AQ Strength", "aq-strength", 0,
                                      3, 1, 2, self)
        self.aqstrength.spinbox.valueChanged.connect(self.optionchanged.emit)
        self.aqstrength.setToolTip("""
            <b>--aq-strength &lt;float&gt;</b>
            <p>Adjust the strength of the adaptive quantization offsets.
            Setting <span class="pre">--aq-strength</span> to 0 disables AQ.
            At aq-modes 2 and 3, high aq-strengths will lead to high QP
            offsets resulting in a large difference in achieved bitrates.</p>
            <p>Default 1.0. Range of values: 0.0 to 3.0</p>
            """)
        layout.addWidget(self.aqstrength)

        self.qgsize = Choices(encoder, "QG Size", "qg-size", [("8", 8),
                                                              ("16", 16),
                                                              ("32", 32),
                                                              ("64", 64)],
                              self)
        self.qgsize.selection.currentIndexChanged.connect(
            self.optionchanged.emit)
        self.qgsize.setToolTip("""
            <b>--qg-size &lt;64|32|16|8&gt;</b>
            <p>Enable adaptive quantization for sub-CTUs. This parameter
            specifies the minimum CU size at which QP can be adjusted, ie.
            Quantization Group size. Allowed range of values are 64, 32, 16, 8
            provided this falls within the inclusive range [maxCUSize,
            minCUSize].</p>
            <p>Default: same as maxCUSize</p>
            """)
        layout.addWidget(self.qgsize)
        """
        TODO:
        --vbv-bufsize
        --vbv-maxrate
        --vbv-init
        --vbv-end
        --vbv-end-fr-adj

        --crf-max
        --crf-min

        --qpmin
        --qpmax

        --lossless

        --aq-motion
        --hevc-aq
        --qp-adaptation-range
        #--qg-size
        --cutree
        --slow-firstpass
        --multi-pass-opt-analysis
        --multi-pass-opt-distortion
        --strict-cbr
        --cbqpoffs
        --crqpoffs
        --ipratio
        --pbratio
        --qcomp
        --qpstep
        --rc-grain
        --const-vbv
        --qblur
        --cplxblur
        --scenecut-aware-qp
        --scenecut-window
        --max-qp-delta
        """

        layout.addStretch()

    def onRateControlModeChange(self, index):
        data = self.rateControlSelection.currentData()

        if data == 0:
            self.encoder.bitrate = self.bitrateSpinBox.value()
            self.encoder.crf = None
            self.encoder.qp = None
            self.encoder.lossless = None

            self.crfSpinBox.setHidden(True)
            self.qpSpinBox.setHidden(True)
            self.rcSpacer.setHidden(True)
            self.bitrateSpinBox.setHidden(False)

        elif data == 1:
            self.encoder.bitrate = None
            self.encoder.crf = self.crfSpinBox.value()
            self.encoder.qp = None
            self.encoder.lossless = None

            self.bitrateSpinBox.setHidden(True)
            self.qpSpinBox.setHidden(True)
            self.rcSpacer.setHidden(True)
            self.crfSpinBox.setHidden(False)

        elif data == 2:
            self.encoder.bitrate = None
            self.encoder.crf = None
            self.encoder.qp = self.qpSpinBox.value()
            self.encoder.lossless = None

            self.bitrateSpinBox.setHidden(True)
            self.crfSpinBox.setHidden(True)
            self.rcSpacer.setHidden(True)
            self.qpSpinBox.setHidden(False)

        elif data == 3:
            self.encoder.bitrate = None
            self.encoder.crf = None
            self.encoder.qp = None
            self.encoder.lossless = True

            self.bitrateSpinBox.setHidden(True)
            self.crfSpinBox.setHidden(True)
            self.qpSpinBox.setHidden(True)
            self.rcSpacer.setHidden(False)

        else:
            self.encoder.bitrate = None
            self.encoder.crf = None
            self.encoder.qp = None
            self.encoder.lossless = None

            self.crfSpinBox.setHidden(True)
            self.qpSpinBox.setHidden(True)
            self.bitrateSpinBox.setHidden(True)
            self.rcSpacer.setHidden(False)

        self.optionchanged.emit()

    def setBitrate(self, value):
        self.encoder.bitrate = value
        self.optionchanged.emit()

    def setCRF(self, value):
        self.encoder.crf = value
        self.optionchanged.emit()

    def setQP(self, value):
        self.encoder.qp = value
        self.optionchanged.emit()
Example #18
0
class ControlButtonsHolder(QWidget):
    """
        +---- Control ButtonsHolder (QWidget) -----------------+
        | +---- self_layout (QHBoxLayout) -------------------+ |
        | | +----+       +----++--------------+       +----+ | |
        | | |Back|       |Play||     List     |       |Hier| | |
        | | +----+       +----++--------------+       +----+ | |
        | +--------------------------------------------------+ |
        +------------------------------------------------------+
    
    """
    def __init__(self, control_panel):
        super().__init__()

        self.control_panel = control_panel

        self_layout = QHBoxLayout(self)
        self.setLayout(self_layout)

        self_layout.setContentsMargins(0, 0, 0, 0)
        self_layout.setSpacing(5)

        # -------------
        #
        # Back Button
        #
        # -------------
        self.back_button_method = None

        back_button = QPushButton()
        back_button.setFocusPolicy(Qt.NoFocus)
        back_button.clicked.connect(self.back_button_on_click)

        back_icon = QIcon()
        back_icon.addPixmap(
            QPixmap(
                resource_filename(
                    __name__,
                    os.path.join(
                        CONTROL_IMG_FOLDER, CONTROL_IMG_BACK_BUTTON + "-" +
                        ON + "." + CONTROL_IMG_EXTENTION))), QIcon.Active)
        back_icon.addPixmap(
            QPixmap(
                resource_filename(
                    __name__,
                    os.path.join(
                        CONTROL_IMG_FOLDER, CONTROL_IMG_BACK_BUTTON + "-" +
                        OFF + "." + CONTROL_IMG_EXTENTION))), QIcon.Disabled)
        back_button.setIcon(back_icon)
        back_button.setIconSize(QSize(CONTROL_IMG_SIZE, CONTROL_IMG_SIZE))
        back_button.setCursor(QCursor(Qt.PointingHandCursor))
        back_button.setStyleSheet("background:transparent; border:none")

        # Back button on the left
        self_layout.addWidget(back_button)

        self_layout.addStretch(1)

        # ================================================
        # ================================================

        # -------------------
        #
        # Play Sequentially Button
        #
        # -------------------

        self.play_continously_button = QPushButton()
        self.play_continously_button.setFocusPolicy(Qt.NoFocus)
        self.play_continously_button.clicked.connect(
            self.play_continously_button_on_click)

        play_continously_icon = QIcon()
        play_continously_icon.addPixmap(
            QPixmap(
                resource_filename(
                    __name__,
                    os.path.join(
                        CONTROL_IMG_FOLDER, CONTROL_IMG_PLAY_BUTTON + "." +
                        CONTROL_IMG_EXTENTION))), QIcon.Normal, QIcon.On)
        #        play_continously_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join(CONTROL_IMG_FOLDER, CONTROL_IMG_PLAY_BUTTON + "-" + ON + "." + CONTROL_IMG_EXTENTION)) ), QIcon.Normal, QIcon.On)
        self.play_continously_button.setIcon(play_continously_icon)
        self.play_continously_button.setIconSize(QSize(25, 25))
        self.play_continously_button.setCursor(QCursor(Qt.PointingHandCursor))
        self.play_continously_button.setStyleSheet(
            "background:transparent; border:none")

        # Play button on the middle
        self_layout.addWidget(self.play_continously_button)

        # -------------------
        #
        # Stop Button
        #
        # -------------------
        self.stop_continously_button = QPushButton()
        self.stop_continously_button.setFocusPolicy(Qt.NoFocus)
        self.stop_continously_button.clicked.connect(
            self.stop_continously_button_on_click)

        stop_continously_icon = QIcon()
        stop_continously_icon.addPixmap(
            QPixmap(
                resource_filename(
                    __name__,
                    os.path.join(
                        CONTROL_IMG_FOLDER, CONTROL_IMG_STOP_BUTTON + "." +
                        CONTROL_IMG_EXTENTION))), QIcon.Normal, QIcon.On)
        #        stop_continously_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join(CONTROL_IMG_FOLDER, CONTROL_IMG_STOP_BUTTON + "-" + OFF + "." + CONTROL_IMG_EXTENTION)) ), QIcon.Normal, QIcon.Off)
        self.stop_continously_button.setIcon(stop_continously_icon)
        self.stop_continously_button.setIconSize(QSize(25, 25))
        self.stop_continously_button.setCursor(QCursor(Qt.PointingHandCursor))
        self.stop_continously_button.setStyleSheet(
            "background:transparent; border:none")

        # Stop button on the middle
        self_layout.addWidget(self.stop_continously_button)

        # ----------------------------------
        #
        # Playing Continously list drop-down
        #
        # ----------------------------------

        self.dropdown_play_continously = QComboBox(self)
        self.dropdown_play_continously.setFocusPolicy(Qt.NoFocus)
        self.dropdown_play_continously.setEditable(False)

        # listener for selection changed
        #self.dropdown_play_continously.currentIndexChanged.connect(self.play_continously_selection_changed_listener)

        style_box = '''
           QComboBox { 
               max-width: 500px; min-width: 300px; border: 1px solid gray; border-radius: 5px;
           }
        '''
        style_drop_down = '''
           QComboBox QAbstractItemView::item { 
               color: red;
               max-height: 15px;
           }
        '''

        self.dropdown_play_continously.setStyleSheet(style_box)
        #self.dropdown_play_continously.addItem("")
        self_layout.addWidget(self.dropdown_play_continously)

        self.disablePlayStopContinously()

        self_layout.addStretch(1)

        # ================================================
        # ================================================

        # ----------------
        #
        # Hierarchy Button
        #
        # ----------------
        self.hierarchy_button_method = None

        self.hierarchy_button = QPushButton()
        self.hierarchy_button.setFocusPolicy(Qt.NoFocus)
        self.hierarchy_button.setCheckable(True)
        self.hierarchy_button.toggled.connect(self.hierarchy_button_on_toggle)

        hierarchy_icon = QIcon()
        hierarchy_icon.addPixmap(
            QPixmap(
                resource_filename(
                    __name__,
                    os.path.join(
                        CONTROL_IMG_FOLDER, CONTROL_IMG_HIERARCHY_BUTTON +
                        "-" + ON + "." + CONTROL_IMG_EXTENTION))),
            QIcon.Normal, QIcon.On)
        hierarchy_icon.addPixmap(
            QPixmap(
                resource_filename(
                    __name__,
                    os.path.join(
                        CONTROL_IMG_FOLDER, CONTROL_IMG_HIERARCHY_BUTTON +
                        "-" + OFF + "." + CONTROL_IMG_EXTENTION))),
            QIcon.Normal, QIcon.Off)
        self.hierarchy_button.setIcon(hierarchy_icon)
        self.hierarchy_button.setIconSize(
            QSize(CONTROL_IMG_SIZE, CONTROL_IMG_SIZE))
        self.hierarchy_button.setCursor(QCursor(Qt.PointingHandCursor))
        self.hierarchy_button.setStyleSheet(
            "background:transparent; border:none")

        # Hierarchy button on the right
        self_layout.addWidget(self.hierarchy_button)

        #        # ================================================
        #        # ================================================

        # Initiate the PlayerThread
        ins = PlayerThread.getInstance()
        ins.startNextPlaying.connect(self.start_next_playing_emmitted)
        ins.stopPlayingAll.connect(self.stop_playing_all_emmitted)

        # -------------------
        #
        # Fast Search Button
        #
        # -------------------
#        self.fast_search_button = QPushButton()
#        self.fast_search_button.setFocusPolicy(Qt.NoFocus)
#        self.fast_search_button.setCheckable(True)
#        self.fast_search_button.setAutoExclusive(False)
#        self.fast_search_button.toggled.connect(self.fast_search_button_on_click)
#
#        fast_search_icon = QIcon()
#        fast_search_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join("img", IMG_FAST_SEARCH_BUTTON_ON)) ), QIcon.Normal, QIcon.On)
#        fast_search_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join("img", IMG_FAST_SEARCH_BUTTON_OFF)) ), QIcon.Normal, QIcon.Off)
#        self.fast_search_button.setIcon( fast_search_icon )
#        self.fast_search_button.setIconSize(QSize(25,25))
#        self.fast_search_button.setCursor(QCursor(Qt.PointingHandCursor))
#        self.fast_search_button.setStyleSheet("background:transparent; border:none")
#        self_layout.addWidget( self.fast_search_button )
#
#        # -------------------
#        #
#        # Advanced Search Button
#        #
#        # -------------------
#        self.advanced_search_button = QPushButton()
#        self.advanced_search_button.setFocusPolicy(Qt.NoFocus)
#        self.advanced_search_button.setCheckable(True)
#        self.advanced_search_button.setAutoExclusive(False)
#        self.advanced_search_button.toggled.connect(self.advanced_search_button_on_click)
#
#        advanced_search_icon = QIcon()
#        advanced_search_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join("img", IMG_ADVANCED_SEARCH_BUTTON_ON)) ), QIcon.Normal, QIcon.On)
#        advanced_search_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join("img", IMG_ADVANCED_SEARCH_BUTTON_OFF)) ), QIcon.Normal, QIcon.Off)
#        self.advanced_search_button.setIcon( advanced_search_icon )
#        self.advanced_search_button.setIconSize(QSize(25,25))
#        self.advanced_search_button.setCursor(QCursor(Qt.PointingHandCursor))
#        self.advanced_search_button.setStyleSheet("background:transparent; border:none")
#        self_layout.addWidget( self.advanced_search_button )
#
#        # ================================================
#        # ================================================
#
#        # -------------------
#        #
#        # Config Button
#        #
#        # -------------------
#        self.config_button = QPushButton()
#        self.config_button.setFocusPolicy(Qt.NoFocus)
#        self.config_button.setCheckable(False)
#        self.config_button.clicked.connect(self.config_button_on_click)
#
#        config_icon = QIcon()
#        config_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join("img", IMG_CONFIG_BUTTON)) ), QIcon.Normal, QIcon.On)
#        self.config_button.setIcon( config_icon )
#        self.config_button.setIconSize(QSize(25,25))
#        self.config_button.setCursor(QCursor(Qt.PointingHandCursor))
#        self.config_button.setStyleSheet("background:transparent; border:none")
#        self_layout.addWidget( self.config_button )
#
#        self.enableSearchIcons(False)
#        self.disablePlayStopContinously()
#
#    # ======================================================
#

    def clear_play_continously_elements(self):
        self.dropdown_play_continously.clear()

    def add_play_continously_separator(self):
        self.dropdown_play_continously.insertSeparator(
            self.dropdown_play_continously.__len__())

    def add_play_continously_element(self, title, media_path, media_type):
        self.dropdown_play_continously.addItem(title, (media_path, media_type))

    def get_play_continously_selected_path(self):
        return self.dropdown_play_continously.itemData(
            self.dropdown_play_continously.currentIndex())

    def get_play_continously_media_path_by_index(self, index):
        return self.dropdown_play_continously.itemData(index)[0]

    def get_play_continously_media_type_by_index(self, index):
        return self.dropdown_play_continously.itemData(index)[1]

    def get_play_continously_data_list(self):
        items = []
        for index in range(self.dropdown_play_continously.count()):
            items.append((self.dropdown_play_continously.itemText(index), ) +
                         self.dropdown_play_continously.itemData(index))
        return items

    def get_play_continously_selected_title(self):
        return self.dropdown_play_continously.itemText(
            self.dropdown_play_continously.currentIndex())

    def get_play_continously_title_by_index(self, index):
        return self.dropdown_play_continously.itemText(index)

    def get_play_continously_selected_index(self):
        return self.dropdown_play_continously.currentIndex()

    def get_play_continously_last_index(self):
        return self.dropdown_play_continously.count() - 1

    def select_play_continously_element_by_index(self, index):
        self.dropdown_play_continously.setCurrentIndex(index)

    # ======================================================

    def disablePlayStopContinously(self):
        self.play_continously_button.setEnabled(False)
        self.stop_continously_button.setEnabled(False)
        self.dropdown_play_continously.setEnabled(False)

    def enablePlayContinously(self, enabled):
        self.play_continously_button.setEnabled(enabled)
        self.stop_continously_button.setEnabled(not enabled)
        self.dropdown_play_continously.setEnabled(enabled)

    # =====================================================

    # =================================================
    #
    # Image/Appendix CLICK button
    #
    # =================================================
    def image_or_appendix_on_click(self, list_to_play):

        #        self.control_panel.gui.refreshPlayContinouslyListBeforeStartPlaying(index)
        #        print("Disabled Play, Enabled Stop and selected Index:", index)

        PlayerThread.play(list_to_play)

    # =================================================
    #
    # Play Contionusly STOP button
    #
    # =================================================
    def stop_continously_button_on_click(self):
        """
        Stops the continous play
        This method is called when the Play continously Stop button is pushed
        
        It stops the actually playing media, 
        It breaks Play Continouisly list

        in the PlayerThread.stop() method it sets the __run=False and emit the stopPlaying event
        the stopPlaying is connected to the stop_playing_listener() method
        """

        PlayerThread.stop()

    # =========================================
    #
    # Play Continously PLAY button
    #
    # =========================================
    def play_continously_button_on_click(self):
        """
        Select the list from the actual media till the end and starts to play it        
        This method is called when the Play Continously Play button is pushed
            
        """
        start_index = self.get_play_continously_selected_index()
        last_index = self.get_play_continously_last_index()
        list_to_play = []
        for actual_index in range(start_index, last_index + 1):
            list_to_play.append({
                'media-index':
                actual_index,
                'media-path':
                self.get_play_continously_media_path_by_index(actual_index),
                'media-type':
                self.get_play_continously_media_type_by_index(actual_index)
            })

        PlayerThread.play(list_to_play)

    # ---------------------------------------------
    #
    # startNextPlaying Emmitted in PlayThread
    #
    # ---------------------------------------------
    def start_next_playing_emmitted(self, index):
        """
        Disable the Play button, Enable the Stop button and select the next value
        in the Play list according to the index. 
        This method is called from the PlayerThread object when the next media is started
        """
        self.select_play_continously_element_by_index(index)
        self.control_panel.gui.refreshPlayContinouslyListBeforeStartPlaying(
            index)

    # ---------------------------------------------
    #
    # startNextPlaying Emmitted in PlayThread
    #
    # ---------------------------------------------
    def stop_playing_all_emmitted(self):
        """
        This method is called from the PlayedThread object when the Stop button is pushed

        Enables the the Play button and disable the Stop button
        Refreshes the Play Continously List
        """
        #self.enablePlayContinously(True)

        self.control_panel.gui.refreshPlayContinouslyListAfterStopPlaying()

    def play_continously_selection_changed_listener(self, index):
        """
        Focus the card according to the selected value in the Play list
        This method is called when the selected element changed in the Play list
        """
        if index >= 0:
            self.control_panel.gui.card_holder.focus_index(index)

#    # --------------------------
#    #
#    # Fast Search Button Clicked
#    #
#    # --------------------------
#    def fast_search_button_on_click(self, checked):
#        if checked:
#            self.advanced_search_button.setChecked(False)
#        # hide/show fast filter
#        self.control_panel.fast_filter_holder.setHidden(not checked)
#        # filter the list
#        self.control_panel.fast_filter_on_change()
#
#    # ------------------------------
#    #
#    # Advanced Search Button Clicked
#    #
#    # ------------------------------
#    def advanced_search_button_on_click(self, checked):
#        if checked:
#            self.fast_search_button.setChecked(False)
#        # hide/show advanced filter
#        self.control_panel.advanced_filter_holder.setHidden(not checked)
#        # filter the list
#        self.control_panel.advanced_filter_filter_on_click()

    def setBackButtonMethod(self, back_button_method):
        self.back_button_method = back_button_method

    def setHierarchyButtonMethod(self, hierarchy_button_method):
        self.hierarchy_button_method = hierarchy_button_method

    def setHierarchy(self, show):
        self.hierarchy_button.setChecked(show)

    # -------------------
    #
    # Back Button Clicked
    #
    # -------------------
    def back_button_on_click(self):
        if self.back_button_method:
            self.back_button_method()

    # -------------------
    #
    # Back Button Clicked
    #
    # -------------------
    def hierarchy_button_on_toggle(self, checked):
        if self.hierarchy_button_method:
            self.hierarchy_button_method(checked)
class GUIToolMaterialsDatabase(BaseToolMaterialsDatabase, QTool):
    """[summary]
    
    [description]
    """
    def __init__(self, name='', parent_app=None):
        """
        **Constructor**
        
        Keyword Arguments:
            - name {[type]} -- [description] (default: {''})
            - parent_dataset {[type]} -- [description] (default: {None})
            - ax {[type]} -- [description] (default: {None})
        """
        super().__init__(name, parent_app)
        self.update_parameter_table()
        self.parent_application.update_all_ds_plots()

        # add widgets specific to the Tool here:
        self.active = False
        self.applytotheory = False
        self.actionActive.setVisible(False)
        self.actionApplyToTheory.setVisible(False)
        self.cbmaterial = QComboBox()
        self.cbmaterial.setToolTip("Choose a Material from the database")
        model = self.cbmaterial.model()
        i = 0
        for polymer in materials_database.keys():
            item = QStandardItem(polymer)
            item.setToolTip(materials_database[polymer].data['long'])
            model.appendRow(item)
            i += 1
        self.num_materials_base = i
        self.cbmaterial.insertSeparator(i)
        for polymer in materials_user_database.keys():
            item = QStandardItem(polymer)
            item.setToolTip(materials_user_database[polymer].data['long'])
            model.appendRow(item)
        self.tb.addWidget(self.cbmaterial)
        connection_id = self.cbmaterial.currentIndexChanged.connect(
            self.change_material)

        self.actionCalculate = QAction(
            QIcon(':/Icon8/Images/new_icons/icons8-ok.png'), "Calculate stuff",
            self)
        self.tb.addAction(self.actionCalculate)
        self.actionNew = QAction(
            QIcon(':/Icon8/Images/new_icons/icons8-add-file.png'),
            "New Material", self)
        self.tb.addAction(self.actionNew)
        self.actionEdit = QAction(
            QIcon(':/Icon8/Images/new_icons/icons8-edit-property.png'),
            "Edit/View Material Properties", self)
        self.tb.addAction(self.actionEdit)
        self.actionSave = QAction(
            QIcon(':/Icon8/Images/new_icons/icons8-save.png'),
            "Save User Material Database", self)
        self.tb.addAction(self.actionSave)
        connection_id = self.actionCalculate.triggered.connect(
            self.calculate_stuff)

        self.labelPolymer = QLabel("None")
        self.labelPolymer.setFont(QFont("Times", weight=QFont.Bold))
        self.verticalLayout.insertWidget(1, self.labelPolymer)

        self.tbMwT = QToolBar()
        self.tbMwT.setIconSize(QSize(24, 24))
        lbl1 = QLabel("Mw (kDa)")
        lbl1.setFont(QFont("Times", weight=QFont.Bold))
        self.tbMwT.addWidget(lbl1)
        self.editMw = QLineEdit("1")
        self.editMw.setStyleSheet(
            "QLineEdit { background: rgb(255, 255, 205);}")
        self.editMw.setFixedWidth(40)
        self.tbMwT.addWidget(self.editMw)
        lbl2 = QLabel("T (°C)")
        lbl2.setFont(QFont("Times", weight=QFont.Bold))
        self.tbMwT.addWidget(lbl2)
        self.editT = QLineEdit("0")
        self.editT.setStyleSheet(
            "QLineEdit { background: rgb(255, 255, 205);}")
        self.editT.setFixedWidth(40)
        self.tbMwT.addWidget(self.editT)
        self.verticalshift = self.tbMwT.addAction(
            QIcon(':/Icon8/Images/new_icons/icons8-vertical-shift.png'),
            'Vertical shift')
        self.verticalshift.setCheckable(True)
        self.verticalshift.setChecked(True)
        self.isofrictional = self.tbMwT.addAction(
            QIcon(':/Icon8/Images/new_icons/icons8-iso.png'),
            "Shift to isofrictional state")
        self.isofrictional.setCheckable(True)
        self.isofrictional.setChecked(True)
        self.verticalLayout.insertWidget(2, self.tbMwT)

        self.change_material()

    def change_material(self):
        selected_material_name = self.cbmaterial.currentText()
        if (self.cbmaterial.currentIndex() < self.num_materials_base):
            dbindex = 1
        else:
            dbindex = 0
        self.labelPolymer.setText(
            materials_db[dbindex][selected_material_name].data['long'])
        for k in materials_db[dbindex][selected_material_name].data.keys():
            self.set_param_value(
                k, materials_db[dbindex][selected_material_name].data[k])
        self.update_parameter_table()

    def calculate_stuff(self):
        Mw = float(self.editMw.text())
        T = float(self.editT.text())
        B1 = self.parameters['B1'].value
        B2 = self.parameters['B2'].value
        logalpha = self.parameters['logalpha'].value
        alpha = np.power(10.0, logalpha)
        CTg = self.parameters['CTg'].value
        tau_e = self.parameters['tau_e'].value
        Ge = self.parameters['Ge'].value
        Me = self.parameters['Me'].value
        c_nu = self.parameters['c_nu'].value
        rho0 = self.parameters['rho0'].value
        Te = self.parameters['Te'].value
        iso = self.isofrictional.isChecked()
        vert = self.verticalshift.isChecked()

        if iso:
            B2 += CTg / Mw  #- 68.7 * dx12
            Trcorrected = T - CTg / Mw  #+ 68.7 * dx12
        else:
            Trcorrected = T

        aT = np.power(
            10.0, -B1 * (Te - Trcorrected) / (B2 + Trcorrected) / (B2 + Te))
        if vert:
            bT = (1 + alpha * Te) * (T + 273.15) / (1 + alpha * T) / (Te +
                                                                      273.15)
        else:
            bT = 1

        self.Qprint('<hr><h3>WLF TTS Shift Factors</h3>')
        # Need T1 (to shift from) and T2 (to shift to), if we want to report aT and bT
        self.Qprint("<b>C1</b> = %g" % (B1 / (B2 + T)))
        self.Qprint("<b>C2</b> = %g<br>" % (B2 + T))

        self.Qprint('<h3>Tube Theory parameters</h3>')
        Ge /= bT
        tau_e /= aT
        self.Qprint("<b>tau_e</b> = %g" % tau_e)
        self.Qprint("<b>Ge</b> = %g<br>" % Ge)

        self.Qprint('<h3>Other Results</h3>')
        CC1 = 1.69
        CC2 = 4.17
        CC3 = -1.55
        Z = Mw / Me
        tR = tau_e * Z * Z
        tD = 3 * tau_e * Z**3 * (1 - 2 * CC1 / np.sqrt(Z) + CC2 / Z +
                                 CC3 / Z**1.5)
        self.Qprint("<b>Z</b> = %g" % Z)
        self.Qprint("<b>tau_R</b> = %g" % tR)
        self.Qprint("<b>tau_D</b> = %g<br>" % tD)
Example #20
0
    def init_options(self):
        if self.layout() is None:
            self.center()
            self.setWindowTitle('Options')
            # Grid for checkbox options
            pref_header = QLabel('Preferences')
            pref_header.setObjectName('preferences')  # In order to customize style in stylesheet

            set_header = QLabel('Settings')
            set_header.setObjectName('settings')
            h_line = QFrame()
            h_line.setFrameShape(QFrame.HLine)

            set_dir = QLabel('Set Screenshot Directory:')
            set_album = QLabel('Set imgur Album:')

            cb_click_send = QCheckBox('Click Balloon to Copy Image Link', self)
            cb_click_send.setChecked(True)

            cb_no_copy = QCheckBox('Never Copy Image Link')
            cb_auto_open = QCheckBox('Open Image in Browser')
            cb_auto_send = QCheckBox('Automatically Copy Image Link')
            cb_launch_start = QCheckBox('Launch on Start up')

            cb_launch_start.setDisabled(True)
            cb_no_copy.setChecked(True)
            cb_no_copy.setDisabled(True)

            cb_click_send.stateChanged.connect(lambda: cb_no_copy.setChecked(not cb_no_copy.isChecked()))
            cb_click_send.stateChanged.connect(lambda: cb_auto_send.setDisabled(cb_auto_send.isEnabled()))
            cb_click_send.stateChanged.connect(lambda: cb_auto_send.setChecked(cb_auto_send.isChecked()))
            cb_click_send.stateChanged.connect(self.toggle_click)

            cb_click_send.stateChanged.emit(1)

            cb_auto_send.stateChanged.connect(lambda: cb_click_send.setDisabled(cb_click_send.isEnabled()))
            cb_auto_send.stateChanged.connect(lambda: cb_click_send.setChecked(cb_click_send.isChecked()))
            cb_auto_send.stateChanged.connect(lambda: cb_no_copy.setChecked(not cb_no_copy.isChecked()))
            cb_auto_send.stateChanged.connect(self.toggle_auto_upload)

            cb_auto_open.stateChanged.connect(self.toggle_auto_open)

            dir_field = QLineEdit()
            dir_field.insert(self.scan_dir)

            album_choice = QComboBox()
            album_list = [alb for alb in self.albums.keys() if alb != 'Main']
            album_choice.addItems(album_list)

            album_choice.insertSeparator(len(album_list) + 1)
            album_choice.insertItem(len(album_list) + 2, 'Main')
            album_choice.setCurrentIndex(len(album_list) + 1)

            album_choice.activated[str].connect(self.set_album)

            set_dir_button = QPushButton("Set")
            set_dir_button.clicked.connect(lambda: self.select_dir(dir_field))
            set_dir_button.setMaximumWidth(80)

            options_layout = QGridLayout()
            options_layout.addWidget(pref_header, 0, 0)
            options_layout.addWidget(cb_click_send, 1, 0)
            options_layout.addWidget(cb_auto_send, 2, 0)
            options_layout.addWidget(cb_no_copy, 3, 0)
            options_layout.addWidget(cb_auto_open, 4, 0)
            options_layout.addWidget(h_line, 5, 0)
            options_layout.addWidget(cb_launch_start, 6, 0)

            options_layout.addWidget(set_header, 7, 0)
            options_layout.addWidget(set_dir, 8, 0)
            options_layout.addWidget(dir_field, 9, 0)
            options_layout.addWidget(set_dir_button, 10, 0)
            options_layout.addWidget(set_album, 11, 0)
            options_layout.addWidget(album_choice, 12, 0)
            ok_button = QPushButton("Ok")
            ok_button.clicked.connect(self.close)
            # cancel_button = QPushButton("Cancel")

            # Window Layout
            hbox = QHBoxLayout()
            hbox.addWidget(ok_button)
            # hbox.addWidget(cancel_button)  # Add this later
            hbox.addStretch(1)

            vbox = QVBoxLayout()
            vbox.addLayout(options_layout)
            vbox.addLayout(hbox)

            self.setLayout(vbox)
            self.setStyleSheet("""
                QWidget {
                    background-color: rgb(50,50,50);
                }
                QLineEdit {
                    border-color: 1px white;
                    border-radius: 3px;
                    padding: 0 8px;
                    selection-color: #85BF25;
                    background-color: white;
                }
                QComboBox {
                    color: black;
                    background-color: white;
                    selection-background-color: rgb(50,50,50);
                    selection-color: #85BF25;
                    border: 1px black;
                    border-radius: 3px;
                    padding: 1px 18px 1px 3px;
                    min-width: 6em;
                }
                QComboBox QListView{
                    color: white;
                    border: 1px black;
                    border-radius: 3px;
                    padding: 1px 18px 1px 3px;
                    min-width: 6em;
                    border-color: #85BF25;
                }
                QComboBox::drop-down {
                    width: 15px;
                }
                QLabel#preferences {
                    color: #85BF25;
                    font: bold 14px;
                }
                QLabel#settings {
                    color: #85BF25;
                    font: bold 14px;
                }
                QLabel {
                    color: white;
                }
                QLabel#set_header {
                    color: white;
                    font: bold 14px;
                }
                QCheckBox {
                    color: white;
                }
                QListWidget {
                    color: white;
                }
                QPushButton {
                    background-color: rgb(50,50,50);
                    border-color: solid black;
                    border-width: 2px;
                    color: rgb(255,255,255);
                    font: bold 12px;
                }
                """)
        else:
            pass
Example #21
0
class QCodecSelection(QWidget):
    contentsModified = pyqtSignal()

    def __init__(self, track, savedencoders, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.track = track
        self.savedencoders = savedencoders

        layout = QHBoxLayout()
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        self.encoderSelectionComboBox = QComboBox(self)
        layout.addWidget(self.encoderSelectionComboBox)

        self.configBtn = QPushButton(self)
        layout.addWidget(self.configBtn)

        self.configBtn.setIcon(QIcon.fromTheme("preferences-other"))

        self.encoderSelectionComboBox.addItem("Copy Track", None)
        self.encoderSelectionComboBox.insertSeparator(
            self.encoderSelectionComboBox.count())

        if track.type == "video":
            common_encoders = ["libx265", "libx264", "mpeg2video"]
            encoders = vencoders

        elif track.type == "audio":
            common_encoders = ["dca", "ac3",
                               "libfdk_aac", "aac", "mp3", "flac"]
            encoders = aencoders

        elif track.type == "subtitle":
            common_encoders = ["ass", "srt"]
            encoders = sencoders

        else:
            common_encoders = ["libx265", "libx264", "mpeg2video",
                               "dca", "ac3", "libfdk_aac", "aac",
                               "mp3", "flac", "ass", "srt"]

            encoders = OrderedDict()
            encoders.update(vencoders)
            encoders.update(aencoders)
            encoders.update(sencoders)

        for key in common_encoders:
            try:
                self.encoderSelectionComboBox.addItem(
                    f"{encoders[key]} ({key})", key)

            except KeyError:
                pass

        self.encoderSelectionComboBox.insertSeparator(
            self.encoderSelectionComboBox.count())

        for key, encoder in sorted(encoders.items(), key=lambda item: item[1]):
            if key in common_encoders:
                continue
            self.encoderSelectionComboBox.addItem(f"{encoder} ({key})", key)

        self.encoderSelectionComboBox.currentIndexChanged.connect(
            self.encoderSelectionComboBoxChanged)
        self.configBtn.clicked.connect(self.configureCodec)
        self.configBtn.setEnabled(track.encoder is not None)

    def encoderSelectionComboBoxChanged(self, value):
        data = self.encoderSelectionComboBox.currentData()

        if ((id(self.track), data) not in self.savedencoders
                and data is not None):
            self.savedencoders[id(self.track),
                               data] = createCodecConfigObj(data)

        self.configBtn.setDisabled(data is None)

    def configureCodec(self):
        data = self.encoderSelectionComboBox.currentData()
        encoder = self.savedencoders[id(self.track), data]

        dlg = encoder.copy().QtDlg(self)
        if (hasattr(dlg, "settingsApplied")
                and isinstance(dlg.settingsApplied, pyqtBoundSignal)):
            dlg.settingsApplied.connect(self.contentsModified)

        if dlg is not None and dlg.exec_():
            encoder.__setstate__(dlg.encoder.__getstate__())

    def setEncoderSelection(self, encoder):
        self.configBtn.setEnabled(encoder is not None)

        if encoder is not None:
            self.savedencoders[id(self.track), encoder.codec] = encoder

        if encoder:
            codecindex = self.encoderSelectionComboBox.findData(encoder.codec)

        else:
            codecindex = self.encoderSelectionComboBox.findData(None)

        self.encoderSelectionComboBox.blockSignals(True)

        if codecindex >= 0:
            self.encoderSelectionComboBox.setCurrentIndex(codecindex)

        else:
            self.encoderSelectionComboBox.setCurrentIndex(0)

        self.encoderSelectionComboBox.blockSignals(False)

    def encoderSelection(self):
        data = self.encoderSelectionComboBox.currentData()
        return self.savedencoders.get((id(self.track), data))
Example #22
0
class GuiOutlineToolBar(QToolBar):

    loadNovelRootRequest = pyqtSignal(str)
    viewColumnToggled = pyqtSignal(bool, Enum)

    def __init__(self, theOutline):
        QTreeWidget.__init__(self, theOutline)

        logger.debug("Initialising GuiOutlineToolBar ...")

        self.mainConf = novelwriter.CONFIG
        self.mainGui = theOutline.mainGui
        self.theProject = theOutline.mainGui.theProject
        self.mainTheme = theOutline.mainGui.mainTheme

        iPx = self.mainConf.pxInt(22)
        mPx = self.mainConf.pxInt(12)

        self.setMovable(False)
        self.setIconSize(QSize(iPx, iPx))
        self.setContentsMargins(0, 0, 0, 0)
        self.setStyleSheet("QToolBar {border: 0px;}")

        stretch = QWidget(self)
        stretch.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        # Novel Selector
        self.novelLabel = QLabel(self.tr("Outline of"))
        self.novelLabel.setContentsMargins(0, 0, mPx, 0)

        self.novelValue = QComboBox(self)
        self.novelValue.setMinimumWidth(self.mainConf.pxInt(200))
        self.novelValue.currentIndexChanged.connect(self._novelValueChanged)

        # Actions
        self.aRefresh = QAction(self.tr("Refresh"), self)
        self.aRefresh.setIcon(self.mainTheme.getIcon("refresh"))
        self.aRefresh.triggered.connect(self._refreshRequested)

        # Column Menu
        self.mColumns = GuiOutlineHeaderMenu(self)
        self.mColumns.columnToggled.connect(
            lambda isChecked, tItem: self.viewColumnToggled.emit(
                isChecked, tItem))

        self.tbColumns = QToolButton(self)
        self.tbColumns.setIcon(self.mainTheme.getIcon("menu"))
        self.tbColumns.setMenu(self.mColumns)
        self.tbColumns.setPopupMode(QToolButton.InstantPopup)

        # Assemble
        self.addWidget(self.novelLabel)
        self.addWidget(self.novelValue)
        self.addSeparator()
        self.addAction(self.aRefresh)
        self.addWidget(self.tbColumns)
        self.addWidget(stretch)

        logger.debug("GuiOutlineToolBar initialisation complete")

        return

    ##
    #  Methods
    ##

    def populateNovelList(self):
        """Fill the novel combo box with a list of all novel folders.
        """
        self.novelValue.clear()
        tIcon = self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL])
        for tHandle, nwItem in self.theProject.tree.iterRoots(
                nwItemClass.NOVEL):
            self.novelValue.addItem(tIcon, nwItem.itemName, tHandle)
        self.novelValue.insertSeparator(self.novelValue.count())
        self.novelValue.addItem(tIcon, self.tr("All Novel Folders"), "")
        return

    def setColumnHiddenState(self, hiddenState):
        """Forward the change of column hidden states to the menu.
        """
        self.mColumns.setHiddenState(hiddenState)
        return

    ##
    #  Private Slots
    ##

    @pyqtSlot(int)
    def _novelValueChanged(self, index):
        """Emit a signal containing the handle of the selected item.
        """
        if index >= 0:
            self.loadNovelRootRequest.emit(self.novelValue.currentData())
        return

    @pyqtSlot()
    def _refreshRequested(self):
        """Emit a signal containing the handle of the selected item.
        """
        self.loadNovelRootRequest.emit(self.novelValue.currentData())
        return
Example #23
0
class PyView(QApplication):
    '''PyView class'''
    def __init__(self, argv):
        '''Constructor. Parse args and build UI.'''
        super(PyView, self).__init__(argv)
        self.win = None
        self.scene = None
        self.gfxView = None
        self.layoutCombo = None
        self.appPath = os.path.abspath(os.path.dirname(argv[0]))
        self.currentLayout = ('createColumnCollage', ('3/2B/3', ))
        # Init GUI
        self.initUI()
        self.win.show()

    def initUI(self):
        '''Init UI of the PyView application'''
        # The QWidget widget is the base class of all user interface objects in PyQt5.
        self.win = QWidget()

        # Set window title
        self.win.setWindowTitle("PyView")
        self.win.setWindowIcon(
            QIcon(os.path.join(self.appPath, 'icons', DefaultPhoto)))
        self.win.resize(800, 800 * (1 / CollageAspectRatio))

        vbox = QVBoxLayout()
        self.win.setLayout(vbox)

        # Add toolbar
        toolbar = QToolBar()
        toolbar.setStyleSheet('QToolBar{spacing:5px;}')
        vbox.addWidget(toolbar)
        # Standard Qt Pixmaps: http://doc.qt.io/qt-5/qstyle.html#StandardPixmap-enum
        icon = self.style().standardIcon(getattr(QStyle, 'SP_FileIcon'))
        toolbar.addAction(icon, 'New', getattr(self, 'newCollage'))
        icon = self.style().standardIcon(getattr(QStyle,
                                                 'SP_DialogSaveButton'))
        toolbar.addAction(icon, 'Save', getattr(self, 'saveCollage'))
        # Layout combobox
        toolbar.addSeparator()
        label = QLabel('Layout: ')
        toolbar.addWidget(label)
        self.layoutCombo = QComboBox()
        self.layoutCombo.addItem('Grid 2x2', ('createGridCollage', (2, 2)))
        self.layoutCombo.addItem('Grid 3x3', ('createGridCollage', (3, 3)))
        self.layoutCombo.addItem('Grid 3x4', ('createGridCollage', (3, 4)))
        self.layoutCombo.addItem('Grid 4x3', ('createGridCollage', (4, 3)))
        self.layoutCombo.addItem('Grid 4x4', ('createGridCollage', (4, 4)))
        self.layoutCombo.addItem('Grid 5x5', ('createGridCollage', (5, 5)))
        self.layoutCombo.addItem('Grid 7x1', ('createGridCollage', (7, 1)))
        self.layoutCombo.addItem('Columns 1B/3',
                                 ('createColumnCollage', ('1B/3', )))
        self.layoutCombo.addItem('Columns 2/2B/2',
                                 ('createColumnCollage', ('2/2B/2', )))
        self.layoutCombo.addItem('Columns 3/1B/3',
                                 ('createColumnCollage', ('3/1B/3', )))
        self.layoutCombo.addItem('Columns 3/2B/3',
                                 ('createColumnCollage', ('3/2B/3', )))
        self.layoutCombo.addItem('Rows 1B/2/3/2B',
                                 ('createRowCollage', ('1B/2/3/2B', )))
        self.layoutCombo.setCurrentIndex(8)
        self.layoutCombo.currentIndexChanged[str].connect(
            self.layoutChangedHandler)
        toolbar.addWidget(self.layoutCombo)
        # Aspect ratio combobox
        label = QLabel('Aspect Ratio: ')
        toolbar.addWidget(label)
        self.aspectRatioCombo = QComboBox()
        self.aspectRatioCombo.addItem('1:1')
        self.aspectRatioCombo.insertSeparator(99)
        self.aspectRatioCombo.addItem('3:2')
        self.aspectRatioCombo.addItem('4:3')
        self.aspectRatioCombo.addItem('16:9')
        self.aspectRatioCombo.addItem('16:10')
        self.aspectRatioCombo.insertSeparator(99)
        self.aspectRatioCombo.addItem('2:3')
        self.aspectRatioCombo.addItem('3:4')
        self.aspectRatioCombo.setCurrentIndex(2)
        self.aspectRatioCombo.currentIndexChanged[str].connect(
            self.aspectRatioChangedHandler)
        toolbar.addWidget(self.aspectRatioCombo)
        # Frame color button
        toolbar.addSeparator()
        icon = QIcon(os.path.join(self.appPath, 'icons', 'frame-color.svg'))
        toolbar.addAction(icon, 'Choose frame color',
                          getattr(self, 'setFrameColor'))

        # Create GraphicsView
        self.gfxView = ImageView()
        self.arWidget = AspectRatioWidget(self.gfxView, CollageAspectRatio)
        vbox.addWidget(self.arWidget)
        self.gfxView.setBackgroundBrush(QBrush(FrameColor))

        # Set OpenGL renderer
        if OpenGLRender:
            self.gfxView.setViewport(QOpenGLWidget())

        # Add scene
        self.scene = CollageScene()

        # Create initial collage
        funcname, args = self.currentLayout
        self.setLayout(funcname, *args)

        self.gfxView.setScene(self.scene)

    def setLayout(self, funcname, *args):
        logger.debug('funcname=%s *args=%s', funcname, str(args))
        # Clear all items from scene
        self.scene.clear()
        # Create new collage
        func = getattr(self, funcname)
        if args:
            func(self.scene, *args)
        else:
            func(self.scene)

    def createGridCollage(self, scene, numx, numy):
        '''Create a collage with specified number of rows and columns'''
        f = LoopIter(filenames)
        photoWidth = CollageSize.width() / numx
        photoHeight = CollageSize.height() / numy
        for x in range(0, numx):
            for y in range(0, numy):
                scene.addPhoto(
                    QRect(x * photoWidth, y * photoHeight, photoWidth,
                          photoHeight), f.next())

    def createColumnCollage(self, scene, desc):
        '''Create a collage based on the string passed in'''
        columns = desc.split('/')
        # Calculate base width
        # - Big photos are twice as wide as normal ones
        baseWidth = CollageSize.width() / (len(columns) + desc.count('B'))
        # Loop through all columns
        f = LoopIter(filenames)
        x = 0
        for col in columns:
            logger.debug('col=%s', col)
            photoCount = int(col.replace('B', ''))
            if 'B' in col:
                photoWidth = baseWidth * 2
            else:
                photoWidth = baseWidth
            photoHeight = CollageSize.height() / photoCount
            for y in range(0, photoCount):
                scene.addPhoto(
                    QRect(x, y * photoHeight, photoWidth, photoHeight),
                    f.next())
            x += photoWidth

    def createRowCollage(self, scene, desc):
        '''Create a collage based on the string passed in'''
        rows = desc.split('/')
        # Calculate base height
        # - Big photos are twice as high as normal ones
        baseHeight = CollageSize.height() / (len(rows) + desc.count('B'))
        # Loop through all columns
        f = LoopIter(filenames)
        y = 0
        for row in rows:
            logger.debug('row=%s', row)
            photoCount = int(row.replace('B', ''))
            if 'B' in row:
                photoHeight = baseHeight * 2
            else:
                photoHeight = baseHeight
            photoWidth = CollageSize.width() / photoCount
            for x in range(0, photoCount):
                scene.addPhoto(
                    QRect(x * photoWidth, y, photoWidth, photoHeight),
                    f.next())
            y += photoHeight

    def layoutChangedHandler(self, desc):
        '''Handler for layoutCombo signal'''
        global filenames
        self.currentLayout = self.layoutCombo.currentData()
        # Save list of displayed photos
        filenames = self.scene.getPhotosPaths()
        # Set new layout
        funcname, args = self.currentLayout
        self.setLayout(funcname, *args)

    def aspectRatioChangedHandler(self, desc):
        '''Handler for aspectRatioCombo signal'''
        global CollageAspectRatio
        global CollageSize
        global filenames
        width, height = [int(i) for i in desc.split(':')]
        CollageAspectRatio = width / height
        CollageSize = QRectF(0, 0, 2048, 2048 * (1 / CollageAspectRatio))
        self.win.resize(self.win.width(),
                        self.win.width() * (1 / CollageAspectRatio))
        self.arWidget.setAspectRatio(CollageAspectRatio)
        # Save list of displayed photos
        filenames = self.scene.getPhotosPaths()
        # Clear scene
        self.scene.clear()
        # Re-create collage
        funcname, args = self.currentLayout
        self.setLayout(funcname, *args)
        #self.gfxView.setScene(self.scene)

    def newCollage(self):
        '''New collage'''
        ret = QMessageBox.question(
            self.win,
            'New collage',
            'Are you sure you want to reset your collage?',
            defaultButton=QMessageBox.Yes)
        if ret == QMessageBox.Yes:
            self.scene.clear()
            funcname, args = self.currentLayout
            self.setLayout(funcname, *args)

    def saveCollage(self, saveas=True):
        '''Save action handler'''
        global OutFileName
        global LastDirectory
        if saveas or not OutFileName:
            if not LastDirectory:
                LastDirectory = os.getcwd()
            OutFileName, filetype = QFileDialog.getSaveFileName(
                None, 'Save Collage', LastDirectory,
                "Images (*.png *.gif *.jpg);;All Files (*)")
        if OutFileName:
            LastDirectory = os.path.dirname(OutFileName)
            self.win.setWindowTitle('PyView - %s' % OutFileName)
            self.gfxView.save(OutFileName)

    def setFrameColor(self):
        '''Set color of the photo frames'''
        global FrameColor
        FrameColor = QColorDialog.getColor()
        self.gfxView.setBackgroundBrush(QBrush(FrameColor))
Example #24
0
class NewFolderWindow(QDialog):
    def __init__(self, parent):
        super(NewFolderWindow, self).__init__()
        self.parent = parent
        self.setWindowTitle("Gridsync - Add New Sync Folder")
        self.resize(500, 225)
        self.layout = QVBoxLayout(self)
        self.folder = None

        layout = QVBoxLayout()

        grid_group_box = QGroupBox(self)
        grid_group_box.setTitle("Select remote storage grid to use:")
        grid_layout = QHBoxLayout(grid_group_box)
        self.grid_combo_box = QComboBox(grid_group_box)
        self.populate_combo_box()
        grid_layout.addWidget(self.grid_combo_box)
        layout.addWidget(grid_group_box)

        folder_group_box = QGroupBox(self)
        folder_group_box.setTitle("Select local folder to sync:")
        folder_layout = QHBoxLayout(folder_group_box)
        self.folder_text = QLineEdit(folder_group_box)
        folder_layout.addWidget(self.folder_text)
        folder_button = QPushButton(folder_group_box)
        folder_button.setText("Browse...")
        folder_button.clicked.connect(self.get_folder)
        folder_layout.addWidget(folder_button)
        layout.addWidget(folder_group_box)

        self.layout.addLayout(layout)

        button_box = QDialogButtonBox(self)
        button_box.setStandardButtons(
            QDialogButtonBox.Cancel | QDialogButtonBox.Ok)
        button_box.rejected.connect(self.close)
        button_box.accepted.connect(self.create_new_folder)
        self.layout.addWidget(button_box)

    def populate_combo_box(self):
        logging.debug("(Re-)populating combo box...")
        self.grid_combo_box.clear()
        for gateway in self.parent.gateways:
            self.grid_combo_box.addItem(gateway.location, gateway)
        self.grid_combo_box.insertSeparator(len(self.parent.gateways))
        self.grid_combo_box.addItem("Add New Grid...")
        #self.grid_combo_box.setEnabled(False)

    def get_folder(self):
        self.folder = QFileDialog.getExistingDirectory(
            self, "Select local folder to sync")
        if self.folder:
            self.folder_text.setText(self.folder)

    def create_new_folder(self):
        if self.folder_text.text() and self.grid_combo_box.currentText():
            self.close()
            selected_folder = str(self.folder_text.text())
            selected_grid = str(self.grid_combo_box.currentText())
            for gateway in self.parent.gateways:
                if gateway.name == selected_grid:
                    tahoe = gateway
            tahoe.add_sync_folder(selected_folder)
Example #25
0
class FileChooser(QWidget):
    fileOpened = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        # TODO: migrate to FolderComboBox?
        self.folderBox = QComboBox(self)
        self.explorerTree = FileTreeView(self)
        self.explorerTree.doubleClickCallback = self._fileOpened
        self.explorerModel = QFileSystemModel(self)
        self.explorerModel.setFilter(QDir.AllDirs | QDir.Files
                                     | QDir.NoDotAndDotDot)
        self.explorerModel.setNameFilters(["*.py"])
        self.explorerModel.setNameFilterDisables(False)
        self.explorerTree.setModel(self.explorerModel)
        for index in range(1, self.explorerModel.columnCount()):
            self.explorerTree.hideColumn(index)
        self.setCurrentFolder()
        self.folderBox.currentIndexChanged[int].connect(
            self.updateCurrentFolder)

        layout = QVBoxLayout(self)
        layout.addWidget(self.folderBox)
        layout.addWidget(self.explorerTree)
        layout.setContentsMargins(5, 5, 0, 0)

    def _fileOpened(self, modelIndex):
        path = self.explorerModel.filePath(modelIndex)
        if os.path.isfile(path):
            self.fileOpened.emit(path)

    def currentFolder(self):
        return self.explorerModel.rootPath()

    def setCurrentFolder(self, path=None):
        if path is None:
            app = QApplication.instance()
            path = app.getScriptsDirectory()
        else:
            assert os.path.isdir(path)
        self.explorerModel.setRootPath(path)
        self.explorerTree.setRootIndex(self.explorerModel.index(path))
        self.folderBox.blockSignals(True)
        self.folderBox.clear()
        style = self.style()
        dirIcon = style.standardIcon(style.SP_DirIcon)
        self.folderBox.addItem(dirIcon, os.path.basename(path))
        self.folderBox.insertSeparator(1)
        self.folderBox.addItem(self.tr("Browse…"))
        self.folderBox.setCurrentIndex(0)
        self.folderBox.blockSignals(False)

    def updateCurrentFolder(self, index):
        if index < self.folderBox.count() - 1:
            return
        path = QFileDialog.getExistingDirectory(self,
                                                self.tr("Choose Directory"),
                                                self.currentFolder(),
                                                QFileDialog.ShowDirsOnly)
        if path:
            QSettings().setValue("scripting/path", path)
            self.setCurrentFolder(path)
Example #26
0
class CSVOptionsWindow(QWidget):
    def __init__(self, mainwindow):
        QWidget.__init__(self, mainwindow, Qt.Window)
        self._setupUi()
        self.doc = mainwindow.doc
        self.model = mainwindow.model.csv_options
        self.tableModel = CSVOptionsTableModel(self.model, self.tableView)
        self.model.view = self
        self.encodingComboBox.addItems(SUPPORTED_ENCODINGS)

        self.cancelButton.clicked.connect(self.hide)
        self.continueButton.clicked.connect(self.model.continue_import)
        self.targetComboBox.currentIndexChanged.connect(self.targetIndexChanged)
        self.layoutComboBox.currentIndexChanged.connect(self.layoutIndexChanged)
        self.rescanButton.clicked.connect(self.rescanClicked)

    def _setupUi(self):
        self.setWindowTitle(tr("CSV Options"))
        self.resize(526, 369)
        self.verticalLayout = QVBoxLayout(self)
        msg = tr(
            "Specify which CSV columns correspond to which transaction fields. You must also "
            "uncheck the \"Import\" column for lines that don\'t represent a transaction "
            "(header, footer, comments)."
        )
        self.label = QLabel(msg)
        self.label.setWordWrap(True)
        self.verticalLayout.addWidget(self.label)
        self.gridLayout = QGridLayout()
        self.label_2 = QLabel(tr("Layout:"))
        self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1)
        self.layoutComboBox = QComboBox(self)
        self.layoutComboBox.setMinimumSize(QtCore.QSize(160, 0))
        self.gridLayout.addWidget(self.layoutComboBox, 0, 1, 1, 1)
        self.label_4 = QLabel(tr("Delimiter:"))
        self.gridLayout.addWidget(self.label_4, 0, 3, 1, 1)
        self.fieldSeparatorEdit = QLineEdit(self)
        self.fieldSeparatorEdit.setMaximumSize(QtCore.QSize(30, 16777215))
        self.gridLayout.addWidget(self.fieldSeparatorEdit, 0, 4, 1, 1)
        self.targetComboBox = QComboBox(self)
        self.gridLayout.addWidget(self.targetComboBox, 1, 1, 1, 1)
        self.label_3 = QLabel(tr("Target:"))
        self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1)
        self.encodingComboBox = QComboBox(self)
        self.gridLayout.addWidget(self.encodingComboBox, 1, 4, 1, 1)
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem, 2, 2, 1, 1)
        self.horizontalLayout_2 = QHBoxLayout()
        self.horizontalLayout_2.setSpacing(0)
        spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem1)
        self.rescanButton = QPushButton(tr("Rescan"))
        sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.rescanButton.sizePolicy().hasHeightForWidth())
        self.rescanButton.setSizePolicy(sizePolicy)
        self.horizontalLayout_2.addWidget(self.rescanButton)
        self.gridLayout.addLayout(self.horizontalLayout_2, 2, 3, 1, 2)
        self.label_5 = QLabel(tr("Encoding:"))
        self.gridLayout.addWidget(self.label_5, 1, 3, 1, 1)
        self.verticalLayout.addLayout(self.gridLayout)
        self.tableView = QTableView(self)
        self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tableView.setShowGrid(False)
        self.tableView.horizontalHeader().setHighlightSections(False)
        self.tableView.verticalHeader().setVisible(False)
        self.tableView.verticalHeader().setDefaultSectionSize(18)
        self.verticalLayout.addWidget(self.tableView)
        self.horizontalLayout = QHBoxLayout()
        spacerItem2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem2)
        self.cancelButton = QPushButton(tr("Cancel"))
        self.cancelButton.setShortcut("Esc")
        self.horizontalLayout.addWidget(self.cancelButton)
        self.continueButton = QPushButton(tr("Continue Import"))
        self.continueButton.setDefault(True)
        self.horizontalLayout.addWidget(self.continueButton)
        self.verticalLayout.addLayout(self.horizontalLayout)

    # --- Private
    def _newLayout(self):
        title = tr("New Layout")
        msg = tr("Choose a name for your new layout:")
        name, ok = QInputDialog.getText(self, title, msg)
        if ok and name:
            self.model.new_layout(name)

    def _renameLayout(self):
        title = tr("Rename Layout")
        msg = tr("Choose a name for your layout:")
        name, ok = QInputDialog.getText(self, title, msg)
        if ok and name:
            self.model.rename_selected_layout(name)

    # --- Event Handling
    def layoutIndexChanged(self, index):
        # This one is a little complicated. We want to only be able to select the layouts. If
        # anything else is clicked, we revert back to the old index. If the item has user data,
        # it means that an action has to be performed.
        if index < 0:
            return
        elif index < len(self.model.layout_names):
            layout_name = None if index == 0 else str(self.layoutComboBox.itemText(index))
            self.model.select_layout(layout_name)
        else:
            self.layoutComboBox.setCurrentIndex(self.layoutComboBox.findText(self.model.layout.name))
            data = str(self.layoutComboBox.itemData(index))
            if data == NEW_LAYOUT:
                self._newLayout()
            elif data == RENAME_LAYOUT:
                self._renameLayout()
            elif data == DELETE_LAYOUT:
                self.model.delete_selected_layout()

    def rescanClicked(self):
        self.model.encoding_index = self.encodingComboBox.currentIndex()
        self.model.field_separator = str(self.fieldSeparatorEdit.text())
        self.model.rescan()

    def targetIndexChanged(self, index):
        self.model.selected_target_index = index

    # --- model --> view
    # hide() is called from the model, but is already covered by QWidget
    def refresh_columns(self):
        self.tableModel.beginResetModel()
        self.tableModel.endResetModel()

    def refresh_columns_name(self):
        self.tableModel.refreshColumnsName()

    def refresh_layout_menu(self):
        self.layoutComboBox.currentIndexChanged.disconnect(self.layoutIndexChanged)
        self.layoutComboBox.clear()
        self.layoutComboBox.addItems(self.model.layout_names)
        self.layoutComboBox.insertSeparator(self.layoutComboBox.count())
        self.layoutComboBox.addItem(tr("New Layout..."), NEW_LAYOUT)
        self.layoutComboBox.addItem(tr("Rename Selected Layout..."), RENAME_LAYOUT)
        self.layoutComboBox.addItem(tr("Delete Selected Layout"), DELETE_LAYOUT)
        self.layoutComboBox.setCurrentIndex(self.layoutComboBox.findText(self.model.layout.name))
        self.layoutComboBox.currentIndexChanged.connect(self.layoutIndexChanged)

    def refresh_lines(self):
        self.tableModel.beginResetModel()
        self.tableModel.endResetModel()
        self.fieldSeparatorEdit.setText(self.model.field_separator)

    def refresh_targets(self):
        self.targetComboBox.currentIndexChanged.disconnect(self.targetIndexChanged)
        self.targetComboBox.clear()
        self.targetComboBox.addItems(self.model.target_account_names)
        self.targetComboBox.currentIndexChanged.connect(self.targetIndexChanged)

    def show(self):
        # For non-modal dialogs, show() is not enough to bring the window at the forefront, we have
        # to call raise() as well
        QWidget.show(self)
        self.raise_()

    def show_message(self, msg):
        title = "Warning"
        QMessageBox.warning(self, title, msg)
Example #27
0
class FontsPreviewWidget(QWidget):
    """Show a preview score using the font selection."""

    # Permanently cache compilations of the provided samples
    persistent_cache_dir = get_persistent_cache_dir()
    # Cache compilations of custom samples for Frescobaldi's lifetime only
    temp_dir = util.tempdir()

    def __init__(self, parent):
        super(FontsPreviewWidget, self).__init__(parent)

        # Create the cache directory for default samples
        os.makedirs(self.persistent_cache_dir, 0o700, exist_ok=True)

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

        # Label with text "Example:"
        self.lb_sample = QLabel()

        # ComboBox for provided default samples and other options
        self.cb_samples = QComboBox()

        # Select custom file
        self.custom_sample_url = widgets.urlrequester.UrlRequester(
            fileMode=QFileDialog.ExistingFile, mustExist=True)

        # put the default sample in the combobox
        self.populate_default_samples()
        # add other actions
        self.cb_samples.insertSeparator(self.cb_samples.count())
        self.cb_samples.addItem(_("Custom"), "<CUSTOM>")
        self.cb_samples.addItem(_("Current Document"), "<CURRENT>")

        # Add sample source widgets to layout
        bl = QHBoxLayout(margin=0)
        bl.addWidget(self.lb_sample)
        bl.addWidget(self.cb_samples)
        bl.addWidget(self.custom_sample_url)
        layout.addLayout(bl)

        # The score preview widget
        self.musicFontPreview = mfp = musicpreview.MusicPreviewWidget(
            parent, showProgress=False, showWaiting=True, showLog=False)
        layout.addWidget(mfp)

        app.translateUI(self)
        self.loadSettings()

        # Trigger showing of new samples
        self.cb_samples.currentIndexChanged.connect(self.show_sample)
        self.custom_sample_url.editingFinished.connect(self.show_sample)
        parent.finished.connect(self.saveSettings)

    def translateUI(self):
        self.lb_sample.setText("Example:")
        csu = self.custom_sample_url
        csu.setToolTip(
            _("Use custom sample for music font.\n" +
              "NOTE: This should not include a version statement " +
              "or a \\paper {...} block."))
        csu.setDialogTitle(_("Select sample score"))
        csu.fileDialog(True).setNameFilters(['LilyPond files (*.ly)'])
        i = self.cb_samples.findData("<CURRENT>")
        self.cb_samples.setItemData(
            i,
            _("Use current document as music font sample.\n" +
              "NOTE: This is not robust if the document contains " +
              "a \\paper {...} block."), Qt.ToolTipRole)
        i = self.cb_samples.findData("<CUSTOM>")
        self.cb_samples.setItemData(i, csu.toolTip(), Qt.ToolTipRole)

    def loadSettings(self):
        s = QSettings()
        s.beginGroup('document-fonts-dialog')
        sample = s.value('default-music-sample', '', str)
        index = max(0, self.cb_samples.findData(sample))
        self.cb_samples.setCurrentIndex(index)
        custom_sample = s.value('custom-music-sample-url', '', str)
        self.custom_sample_url.setPath(custom_sample)
        if custom_sample:
            sample_dir = os.path.dirname(custom_sample)
        else:
            sample_dir = os.path.dirname(
                self.window().parent().currentDocument().url().toLocalFile())
        self.custom_sample_url.fileDialog().setDirectory(sample_dir)

    def saveSettings(self):
        s = QSettings()
        s.beginGroup('document-fonts-dialog')
        s.setValue('default-music-sample', self.cb_samples.currentData())
        s.setValue('custom-music-sample-url', self.custom_sample_url.path())

    def populate_default_samples(self):
        """Populate hte default samples ComboBox.
        This is just factored out to unclutter __init__.
        """
        cb = self.cb_samples

        def add_entry(entry):
            cb.addItem(entry['label'], entry['file'])
            cb.setItemData(cb.count() - 1, entry['tooltip'], Qt.ToolTipRole)

        add_entry({
            'label':
            _('Bach (Piano)'),
            'file':
            'bach.ly',
            'tooltip':
            _("Baroque music lends itself to traditional fonts")
        })
        add_entry({
            'label': _('Scriabine (Piano)'),
            'file': 'scriabine.ly',
            'tooltip': _("Late romantic, complex piano music")
        })
        add_entry({
            'label': _('Berg (String Quartet)'),
            'file': 'berg-string-quartet.ly',
            'tooltip': _("Complex score, requires a 'clean' font")
        })
        add_entry({
            'label':
            _('Real Book (Lead Sheet)'),
            'file':
            'realbook.ly',
            'tooltip':
            _("Jazz-like lead sheet.\n" +
              "NOTE: beautiful results rely on appropriate text fonts.\n" +
              "Good choices are \"lilyjazz-text\" for roman and\n" +
              "\"lilyjazz-chords\" for sans text fonts.")
        })
        add_entry({
            'label':
            _('Schenker Diagram'),
            'file':
            'schenker.ly',
            'tooltip':
            _("Schenker diagram with absolutely\n" + "non-standard notation.")
        })
        add_entry({
            'label': _('Glyphs'),
            'file': 'glyphs.ly',
            'tooltip': _("Non-comprehensive specimen sheet")
        })

    def show_sample(self):
        """Display a sample document for the selected notation font."""
        print("Enter show_sample")
        global_size = ''
        base_dir = None
        sample_content = ''
        cache_persistently = False

        target = self.cb_samples.currentData()
        self.custom_sample_url.setEnabled(target == "<CUSTOM>")

        def handle_staff_size():
            """
            If the sample file *starts with* a staff-size definition
            it will be injected *after* our paper block.
            """
            nonlocal sample_content, global_size
            match = re.match('#\(set-global-staff-size \d+\)', sample_content)
            if match:
                global_size = match.group(0)
                sample_content = sample_content[len(global_size):]

        def load_content():
            """
            Load the content to be engraved as sample,
            either from the active editor or from a file.
            """
            nonlocal sample_content, base_dir
            nonlocal cache_persistently, target
            custom_file = self.custom_sample_url.path()

            if target == "<CUSTOM>" and not custom_file:
                target = self.cb_samples.itemData(0)

            # Provided sample files will be cached persistently
            cache_persistently = target not in ("<CUSTOM>", "<CURRENT>")

            if target == "<CURRENT>":
                # Engrave active document
                import engrave
                current_doc = engrave.engraver(app.activeWindow()).document()
                sample_content = current_doc.toPlainText()
                if not current_doc.url().isEmpty():
                    base_dir = os.path.dirname(current_doc.url().toLocalFile())
            else:
                if target == "<CUSTOM>":
                    print("Custom file:", custom_file)
                    sample_file = custom_file
                else:
                    # Engrave from a file
                    import fonts
                    template_dir = os.path.join(fonts.__path__[0], 'templates')
                    sample_file = os.path.join(template_dir,
                                               'musicfont-' + target)
                    print("Default:", sample_file)
                base_dir = os.path.dirname(sample_file)
                with open(sample_file, 'r') as f:
                    sample_content = f.read()

        def sample_document():
            """
            Steps of composing the used sample document.
            """
            load_content()
            handle_staff_size()
            result = [
                '\\version "{}"\n'.format(self.window(
                ).available_fonts.music_fonts().lilypond_info.versionString()),
                '{}\n'.format(global_size) if global_size else '',
                # TODO: "Protect" this regarding openLilyLib.
                # It would be easy to simply pass 'lily' as an argument
                # to always use the generic approach. However, that would
                # prevent the use of font extensions and stylesheets.
                self.window().font_full_cmd(),
                sample_content
            ]
            return '\n'.join(result)

        sample = sample_document()
        cache_dir = (self.persistent_cache_dir
                     if cache_persistently else self.temp_dir)
        self.musicFontPreview.preview(sample,
                                      title='Music font preview',
                                      base_dir=base_dir,
                                      temp_dir=cache_dir,
                                      cached=True)
Example #28
0
class QDataSet(DataSet, QWidget, Ui_DataSet):
    """[summary]
    
    [description]
    """
    def __init__(self, name="QDataSet", parent=None):
        """
        **Constructor**
        
        [description]
        
        Keyword Arguments:
            - name {[type]} -- [description] (default: {"QDataSet"})
            - parent {[type]} -- [description] (default: {None})
        """
        super().__init__(name=name, parent=parent)
        QWidget.__init__(self)
        Ui_DataSet.__init__(self)

        self.setupUi(self)

        self.DataSettreeWidget = DataSetWidget(self)
        self.splitter.insertWidget(0, self.DataSettreeWidget)

        self.DataSettreeWidget.setIndentation(0)
        self.DataSettreeWidget.setHeaderItem(QTreeWidgetItem([""]))
        self.DataSettreeWidget.setSelectionMode(
            1)  #QAbstractItemView::SingleSelection
        hd = self.DataSettreeWidget.header()
        hd.setSectionsMovable(False)
        w = self.DataSettreeWidget.width()
        w /= hd.count()
        for i in range(hd.count()):
            hd.resizeSection(0, w)

        # Theory Toolbar
        tb = QToolBar()
        tb.setIconSize(QSize(24, 24))
        tb.addAction(self.actionNew_Theory)
        self.cbtheory = QComboBox()
        model = self.cbtheory.model()
        self.cbtheory.setToolTip("Choose a Theory")

        item = QStandardItem('Select:')
        item.setForeground(QColor('grey'))
        model.appendRow(item)
        i = 1
        for th_name in self.parent_application.theories:
            if th_name not in self.parent_application.common_theories:
                item = QStandardItem(th_name)
                item.setToolTip(
                    self.parent_application.theories[th_name].description)
                model.appendRow(item)
        flag_first = True
        for th_name in self.parent_application.theories:
            if th_name in self.parent_application.common_theories:
                if flag_first:
                    # add separator if al least one common theories is added
                    self.cbtheory.insertSeparator(self.cbtheory.count())
                    flag_first = False
                item = QStandardItem(th_name)
                item.setToolTip(
                    self.parent_application.theories[th_name].description)
                model.appendRow(item)
        self.cbtheory.setCurrentIndex(0)

        ###

        self.cbtheory.setMaximumWidth(115)
        self.cbtheory.setMinimumWidth(50)
        tb.addWidget(self.cbtheory)
        tb.addAction(self.actionCalculate_Theory)
        tb.addAction(self.actionMinimize_Error)
        #Buttons not wired yet
        # tb.addAction(self.actionTheory_Options)
        # self.actionTheory_Options.setDisabled(True)
        tbut = QToolButton()
        tbut.setPopupMode(QToolButton.MenuButtonPopup)
        tbut.setDefaultAction(self.actionShow_Limits)
        menu = QMenu()
        menu.addAction(self.actionVertical_Limits)
        menu.addAction(self.actionHorizontal_Limits)
        tbut.setMenu(menu)
        tb.addWidget(tbut)
        tbut2 = QToolButton()
        tbut2.setPopupMode(QToolButton.MenuButtonPopup)
        self.action_save_theory_data = QAction(
            QIcon(':/Icon8/Images/new_icons/icons8-save_TH.png'),
            "Save Theory Data", self)
        tbut2.setDefaultAction(self.action_save_theory_data)
        menu2 = QMenu()
        menu2.addAction(self.actionCopy_Parameters)
        menu2.addAction(self.actionPaste_Parameters)
        tbut2.setMenu(menu2)
        tb.addWidget(tbut2)

        self.TheoryLayout.insertWidget(0, tb)
        self.splitter.setSizes((1000, 3000))

        #desactive buttons when no theory tab
        self.theory_actions_disabled(True)

        connection_id = self.actionNew_Theory.triggered.connect(
            self.handle_actionNew_Theory)
        connection_id = self.DataSettreeWidget.itemChanged.connect(
            self.handle_itemChanged)
        #connection_id = self.DataSettreeWidget.itemClicked.connect(self.handle_itemClicked)
        connection_id = self.DataSettreeWidget.itemDoubleClicked.connect(
            self.handle_itemDoubleClicked)
        connection_id = self.DataSettreeWidget.header(
        ).sortIndicatorChanged.connect(self.handle_sortIndicatorChanged)
        connection_id = self.DataSettreeWidget.itemSelectionChanged.connect(
            self.handle_itemSelectionChanged)
        # connection_id = self.DataSettreeWidget.currentItemChanged.connect(self.handle_currentItemChanged)

        connection_id = self.TheorytabWidget.tabCloseRequested.connect(
            self.handle_thTabCloseRequested)
        connection_id = self.TheorytabWidget.tabBarDoubleClicked.connect(
            self.handle_thTabBarDoubleClicked)
        connection_id = self.TheorytabWidget.currentChanged.connect(
            self.handle_thCurrentChanged)
        connection_id = self.actionMinimize_Error.triggered.connect(
            self.handle_actionMinimize_Error)
        connection_id = self.actionCalculate_Theory.triggered.connect(
            self.handle_actionCalculate_Theory)
        connection_id = self.action_save_theory_data.triggered.connect(
            self.handle_action_save_theory_data)
        connection_id = self.actionCopy_Parameters.triggered.connect(
            self.copy_parameters)
        connection_id = self.actionPaste_Parameters.triggered.connect(
            self.paste_parameters)

        connection_id = self.actionVertical_Limits.triggered.connect(
            self.toggle_vertical_limits)
        connection_id = self.actionHorizontal_Limits.triggered.connect(
            self.toggle_horizontal_limits)

    def copy_parameters(self):
        """Copy the parameters of the currently active theory to the clipboard"""
        th = self.current_theory
        if th:
            self.theories[th].copy_parameters()

    def paste_parameters(self):
        """Paste the parameters from the clipboard to the currently active theory"""
        th = self.current_theory
        if th:
            self.theories[th].paste_parameters()

    def handle_action_save_theory_data(self):
        """Save theory data of current theory"""
        th = self.current_theory
        if th:
            # file browser window
            dir_start = "data/"
            dilogue_name = "Select Folder"
            folder = QFileDialog.getExistingDirectory(self, dilogue_name,
                                                      dir_start)
            if os.path.isdir(folder):
                dialog = QInputDialog(self)
                dialog.setWindowTitle('Add label to filename(s)?')
                dialog.setLabelText(
                    'Add the following text to each saved theory filename(s):')
                dialog.setTextValue('')
                dialog.setCancelButtonText('None')
                if dialog.exec():
                    txt = dialog.textValue()
                    if txt != '':
                        txt = '_' + txt
                else:
                    txt = ''
                self.theories[th].do_save(folder, txt)

    def set_table_icons(self, table_icon_list):
        """The list 'table_icon_list' contains tuples (file_name_short, marker_name, face, color)
        
        [description]
        
        Arguments:
            - table_icon_list {[type]} -- [description]
        """
        self.DataSettreeWidget.blockSignals(
            True
        )  #avoid triggering 'itemChanged' signal that causes a call to do_plot()

        for fname, marker_name, face, color in table_icon_list:
            item = self.DataSettreeWidget.findItems(
                fname, Qt.MatchCaseSensitive,
                column=0)  #returns list of items matching file name
            if item:
                #paint icon
                folder = ':/Markers/Images/Matplotlib_markers/'
                if face == 'none':  #empty symbol
                    marker_path = folder + 'marker_%s' % marker_name
                else:  #filled symbol
                    marker_path = folder + 'marker_filled_%s' % marker_name
                qp = QPixmap(marker_path)
                mask = qp.createMaskFromColor(QColor(0, 0, 0), Qt.MaskOutColor)
                qpainter = QPainter()
                qpainter.begin(qp)
                qpainter.setPen(
                    QColor(int(255 * color[0]), int(255 * color[1]),
                           int(255 * color[2]), 255))
                qpainter.drawPixmap(qp.rect(), mask, qp.rect())
                qpainter.end()
                item[0].setIcon(0, QIcon(qp))

        self.DataSettreeWidget.blockSignals(False)

    def theory_actions_disabled(self, state):
        """Disable theory buttons if no theory tab is open
        
        [description]
        
        Arguments:
            - state {[type]} -- [description]
        """
        self.actionCalculate_Theory.setDisabled(state)
        self.actionMinimize_Error.setDisabled(state)
        # self.actionTheory_Options.setDisabled(state)
        self.actionShow_Limits.setDisabled(state)
        self.actionVertical_Limits.setDisabled(state)
        self.actionHorizontal_Limits.setDisabled(state)
        self.action_save_theory_data.setDisabled(state)

    def set_limit_icon(self):
        """[summary]
        
        [description]
        """
        if self.current_theory:
            th = self.theories[self.current_theory]
        vlim = th.is_xrange_visible
        hlim = th.is_yrange_visible
        if hlim and vlim:
            img = "Line Chart Both Limits"
        elif vlim:
            img = "Line Chart Vertical Limits"
        elif hlim:
            img = "Line Chart Horizontal Limits"
        else:
            img = "Line Chart"
        self.actionShow_Limits.setIcon(QIcon(':/Images/Images/%s.png' % img))

    def set_no_limits(self, th_name):
        """Turn the x and yrange selectors off
        
        [description]
        
        Arguments:
            - th_name {[type]} -- [description]
        """
        if th_name in self.theories:
            self.theories[self.current_theory].set_xy_limits_visible(
                False, False)  #hide xrange and yrange

    def toggle_vertical_limits(self, checked):
        """Show/Hide the xrange selector for fit
        
        [description]
        """
        if self.current_theory:
            th = self.theories[self.current_theory]
            th.do_xrange("", checked)
            th.is_xrange_visible = checked
            self.set_limit_icon()

    def toggle_horizontal_limits(self, checked):
        """Show/Hide the yrange selector for fit
        
        [description]
        """
        if self.current_theory:
            th = self.theories[self.current_theory]
            th.do_yrange("", checked)
            th.is_yrange_visible = checked
            self.set_limit_icon()

    def end_of_computation(self, th_name):
        """Action when theory has finished computations"""
        try:
            th = self.theories[th_name]
            th.stop_theory_flag = False
        except KeyError:
            pass
        if self.current_theory == th_name:
            self.icon_calculate_is_stop(False)
            self.icon_fit_is_stop(False)

    def handle_actionCalculate_Theory(self):
        if self.current_theory and self.files:
            th = self.theories[self.current_theory]
            if th.thread_calc_busy:  # request stop if in do_calculate
                th.request_stop_computations()
                return
            elif th.is_fitting or th.thread_fit_busy:  #do nothing if already busy in do_fit
                th.Qprint("Busy minimising theory...")
                return
            if th.single_file and (len(self.files) -
                                   len(self.inactive_files)) > 1:
                header = "Calculate"
                message = "<p>Too many active files: \"%s\" uses only one data file.</p>\
                    <p>The theory will be applied to the highlighted file if any or to the first active file.</p>" % th.thname
                QMessageBox.warning(self, header, message)
            self.icon_calculate_is_stop(True)
            th.handle_actionCalculate_Theory()

    def handle_actionMinimize_Error(self):
        """Minimize the error
        
        [description]
        """
        if self.current_theory and self.files:
            th = self.theories[self.current_theory]
            if th.is_fitting or th.thread_fit_busy:  # request stop if in do_fit
                th.request_stop_computations()
                return
            elif th.calculate_is_busy or th.thread_calc_busy:  #do nothing if already busy in do_calculate
                th.Qprint("Busy calculating theory...")
                return
            if th.single_file and (len(self.files) -
                                   len(self.inactive_files)) > 1:
                header = "Minimization"
                message = "<p>Too many active files: \"%s\" uses only one data file.</p>\
                    <p>The theory will be applied to the highlighted file if any or to the first active file.</p>" % th.thname
                QMessageBox.warning(self, header, message)
            self.icon_fit_is_stop(True)
            th.handle_actionMinimize_Error()

    def icon_calculate_is_stop(self, ans):
        """Change the "calculate" button to "stop" button"""
        if ans:
            self.actionCalculate_Theory.setIcon(
                QIcon(":/Icon8/Images/new_icons/icons8-stop-sign.png"))
            self.actionCalculate_Theory.setToolTip("Stop current calculations")
        else:
            self.actionCalculate_Theory.setIcon(
                QIcon(":/Icon8/Images/new_icons/icons8-abacus.png"))
            self.actionCalculate_Theory.setToolTip("Calculate Theory (Alt+C)")

    def icon_fit_is_stop(self, ans):
        """Change the "fit" button to "stop" button"""
        if ans:
            self.actionMinimize_Error.setIcon(
                QIcon(":/Icon8/Images/new_icons/icons8-stop-sign.png"))
            self.actionCalculate_Theory.setToolTip("Stop current calculations")
        else:
            self.actionMinimize_Error.setIcon(
                QIcon(":/Icon8/Images/new_icons/icons8-minimum-value.png"))
            self.actionCalculate_Theory.setToolTip("Calculate Theory (Alt+C)")

    def handle_thCurrentChanged(self, index):
        """Change figure when the active theory tab is changed
        
        [description]
        
        Arguments:
            - index {[type]} -- [description]
        """
        self.icon_calculate_is_stop(False)
        self.icon_fit_is_stop(False)
        th = self.TheorytabWidget.widget(index)
        if th:
            self.current_theory = th.name
            ntab = self.TheorytabWidget.count()
            #hide all theory curves
            for i in range(ntab):
                if i != index:
                    th_to_hide = self.TheorytabWidget.widget(i)
                    th_to_hide.do_hide()
            th.do_show()  #must be called last, after hiding other theories

            if th.thread_calc_busy or th.thread_fit_busy:
                self.icon_calculate_is_stop(th.thread_calc_busy)
                self.icon_fit_is_stop(th.thread_fit_busy)
                return
        else:
            self.current_theory = None
            self.theory_actions_disabled(True)
        self.parent_application.update_plot()
        self.parent_application.update_Qplot()

    def handle_thTabBarDoubleClicked(self, index):
        """Edit Theory name
        
        Edit the theory tab name, leave 'theories' dictionary keys unchanged.
        Two tabs can share the same name

        Arguments:
            - index {[type]} -- [description]
        """
        old_name = self.TheorytabWidget.tabText(index)
        dlg = QInputDialog(self)
        dlg.setWindowTitle("Change Theory Name")
        dlg.setLabelText("New Theory Name:")
        dlg.setTextValue(old_name)
        dlg.resize(400, 100)
        success = dlg.exec()
        new_tab_name = dlg.textValue()
        if (success and new_tab_name != ""):
            self.TheorytabWidget.setTabText(index, new_tab_name)
            # self.theories[old_name].name = new_tab_name
            # self.theories[new_tab_name] = self.theories.pop(old_name)
            # self.current_theory = new_tab_name

    def handle_thTabCloseRequested(self, index):
        """Delete a theory tab from the current dataset
        
        [description]
        
        Arguments:
            - index {[type]} -- [description]
        """
        th_name = self.TheorytabWidget.widget(index).name
        th = self.theories[th_name]
        th.Qprint("Close theory tab requested")
        th.request_stop_computations()
        self.set_no_limits(th_name)
        self.do_theory_delete(th_name)  #call DataSet.do_theory_delete
        self.TheorytabWidget.removeTab(index)

    def handle_itemSelectionChanged(self):
        """Define actions for when a file table is selected
        
        [description]
        """
        selection = self.DataSettreeWidget.selectedItems()
        if selection == []:
            self.selected_file = None
            self.highlight_series()
            return
        for f in self.files:
            if f.file_name_short == selection[0].text(0):
                self.parent_application.disconnect_curve_drag()
                self.selected_file = f
                self.highlight_series()
                self.populate_inspector()
                self.parent_application.handle_actionShiftTriggered()

    def highlight_series(self):
        """Highligh the data series of the selected file
        
        [description]
        """
        self.do_plot()  #remove current series highlight
        file = self.selected_file
        thname = self.current_theory
        if thname:
            th = self.theories[thname]
        else:
            th = None
        if file is not None:
            dt = file.data_table
            if th:
                tt = th.tables[file.file_name_short]
            for i in range(dt.MAX_NUM_SERIES):
                for nx in range(self.nplots):
                    view = self.parent_application.multiviews[nx]
                    if (i < view.n and file.active):
                        dt.series[nx][i].set_marker('.')
                        # dt.series[nx][i].set_linestyle(":")
                        dt.series[nx][i].set_markerfacecolor(
                            dt.series[nx][i].get_markeredgecolor())
                        dt.series[nx][i].set_markeredgecolor('peachpuff')
                        dt.series[nx][i].set_markersize(self.marker_size + 3)
                        dt.series[nx][i].set_markeredgewidth(2)
                        dt.series[nx][i].set_zorder(
                            self.parent_application.zorder)  #put series on top
                        if th:
                            if th.active:
                                tt.series[nx][i].set_color('k')
                                tt.series[nx][i].set_path_effects([
                                    pe.Stroke(linewidth=self.th_line_width + 3,
                                              foreground='chartreuse'),
                                    pe.Normal()
                                ])
                                tt.series[nx][i].set_zorder(
                                    self.parent_application.zorder)

            self.parent_application.zorder += 1
        self.parent_application.update_plot()

    def populate_inspector(self):
        """[summary]
        
        [description]
        """
        file = self.selected_file
        if not file:
            self.parent_application.inspector_table.setRowCount(0)
            self.parent_application.DataInspectordockWidget.setWindowTitle(
                "File:")
            return
        if self.parent_application.DataInspectordockWidget.isHidden():
            return
        dt = file.data_table
        nrow = dt.num_rows
        ncol = dt.num_columns
        inspec_tab = self.parent_application.inspector_table
        inspec_tab.file_repr = file
        inspec_tab.setRowCount(nrow)
        inspec_tab.setColumnCount(ncol)
        for i in range(nrow):
            for j in range(ncol):
                item = QTableWidgetItem("%.3e" % dt.data[i, j])
                item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
                inspec_tab.setItem(i, j, item)  # dt.setItem(row, column, item)
        ds_index = self.parent_application.DataSettabWidget.currentIndex()
        self.parent_application.DataInspectordockWidget.setWindowTitle(
            "File: \"%s\" in %s" %
            (file.file_name_short,
             self.parent_application.DataSettabWidget.tabText(ds_index)))
        inspec_tab.resizeColumnsToContents()
        inspec_tab.resizeRowsToContents()
        # Update shift factors
        for i in range(DataTable.MAX_NUM_SERIES):
            self.parent_application.update_shifts(0, 0, i)

    def handle_itemChanged(self, item, column):
        """[summary]
        
        [description]
        
        Arguments:
            - item {[type]} -- [description]
            - column {[type]} -- [description]
        """
        if column == 0:
            self.change_file_visibility(item.text(0),
                                        item.checkState(column) == Qt.Checked)

    def handle_sortIndicatorChanged(self, column, order):
        """Sort files according to the selected parameter (column) and replot
        
        [description]
        
        Arguments:
            - column {[type]} -- [description]
            - order {[type]} -- [description]
        """
        # if column == 0: #do not sort file name
        #     return
        if self.DataSettreeWidget.topLevelItemCount() > 0:
            # sort iff there are some files in the dataset
            sort_param = self.DataSettreeWidget.headerItem().text(column)
            rev = True if order == Qt.AscendingOrder else False
            if rev:
                sort_param = sort_param + ",reverse"
            self.do_sort(sort_param)
            self.do_plot()
            self.set_table_icons(self.table_icon_list)

    def Qshow_all(self):
        """Show all the files in this dataset, except those previously hiden
        
        [description]
        """
        self.do_show_all()
        for i in range(self.DataSettreeWidget.topLevelItemCount()):
            file_name = self.DataSettreeWidget.topLevelItem(i).text(0)
            if file_name in self.inactive_files:
                self.DataSettreeWidget.topLevelItem(i).setCheckState(0, 0)
            else:
                self.DataSettreeWidget.topLevelItem(i).setCheckState(0, 2)

    def resizeEvent(self, evt=None):
        """[summary]
        
        [description]
        
        Keyword Arguments:
            - evt {[type]} -- [description] (default: {None})
        """
        hd = self.DataSettreeWidget.header()
        w = self.DataSettreeWidget.width()
        w /= hd.count()
        for i in range(hd.count()):
            hd.resizeSection(i, w)
            #hd.setTextAlignment(i, Qt.AlignHCenter)

    def handle_itemDoubleClicked(self, item, column):
        """Edit item entry upon double click
        
        [description]
        
        Arguments:
            - item {[type]} -- [description]
            - column {[type]} -- [description]
        """
        # if column>0:
        #     param = self.DataSettreeWidget.headerItem().text(column) #retrive parameter name
        #     file_name_short = item.text(0) #retrive file name
        #     header = "Edit Parameter"
        #     message = "Do you want to edit %s of \"%s\"?"%(param, file_name_short)
        #     answer = QMessageBox.question(self, header, message)
        #     if answer == QMessageBox.Yes:
        #         old_value = item.text(column) #old parameter value
        #         message = "New value of %s"%param
        #         new_value, success = QInputDialog.getDouble(self, header, message, float(old_value))
        #         if success:
        #             for file in self.files:
        #                 if file.file_name_short == file_name_short:
        #                     file.file_parameters[param] = new_value #change value in DataSet
        #             self.DataSettreeWidget.blockSignals(True) #avoid triggering 'itemChanged' signal that causes a false checkbox change
        #             item.setText(column, str(new_value)) #change table label
        #             self.DataSettreeWidget.blockSignals(False)
        # else:
        file_name_short = item.text(0)
        for file in self.files:
            if file.file_name_short == file_name_short:
                d = EditFileParametersDialog(self, file)
                if d.exec_():
                    for p in d.param_dict:
                        if isinstance(file.file_parameters[p], str):
                            file.file_parameters[p] = d.param_dict[p].text()
                        else:
                            try:
                                file.file_parameters[p] = float(
                                    d.param_dict[p].text())
                            except Exception as e:
                                print(e)
                        for i in range(self.DataSettreeWidget.columnCount()):
                            if p == self.DataSettreeWidget.headerItem().text(
                                    i):
                                item.setText(i, str(file.file_parameters[p]))
                    # theory xmin/max
                    try:
                        file.theory_xmin = float(d.th_xmin.text())
                    except ValueError:
                        file.theory_xmin = "None"
                    try:
                        file.theory_xmax = float(d.th_xmax.text())
                    except ValueError:
                        file.theory_xmax = "None"
                    # theory logspace and Npoints
                    try:
                        file.th_num_pts = float(d.th_num_pts.text())
                    except ValueError:
                        pass
                    try:
                        file.th_num_pts = max(int(d.th_num_pts.text()), 2)
                    except ValueError:
                        pass
                    file.theory_logspace = d.th_logspace.isChecked()
                    file.with_extra_x = d.with_extra_x.isChecked() and (
                        file.theory_xmin != "None"
                        or file.theory_xmax != "None")

    def handle_actionNew_Theory(self):
        """Create new theory and do fit
        
        [description]
        """
        self.actionNew_Theory.setDisabled(True)
        if self.cbtheory.currentIndex() == 0:
            # by default, open first theory in the list
            th_name = self.cbtheory.itemText(1)
        else:
            th_name = self.cbtheory.currentText()
        self.cbtheory.setCurrentIndex(0)  # reset the combobox selection
        if th_name != '':
            self.new_theory(th_name)
        self.actionNew_Theory.setDisabled(False)

    def new_theory(self, th_name, th_tab_id="", calculate=True, show=True):
        """[summary]
        
        [description]
        
        Arguments:
            - th_name {[type]} -- [description]
        """
        if not self.files:
            return
        if self.current_theory:
            self.set_no_limits(
                self.current_theory)  #remove the xy-range limits
        self.theory_actions_disabled(False)  #enable theory buttons
        newth = self.do_theory_new(th_name, calculate)

        # add new theory tab
        if th_tab_id == "":
            th_tab_id = newth.name
            th_tab_id = ''.join(
                c for c in th_tab_id
                if c.isupper())  #get the upper case letters of th_name
            th_tab_id = "%s%d" % (th_tab_id, self.num_theories)  #append number

        #hide all theory curves
        ntab = self.TheorytabWidget.count()
        for i in range(ntab):
            th_to_hide = self.TheorytabWidget.widget(i)
            th_to_hide.do_hide()
        #add theory tab
        self.TheorytabWidget.blockSignals(
            True)  #avoid trigger handle_thCurrentChanged()
        index = self.TheorytabWidget.addTab(newth, th_tab_id)
        self.TheorytabWidget.setCurrentIndex(
            index)  #set new theory tab as curent tab
        self.TheorytabWidget.setTabToolTip(index,
                                           th_name)  #set new-tab tool tip
        self.TheorytabWidget.blockSignals(False)
        if show:
            newth.update_parameter_table()
            newth.do_show("")
        return newth
class main_principal(QWidget):
    fecha_actual = datetime.datetime.now(
    )  # datetime es la libreria que nos ayuda con las fechas horas minutos y hsta segundos
    #en este caso nos referimos a que nos de la fecha actual
    contador_hilo = 1
    cursor = None
    lista_hilos = []

    def banner_anonymous(self):
        #banner un bannner es solo un mensaje de texto
        #el       \32 es para indicarle que queremos un espacio en blanco
        #puedes ver que hay muchos \32 en este paratado eso es debido a que
        #se necesitan espacios para imprimir bien el banner
        self.textarea_proceso.append(
            "$$$$$\32$\32\32\32\32$\32\32$$$$$\32$\32\32\32\32\32$$$$$$$\32\32\32\32\32\32######\32#####\32######\32##\32\32\32##"
        )
        self.textarea_proceso.append(
            "$\32\32\32\32\32\32\32\32$\32\32\32\32$\32\32\32\32\32$\32\32\32\32$\32\32\32\32\32$\32\32\32\32\32$\32\32\32\32\32$\32\32\32\32\32\32#\32\32\32\32\32\32#"
        )
        self.textarea_proceso.append(
            "$$$$$\32\32\32$\32\32\32\32\32$$$$$\32$\32\32\32\32\32$\32\32\32\32\32$||||||\32\32\32\32\32######\32#####\32######\32#\32\32\32\32\32#"
        )
        self.textarea_proceso.append(
            "$\32\32\32\32\32\32$\32\32$\32\32\32$\32\32\32\32\32$\32\32\32\32\32$\32\32\32\32\32\32$\32\32\32\32\32\32\32\32\32\32\32#|#\32\32\32\32\32#\32\32\32\32#\32#\32\32\32\32\32#"
        )
        self.textarea_proceso.append(
            "$$$$$\32$\32\32\32\32$\32\32$\32\32\32\32\32$$$$$\32$$$$$$$\32\32\32\32\32\32######\32#\32\32\32\32\32#\32\32\32\32#\32#\32\32\32\32\32#"
        )
        self.textarea_proceso.append(
            "Autor: Aldair Martinez Alias Hans Krammler Junior"
        )  # Aqui declaramos mi nombre jajaj XD

    def spam_uno_a_uno(self):
        self.banner_anonymous()
        print(self.fecha_actual)

    def spam_uno_a_varios(self):
        self.banner_anonymous()
        print(self.fecha_actual)
        print(Fore.GREEN + "HAZ ELEGIDO ENVIAR DESDE TU COREO A OTROS CORREO")

    def mensaje(self):
        print("SE TERMINO EL HILO")

    contador_hilo_aux = 0
    lista_hilos = []
    workers = []
    threads = []

    def incializa_hilos(self):
        if self.contador_hilo == 1:
            self.thread = QThread()
            self.thread.setObjectName("Hilo_1")
            self.worker = Worker(self.contador_hilo, self.textarea_proceso,
                                 self.label_proceso_verificacion, None)
            self.worker.moveToThread(self.thread)
            self.thread.setTerminationEnabled(True)
            self.thread.started.connect(self.worker.run)
            self.worker.finished.connect(self.terminado)
            self.thread.finished.connect(
                lambda: self.verificar_resultado_hilo(self.thread))
            self.worker.progressed.connect(
                lambda: self.reportProgress(self.worker))
            self.worker.siguiente.connect(
                lambda: self.siguiente_hilo(self.thread))
            self.thread.finished.connect(self.thread.quit)
            self.lista_hilos.append(self.thread)
            return self.lista_hilos
        else:
            self.lista_hilos = []
            self.threads.append(QThread())
            self.threads[self.contador_hilo_aux].setObjectName("Hilo_2")
            if self.contador_hilo == 2:
                print("Aqui tambien funciona")
                self.workers.append(
                    Worker(self.contador_hilo, self.textarea_proceso, None,
                           self.label_proceso_verificacion2))
            elif self.contador_hilo == 3:
                self.workers.append(
                    Worker(self.contador_hilo, self.textarea_proceso, None,
                           self.label_proceso_verificacion3))
            self.workers[self.contador_hilo_aux].moveToThread(
                self.threads[self.contador_hilo_aux])
            self.threads[self.contador_hilo_aux].started.connect(
                self.workers[self.contador_hilo_aux].run)
            self.workers[self.contador_hilo_aux].finished.connect(
                self.terminado)
            print("Pasando terminado")
            self.threads[self.contador_hilo_aux].finished.connect(
                lambda: self.verificar_resultado_hilo(self.threads[
                    self.contador_hilo_aux]))
            print("Pasando verificar resultado")
            self.workers[self.contador_hilo_aux].progressed.connect(
                lambda: self.reportProgress(self.workers[self.contador_hilo_aux
                                                         ]))
            print("Pasando reportprogress")
            self.workers[self.contador_hilo_aux].siguiente.connect(
                lambda: self.siguiente_hilo(self.threads[self.contador_hilo_aux
                                                         ]))
            self.threads[self.contador_hilo_aux].finished.connect(
                self.threads[self.contador_hilo_aux].quit)
            print("Pasando quit")
            self.lista_hilos.append(self.threads[self.contador_hilo_aux])
            return self.lista_hilos
        return None

    def siguiente_hilo(self, hilo):
        if self.contador_hilo == 1:
            if hilo.isRunning() == False:
                if hilo.isFinished() == True:
                    print("si funciono")
                    hilo.finished.connect(hilo.deleteLater)
                    hilo.finished.connect(hilo.terminate)
                    self.contador_hilo = self.contador_hilo + 1
                    self.incializa_hilos()[0].start()
        elif self.contador_hilo > 1:
            if self.get_verificado() == -1:
                return -1
            elif self.get_verificado() == -2:
                return -2
            else:
                return -3
            if hilo.isRunning() == False:
                if hilo.isFinished() == True:
                    self.contador_hilo = self.contador_hilo + 1
                    self.contador_hilo_aux = self.contador_hilo_aux + 1
                    self.incializa_hilos()[0].start()

        return 0

    cursor = None
    estado_hilo_x = 0
    lista_verificado = []

    def set_verificado(self, estado):
        self.estado_hilo_x = estado

    def get_verificado(self):
        self.lista_verificado.append(self.estado_hilo_x)
        print("get.lista.verificado" + str(self.lista_verificado[0]))
        return int(self.lista_verificado[0])

    def terminado(self):
        if self.contador_hilo == 1:
            print("TRABAJO TERMINADO")
            self.thread.finished.emit()
        elif self.contador_hilo > 1:
            self.threads[self.contador_hilo_aux].finished.emit()

    def verificar_resultado_hilo(self, thread):
        if self.contador_hilo == 1:
            if self.thread.isRunning() == False:
                print("EL HILO 1 HA TERMINADO SU TAREA")
            if self.thread.isFinished() == True:
                print("EL HILI 1 TERMINO CON EXITO")
                self.worker.progressed.emit()
        elif self.contador_hilo > 1:
            print(str(self.contador_hilo_aux))
            if thread.isRunning() == False:
                print("EL HILO" + str(self.contador_hilo_aux) +
                      "ESTA CORRIENDO")
            if thread.isFinished() == True:
                print("EL HILO" + str(self.contador_hilo_aux) + "HA TERMINADO")
                self.workers[self.contador_hilo_aux].progressed.emit()

    porcentaje = 10
    _i = 0
    lista_progreso = ["INICIANDO HILO DE EJECUCION......"]

    def reportProgress(self, worker):
        print(self.contador_hilo)
        if self.contador_hilo == 1:
            print("REPORTANDO HILO")
            #print("POSICION ACTUAL DEL CURSOR"+str(int(self.textarea_proceso.textCursor().position())))
            worker.siguiente.emit()
        else:
            if self.contador_hilo == 2:
                email = self.line_edit_user_email.text()
                password = self.line_edit_user_password.text()
                longitud_email = len(email)
                longitud_password = len(password)
                if longitud_email == 0 or longitud_password == 0:

                    self.set_verificado(-1)
            elif self.contador_hilo == 3:
                email = self.line_edit_user_email.text()
                email_to_list = list(email)
                contador = 1
                for _x in len(email):
                    if email_to_list[_x] == "@":
                        contador = contador + 1
                if contador > 1:
                    self.set_verificado(-2)
            elif self.contador_hilo == 4:
                contador = 1
                email_dominio = email.split(".")
                textarea_proceso.append("DIVIDIENDO TU EMAIL--->" +
                                        email_dominio)
                longitud_dominio_email = len(email_dominio)
                textarea_proceso.append(
                    "VERIFICANDO COINCIDENCIA DE DOMINIO DE EMAIL....")
                dominios = [
                    "gmail.com", "outlook.com", "outlook.es", "hotmail.com",
                    "hotmail.mx", "hotmail.es"
                ]
                longitud_dominio_gmail = len(dominios[0])
                longitud_dominio_outlook_com = len(dominios[1])
                longitud_dominio_outlook_es = len(dominios[2])
                longitud_dominio_hotmail_com = len(dominios[3])
                longitud_dominio_hotmail_mx = len(dominios[4])
                longitud_dominio_hotmail_es = len(dominios[5])
                for _i in range(longitud_dominio_email):
                    for _j in (range(longitud_dominio_gmail)
                               or range(longitud_dominio_outlook_com)
                               or range(longitud_dominio_outlook_es)
                               or range(longitud_dominio_hotmail_com)
                               or range(longitud_dominio_hotmail_mx)
                               or range(longitud_dominio_hotmail_es)):
                        if _j < longitud_dominio_gmail:
                            if dominios[0][_j] == email_dominio[1][_j]:
                                print(dominios[0][j])
                                contador = contador + 1
                        elif _j < longitud_dominio_outlook_com:
                            if dominios[1][_j] == email_dominio[1][_j]:
                                contador = contador + 1
                        elif _j < longitud_dominio_outlook_es:
                            if dominios[2][_j] == email_dominio[1][_j]:
                                contador = contador + 1
                        elif _j < longitud_dominio_hotmail_com:
                            if dominios[3][_j] == email_dominio[1][_j]:
                                contador = contador + 1
                        elif _j < longitud_dominio_hotmail_mx:
                            if dominios[4][_j] == email_dominio[1][_j]:
                                contador = contador + 1
                        elif _j < longitud_dominio_hotmail_es:
                            if dominios[5][_j] == email_dominio[1][_j]:
                                contador = contador + 1
                    if contador > longitud_dominio_gmail:
                        return -3
                    else:
                        contador = 1
            print("AQUI MEN")
            posicion_textarea = len(self.lista_progreso[self._i])
            self.cursor = self.textarea_proceso.textCursor()
            print("CURSOR ACTUAL" + str(self.cursor))
            print("POSICION CURSOR ACTUAL++" + str(self.cursor.position()))
            if self.cursor.atEnd() == True:
                print("FIN DEL CURSOR True")
                print("TEXTO SELECCIONADO ANTES" + self.cursor.selectedText())
                posicion_inicial = (self.cursor.position() -
                                    1) - (posicion_textarea - 1) + 1
                print("posicion inicial" + str(posicion_inicial))
                time.sleep(0.4)
                self.cursor.setPosition(posicion_inicial,
                                        QTextCursor.KeepAnchor)
                print("TEXTO SELECCIONADO AHORA" + self.cursor.selectedText())
                print("POSICION CURSOR ACTUAL--" + str(self.cursor.position()))
                self.progreso = self.cursor.selectedText() + str(
                    self.porcentaje)
                self.porcentaje = self.porcentaje + 10
                self.textarea_proceso.append(self.progreso)
                print("POSICION CURSOR ACTUAL++" + str(self.cursor.position()))
            self._i = self._i + 1
            worker.siguiente.emit()

    def verificar_opcion(self):
        pass

    def validar_oprciones(self):
        if self.checkbox_opcion_spam_uno_a_uno.isChecked(
        ) == True and self.checkbox_opcion_spam_uno_a_varios.isChecked():
            self.label_estado_proceso.setText(
                Fore.RED +
                "LO SIENTO NO PUEDES SELECCIONAR DOS OPCIONES A LA VEZ")
            return False
        else:
            return True

    def escannear_red(self):
        scan = nmap.PortScanner()
        informacion_sistema = os.uname()

    def presionado(self):
        resultado_validar_opciones = self.validar_oprciones()
        if resultado_validar_opciones == True:
            self.inciar_hilo_principal()
            self.resultado_verificacion_email = 0
            if self.resultado_verificacion_email == 0:
                print("PASANDO AL SIGUIENTE HILO DE EJECUCION")
            if self.resultado_verificacion_email == 1:
                if self.checkbox_opcion_spam_uno_a_uno.isChecked() == True:
                    print(
                        "LAS OCPIONES SELECCIONADAAS EN LOS CASILLA SON VALIDAS"
                    )
            else:
                if self.resultado_verificacion_email == -1 or self.resultado_verificacion_email == -2 or self.resultado_verificacion_email == -3:
                    if self.resultado_verificacion_email == -1:
                        self.label_estado_proceso.setText(
                            "NO HAS INGRESADO NADA EN EL PRIMER CAMPO")
                        self.textarea_proceso.append(
                            "ERROR NO HAS INGRESADO NADA EN EL PRIMER CAMPO")
                    elif self.resultado_verificacion_email == -2:
                        self.label_estado_proceso.setText(
                            "HAS MAS DE UN ARROBA EN TU CORREO")
                        self.textarea_proceso.append(
                            "ERROR HAY MAS DE UN ARROBA EN TU CORREO")
                    elif self.resultado_verificacion_email == -3:
                        self.label_estado_proceso.setText(
                            "TERMINACION DE CORREO NO VALIDA")

        else:
            self.textarea_proceso.append(
                "INTENTE DE NUEVO RELLENAR LOS CAMPOS ADECUADAMENTE")

    def __init__(self, parent=None):
        #Parte de intefaz grafica
        super().__init__(parent)

        self.color = QColor(0, 0, 0, 0.5)
        self.setGeometry(550, 100, 1500, 500)
        self.pallette = QPalette(self.color)
        self.pallette.setColor(QPalette.Text, Qt.cyan)

        self.titulo_ventana = "ENVIO DE CORREO PARA HACER SPAM"
        self.setWindowTitle(self.titulo_ventana)
        self.setStyleSheet(
            "border-color: cyan; border-style: dashed; border-width: 2px; color:white"
        )
        self.setPalette(self.pallette)
        self.checkbox_opcion_spam_uno_a_uno = QCheckBox(
            "REALIZAR SPAM UNO A UN CORREO")
        self.checkbox_opcion_spam_uno_a_uno.clicked.connect(
            self.spam_uno_a_uno)
        self.checkbox_opcion_spam_uno_a_varios = QCheckBox(
            "REALIZAR SPAM UNO A VARIOS COOREOS")
        self.checkbox_opcion_spam_uno_a_varios.clicked.connect(
            self.spam_uno_a_varios)

        self.label_user_email = QLabel("Ingresa tu direccion de correo: ")
        self.label_user_email.setFont(QFont("Times", 14, QFont.Bold, True))
        self.label_user_email.setStyleSheet("color: white")

        self.line_edit_user_email = QLineEdit(self)
        self.line_edit_user_email.setPlaceholderText(
            "Ingresa tu direccion de cooreo:")
        self.line_edit_user_email.setFont(QFont("Times", 14, QFont.Bold, True))
        self.line_edit_user_email.setStyleSheet("color : black")

        self.label_user_password = QLabel("Ingresa tu password de correo")
        self.label_user_password.setFont(QFont("Times", 14, QFont.Bold, True))
        self.label_user_password.setStyleSheet("color: white")

        self.line_edit_user_password = QLineEdit(self)
        self.line_edit_user_password.setPlaceholderText(
            "Ingresa tu password de tu correo:")
        self.line_edit_user_password.setFont(
            QFont("Times", 14, QFont.Bold, True))
        self.line_edit_user_password.setStyleSheet("color : black")

        self.label_victima_email = QLabel(
            "Ingresa direccion de correo destinatario: ")
        self.label_victima_email.setFont(QFont("Times", 14, QFont.Bold, True))
        self.label_victima_email.setStyleSheet("color: white")

        self.line_edit_victima_email = QLineEdit(self)
        self.line_edit_victima_email.setPlaceholderText(
            "Ingresa tu direccion de cooreo:")
        self.line_edit_victima_email.setFont(
            QFont("Times", 14, QFont.Bold, True))
        self.line_edit_victima_email.setStyleSheet("color : black")

        self.label_user_asunto = QLabel("Ingresa el asunto ")
        self.label_user_asunto.setFont(QFont("Times", 14, QFont.Bold, True))
        self.label_user_asunto.setStyleSheet("color: white")

        self.line_edit_user_asunto = QLineEdit(self)
        self.line_edit_user_asunto.setPlaceholderText(
            "Ingresa tu direccion de cooreo:")
        self.line_edit_user_asunto.setFont(QFont("Times", 14, QFont.Bold,
                                                 True))
        self.line_edit_user_asunto.setStyleSheet("color : black")

        self.pushbutton_enviar = QPushButton("ENVIAR SPAM")
        self.pushbutton_enviar.setFont(QFont("Times", 14, QFont.Bold, True))
        self.pushbutton_enviar.setPalette(self.pallette)

        self.label_estado_proceso = QLabel("")
        self.label_estado_proceso.setText("ESPERANDO DATOS....")

        self.label_proceso = QLabel("Estado verificacion email y password")
        self.label_proceso_verificacion = QLabel("")
        self.label_proceso2 = QLabel(
            "Estado verificacion arroba de email origen y destino")
        self.label_proceso_verificacion2 = QLabel("")
        self.label_proceso3 = QLabel(
            "Estado verificacion terminacion correo origen y destino")
        self.label_proceso_verificacion3 = QLabel("")
        self.combobox_dominios_from = QComboBox()
        self.combobox_dominios_from.addItem("Gmail.com")
        self.combobox_dominios_from.insertSeparator(1)
        self.combobox_dominios_from.addItem("Outlook.com")
        self.combobox_dominios_from.addItem("Outlook.es")
        self.combobox_dominios_from.insertSeparator(4)
        self.combobox_dominios_from.addItem("Hotmail.com")
        self.combobox_dominios_from.addItem("Hotmail.es")
        self.combobox_dominios_from.addItem("Hotmail.mx")
        self.combobox_dominios_from.setStyleSheet(
            "background-color:black; color: cyan")

        self.combobox_dominios_to = QComboBox()
        self.combobox_dominios_to.addItem("Gmail.com")
        self.combobox_dominios_to.insertSeparator(1)
        self.combobox_dominios_to.addItem("Outlook.com")
        self.combobox_dominios_to.addItem("Outlook.es")
        self.combobox_dominios_to.insertSeparator(4)
        self.combobox_dominios_to.addItem("Hotmail.com")
        self.combobox_dominios_to.addItem("Hotmail.es")
        self.combobox_dominios_to.addItem("Hotmail.mx")
        self.combobox_dominios_to.setStyleSheet(
            "background-color:black; color: cyan")

        self.combobox_dominios_from.currentTextChanged.connect(
            self.verificar_opcion)
        self.combobox_dominios_to.currentTextChanged.connect(
            self.verificar_opcion)
        self.pushbutton_enviar.clicked.connect(self.presionado)

        self.layout_main = QHBoxLayout(self)

        self.layout_principal = QVBoxLayout()
        self.layout_principal.addWidget(self.label_user_email)
        self.layout_principal.addWidget(self.line_edit_user_email)
        self.layout_principal.addWidget(self.label_user_password)
        self.layout_principal.addWidget(self.line_edit_user_password)
        self.layout_principal.addWidget(self.label_victima_email)
        self.layout_principal.addWidget(self.line_edit_victima_email)
        self.layout_principal.addWidget(self.label_user_asunto)
        self.layout_principal.addWidget(self.line_edit_user_asunto)
        self.layout_principal.addWidget(self.checkbox_opcion_spam_uno_a_uno)
        self.layout_principal.addWidget(self.checkbox_opcion_spam_uno_a_varios)
        self.layout_principal.addWidget(self.pushbutton_enviar)
        self.layout_principal.addWidget(self.label_estado_proceso)
        self.layout_principal.addWidget(self.combobox_dominios_from)
        self.layout_principal.addWidget(self.combobox_dominios_to)
        self.layout_principal.addWidget(self.label_proceso)
        self.layout_principal.addWidget(self.label_proceso_verificacion)
        self.layout_principal.addWidget(self.label_proceso2)
        self.layout_principal.addWidget(self.label_proceso_verificacion2)
        self.layout_principal.addWidget(self.label_proceso3)
        self.layout_principal.addWidget(self.label_proceso_verificacion3)

        self.layout_secundario = QVBoxLayout()
        self.textarea_proceso = QTextEdit()
        self.textarea_proceso.setPlaceholderText("ESPERANDO PARA PROCESAR")
        self.textarea_proceso.setFont(QFont("Times", 14, QFont.Bold, True))
        self.textarea_proceso.setGeometry(0, 0, 500, 400)
        self.textarea_proceso.setStyleSheet(
            "color: yellow; background-color:black; border-style:solid")
        self.textarea_proceso.setReadOnly(False)
        self.textarea_proceso.setOverwriteMode(QTextEdit.WidgetWidth)
        self.layout_secundario.addWidget(self.textarea_proceso)

        self.layout_main.addLayout(self.layout_principal, 4)
        self.layout_main.addLayout(self.layout_secundario, 4)

    def inciar_hilo_principal(self):
        self.incializa_hilos()[0].start()
        return 0
class FluidPropertyInterrogatorPlugin(QtWidgets.QWidget):
    """
    Fluid property interrogator GUI
    """

    SINGLE_PHASE = 1
    TWO_PHASE = 2
    TWO_PHASE_NCG = 3

    def __init__(self, **kwargs):
        super(FluidPropertyInterrogatorPlugin, self).__init__(**kwargs)

        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)

        self.layoutMain = QVBoxLayout(self)

        self.ctlFPType = QComboBox(self)
        self.layoutMain.addWidget(self.ctlFPType)

        self.layoutFPParams = QStackedLayout()
        self.ctlSinglePhaseWidget = self.setupSinglePhaseUI(self.layoutFPParams)
        self.ctlTwoPhaseWidget = self.setupTwoPhaseUI(self.layoutFPParams)
        self.layoutFPParams.addWidget(self.ctlSinglePhaseWidget)
        self.layoutFPParams.addWidget(self.ctlTwoPhaseWidget)
        self.layoutMain.addLayout(self.layoutFPParams)

        self.ctlFPType.currentIndexChanged.connect(self.onFluidPropertyChanged)

    def setupSinglePhaseUI(self, layout):
        widget = QTabWidget(self)
        widget.addTab(FluidPropertyWidget1PhasePT(self), "p, T")
        widget.addTab(FluidPropertyWidget1PhaseRhoE(self), "rho, e")
        widget.addTab(FluidPropertyWidget1PhaseRhoP(self), "rho, p")
        return widget

    def setupTwoPhaseUI(self, layout):
        widget = QTabWidget(self)
        widget.addTab(FluidPropertyWidget2PhaseP(self), "p")
        widget.addTab(FluidPropertyWidget2PhaseT(self), "T")
        return widget

    def fillFluidProperties(self):
        """
        Fill the combo box with single phase fluid property classes
        """

        fp_classes = [
            {
                'name': 'Single phase',
                'classes': [],
                'data': self.SINGLE_PHASE
            },
            {
                'name': 'Two phase',
                'classes': [],
                'data': self.TWO_PHASE
            }
        ]

        json_fps = self.exe_info.json_data.json_data["blocks"]['Modules']['subblocks']['FluidProperties']['star']['subblock_types']

        for class_name, vals in json_fps.items():
            params = vals['parameters']
            if 'fp_type' in params:
                fp_type = params['fp_type']['default']
                if fp_type == 'single-phase-fp':
                    fp_classes[0]['classes'].append(class_name)
                elif fp_type == 'two-phase-fp':
                    fp_classes[1]['classes'].append(class_name)

        for fpc in fp_classes:
            fpc['classes'].sort()

        sep_indices = []
        model = QStandardItemModel()
        for fpc in fp_classes:
            parent = QStandardItem(fpc['name'])
            parent.setEnabled(False)
            model.appendRow(parent)
            for c in fpc['classes']:
                item = QStandardItem(c)
                item.setData(fpc['data'])
                model.appendRow(item)
            sep_indices.append(model.rowCount())

        self.ctlFPType.setModel(model)
        for idx in sep_indices[:-1]:
            self.ctlFPType.insertSeparator(idx)

    def onFluidPropertyChanged(self, index):
        fp_type = self.ctlFPType.model().item(index).data()
        if fp_type == self.SINGLE_PHASE:
            self.layoutFPParams.setCurrentWidget(self.ctlSinglePhaseWidget)
            self.ctlSinglePhaseWidget.currentWidget().updateWidgets()
        elif fp_type == self.TWO_PHASE:
            self.layoutFPParams.setCurrentWidget(self.ctlTwoPhaseWidget)
            self.ctlTwoPhaseWidget.currentWidget().updateWidgets()
        else:
            raise SystemExit("Unknown fp_type")

    def fluidPropertyInputFileBlock(self):
        str = ""
        str += "[./fp]\n"
        str += "type = {}\n".format(self.ctlFPType.currentText())
        str += "[../]\n"
        return str

    def setExecutablePath(self, exe_path):
        self.exe_path = exe_path
        self.exe_info = ExecutableInfo()
        self.exe_info.setPath(self.exe_path)
        self.fillFluidProperties()

        for tab in range(self.ctlSinglePhaseWidget.count()):
            self.ctlSinglePhaseWidget.widget(tab).setExecutablePath(exe_path)
        for tab in range(self.ctlTwoPhaseWidget.count()):
            self.ctlTwoPhaseWidget.widget(tab).setExecutablePath(exe_path)
Example #31
0
class EditStructure(ToolInstance):

    help = "https://github.com/QChASM/SEQCROW/wiki/Structure-Modification-Tool"
    SESSION_ENDURING = True
    SESSION_SAVE = True

    def __init__(self, session, name):       
        super().__init__(session, name)
        
        self.settings = _EditStructureSettings(session, "Structure Modification")
        
        self.tool_window = MainToolWindow(self)        

        self.close_previous_bool = self.settings.modify

        self._build_ui()

    def _build_ui(self):
        layout = QGridLayout()
        
        self.alchemy_tabs = QTabWidget()
        
        #substitute
        substitute_tab = QWidget()
        substitute_layout = QGridLayout(substitute_tab) 

        sublabel = QLabel("substituent name:")
        substitute_layout.addWidget(sublabel, 0, 0, Qt.AlignVCenter)
        
        self.subname = QLineEdit()
        # self.subname.setText("Et")
        sub_completer = NameCompleter(Substituent.list(), self.subname)
        self.subname.setCompleter(sub_completer)
        self.subname.setToolTip("name of substituent in the AaronTools library or your personal library\nseparate names with commas and uncheck 'modify selected structure' to create several structures")
        substitute_layout.addWidget(self.subname, 0, 1, Qt.AlignVCenter)
        
        open_sub_lib = QPushButton("from library...")
        open_sub_lib.clicked.connect(self.open_sub_selector)
        substitute_layout.addWidget(open_sub_lib, 0, 2, Qt.AlignTop)        
        
        substitute_layout.addWidget(QLabel("modify selected structure:"), 1, 0, 1, 1, Qt.AlignVCenter)
        
        self.close_previous_sub = QCheckBox()
        self.close_previous_sub.setToolTip("checked: selected structure will be modified\nunchecked: new model will be created for the modified structure")
        self.close_previous_sub.setChecked(self.settings.modify)
        self.close_previous_sub.stateChanged.connect(self.close_previous_change)
        substitute_layout.addWidget(self.close_previous_sub, 1, 1, 1, 2, Qt.AlignTop)    
        
        substitute_layout.addWidget(QLabel("relax substituent:"), 2, 0, 1, 1, Qt.AlignVCenter)
        
        self.minimize = QCheckBox()
        self.minimize.setToolTip("spin the added substituents to try to minimize the LJ potential energy")
        self.minimize.setChecked(self.settings.minimize)
        substitute_layout.addWidget(self.minimize, 2, 1, 1, 1, Qt.AlignTop)
        
        substitute_layout.addWidget(QLabel("guess previous substituent:"), 3, 0, 1, 1, Qt.AlignVCenter)
        
        self.guess_old = QCheckBox()
        self.guess_old.setToolTip("checked: leave the longest connected fragment in the residue\nunchecked: previous substituent must be selected")
        self.guess_old.setChecked(self.settings.guess)
        self.guess_old.stateChanged.connect(lambda state, settings=self.settings: settings.__setattr__("guess", True if state == Qt.Checked else False))
        substitute_layout.addWidget(self.guess_old, 3, 1, 1, 2, Qt.AlignTop)
        
        substitute_layout.addWidget(QLabel("new residue:"), 5, 0, 1, 1, Qt.AlignVCenter)

        self.new_residue = QCheckBox()
        self.new_residue.setToolTip("put the new substituent in its own residue instead\nof adding it to the residue of the old substituent")
        self.new_residue.setChecked(self.settings.new_residue)
        self.new_residue.stateChanged.connect(lambda state, settings=self.settings: settings.__setattr__("new_residue", True if state == Qt.Checked else False))
        substitute_layout.addWidget(self.new_residue, 5, 1, 1, 2, Qt.AlignTop)
        
        substitute_layout.addWidget(QLabel("use distance names:"), 4, 0, 1, 1, Qt.AlignVCenter)
        
        self.use_greek = QCheckBox()
        self.use_greek.setChecked(self.settings.use_greek)
        self.use_greek.setToolTip("indicate distance from point of attachment with atom name")
        substitute_layout.addWidget(self.use_greek, 4, 1, 1, 1, Qt.AlignTop)

        substitute_layout.addWidget(QLabel("change residue name:"), 6, 0, 1, 1, Qt.AlignVCenter)
        
        self.new_sub_name = QLineEdit()
        self.new_sub_name.setToolTip("change name of modified residues")
        self.new_sub_name.setPlaceholderText("leave blank to keep current")
        substitute_layout.addWidget(self.new_sub_name, 6, 1, 1, 2, Qt.AlignTop)

        substitute_button = QPushButton("substitute current selection")
        substitute_button.clicked.connect(self.do_substitute)
        substitute_layout.addWidget(substitute_button, 7, 0, 1, 3, Qt.AlignTop)
        self.substitute_button = substitute_button
        
        substitute_layout.setRowStretch(0, 0)
        substitute_layout.setRowStretch(1, 0)
        substitute_layout.setRowStretch(2, 0)
        substitute_layout.setRowStretch(3, 0)
        substitute_layout.setRowStretch(4, 0)
        substitute_layout.setRowStretch(5, 0)
        substitute_layout.setRowStretch(6, 0)
        substitute_layout.setRowStretch(7, 1)
        
        
        #map ligand
        maplig_tab = QWidget()
        maplig_layout = QGridLayout(maplig_tab)
        
        liglabel = QLabel("ligand name:")
        maplig_layout.addWidget(liglabel, 0, 0, Qt.AlignVCenter)
        
        self.ligname = QLineEdit()
        lig_completer = NameCompleter(Component.list(), self.ligname)
        self.ligname.setCompleter(lig_completer)
        self.ligname.setToolTip("name of ligand in the AaronTools library or your personal library\nseparate names with commas and uncheck 'modify selected structure' to create several structures")
        maplig_layout.addWidget(self.ligname, 0, 1, Qt.AlignVCenter)
        
        open_lig_lib = QPushButton("from library...")
        open_lig_lib.clicked.connect(self.open_lig_selector)
        maplig_layout.addWidget(open_lig_lib, 0, 2, Qt.AlignTop)        
        
        maplig_layout.addWidget(QLabel("modify selected structure:"), 1, 0, 1, 1, Qt.AlignVCenter)
        
        self.close_previous_lig = QCheckBox()
        self.close_previous_lig.setToolTip("checked: selected structure will be modified\nunchecked: new model will be created for the modified structure")
        self.close_previous_lig.setChecked(self.settings.modify)
        self.close_previous_lig.stateChanged.connect(self.close_previous_change)
        maplig_layout.addWidget(self.close_previous_lig, 1, 1, 1, 2, Qt.AlignTop)

        maplig_button = QPushButton("swap ligand with selected coordinating atoms")
        maplig_button.clicked.connect(self.do_maplig)
        maplig_layout.addWidget(maplig_button, 2, 0, 1, 3, Qt.AlignTop)
        self.maplig_button = maplig_button

        start_structure_button = QPushButton("place in:")
        self.lig_model_selector = ModelComboBox(self.session, addNew=True)
        start_structure_button.clicked.connect(self.do_new_lig)
        maplig_layout.addWidget(start_structure_button, 3, 0, 1, 1, Qt.AlignTop)
        maplig_layout.addWidget(self.lig_model_selector, 3, 1, 1, 2, Qt.AlignTop)

        maplig_layout.setRowStretch(0, 0)
        maplig_layout.setRowStretch(1, 0)
        maplig_layout.setRowStretch(2, 0)
        maplig_layout.setRowStretch(3, 1)
        
        
        #close ring
        closering_tab = QWidget()
        closering_layout = QGridLayout(closering_tab)
        
        ringlabel = QLabel("ring name:")
        closering_layout.addWidget(ringlabel, 0, 0, Qt.AlignVCenter)
        
        self.ringname = QLineEdit()
        ring_completer = NameCompleter(Ring.list(), self.ringname)
        self.ringname.setCompleter(ring_completer)
        self.ringname.setToolTip("name of ring in the AaronTools library or your personal library\nseparate names with commas and uncheck 'modify selected structure' to create several structures")
        closering_layout.addWidget(self.ringname, 0, 1, Qt.AlignVCenter)
        
        open_ring_lib = QPushButton("from library...")
        open_ring_lib.clicked.connect(self.open_ring_selector)
        closering_layout.addWidget(open_ring_lib, 0, 2, Qt.AlignTop)        
        
        closering_layout.addWidget(QLabel("modify selected structure:"), 1, 0, 1, 1, Qt.AlignVCenter) 
        
        self.close_previous_ring = QCheckBox()
        self.close_previous_ring.setToolTip("checked: selected structure will be modified\nunchecked: new model will be created for the modified structure")
        self.close_previous_ring.setChecked(self.settings.modify)
        self.close_previous_ring.stateChanged.connect(self.close_previous_change)
        closering_layout.addWidget(self.close_previous_ring, 1, 1, 1, 2, Qt.AlignTop)

        closering_layout.addWidget(QLabel("try multiple:"), 2, 0, 1, 1, Qt.AlignVCenter)

        self.minimize_ring = QCheckBox()
        self.minimize_ring.setToolTip("try to use other versions of this ring in the library to find the one that fits best")
        self.minimize_ring.setChecked(self.settings.minimize_ring)
        closering_layout.addWidget(self.minimize_ring, 2, 1, 1, 2, Qt.AlignTop)

        closering_layout.addWidget(QLabel("new residue name:"), 3, 0, 1, 1, Qt.AlignVCenter)
        
        self.new_ring_name = QLineEdit()
        self.new_ring_name.setToolTip("change name of modified residues")
        self.new_ring_name.setPlaceholderText("leave blank to keep current")
        closering_layout.addWidget(self.new_ring_name, 3, 1, 1, 2, Qt.AlignTop)

        closering_button = QPushButton("put a ring on current selection")
        closering_button.clicked.connect(self.do_fusering)

        closering_layout.addWidget(closering_button, 4, 0, 1, 3, Qt.AlignTop)
        self.closering_button = closering_button

        start_structure_button = QPushButton("place in:")
        self.ring_model_selector = ModelComboBox(self.session, addNew=True)
        start_structure_button.clicked.connect(self.do_new_ring)
        closering_layout.addWidget(start_structure_button, 5, 0, 1, 1, Qt.AlignTop)
        closering_layout.addWidget(self.ring_model_selector, 5, 1, 1, 2, Qt.AlignTop)

        closering_layout.setRowStretch(0, 0)
        closering_layout.setRowStretch(1, 0)
        closering_layout.setRowStretch(2, 0)
        closering_layout.setRowStretch(3, 0)
        closering_layout.setRowStretch(4, 0)
        closering_layout.setRowStretch(5, 1)


        #change element
        changeelement_tab = QWidget()
        changeelement_layout = QFormLayout(changeelement_tab)
        
        self.element = QPushButton("C")
        self.element.setMinimumWidth(int(1.3*self.element.fontMetrics().boundingRect("QQ").width()))
        self.element.setMaximumWidth(int(1.3*self.element.fontMetrics().boundingRect("QQ").width()))
        self.element.setMinimumHeight(int(1.5*self.element.fontMetrics().boundingRect("QQ").height()))
        self.element.setMaximumHeight(int(1.5*self.element.fontMetrics().boundingRect("QQ").height()))
        ele_color = tuple(list(element_color(ELEMENTS.index("C")))[:-1])
        self.element.setStyleSheet(
            "QPushButton { background: rgb(%i, %i, %i); color: %s; font-weight: bold; }" % (
                *ele_color,
                'white' if sum(
                    int(x < 130) - int(x > 225) for x in ele_color
                ) - int(ele_color[1] > 225) +
                int(ele_color[2] > 200) >= 2 else 'black'
            )
        )
        self.element.clicked.connect(self.open_ptable)
        changeelement_layout.addRow("element:", self.element)
        
        self.vsepr = QComboBox()
        self.vsepr.addItems([
            "do not change",                  # 0
            
            "linear (1 bond)",                # 1
            
            "linear (2 bonds)",               # 2 
            "trigonal planar (2 bonds)",      # 3
            "tetrahedral (2 bonds)",          # 4 
            
            "trigonal planar",                # 5
            "tetrahedral (3 bonds)",          # 6
            "T-shaped",                       # 7
            
            "trigonal pyramidal",             # 8
            "tetrahedral",                    # 9
            "sawhorse",                       #10
            "seesaw",                         #11
            "square planar",                  #12
            
            "trigonal bipyramidal",           #13
            "square pyramidal",               #14
            "pentagonal",                     #15
            
            "octahedral",                     #16
            "hexagonal",                      #17
            "trigonal prismatic",             #18
            "pentagonal pyramidal",           #19
            
            "capped octahedral",              #20
            "capped trigonal prismatic",      #21
            "heptagonal",                     #22
            "hexagonal pyramidal",            #23
            "pentagonal bipyramidal",         #24
            
            "biaugmented trigonal prismatic", #25
            "cubic",                          #26
            "elongated trigonal bipyramidal", #27
            "hexagonal bipyramidal",          #28
            "heptagonal pyramidal",           #29
            "octagonal",                      #30
            "square antiprismatic",           #31
            "trigonal dodecahedral",          #32
            
            "capped cube",                    #33
            "capped square antiprismatic",    #34
            "enneagonal",                     #35
            "heptagonal bipyramidal",         #36
            "hula-hoop",                      #37
            "triangular cupola",              #38
            "tridiminished icosahedral",      #39
            "muffin",                         #40
            "octagonal pyramidal",            #41
            "tricapped trigonal prismatic",   #42
        ])
        
        self.vsepr.setCurrentIndex(9)
        
        self.vsepr.insertSeparator(33)
        self.vsepr.insertSeparator(25)
        self.vsepr.insertSeparator(20)
        self.vsepr.insertSeparator(16)
        self.vsepr.insertSeparator(13)
        self.vsepr.insertSeparator(8)
        self.vsepr.insertSeparator(5)
        self.vsepr.insertSeparator(2)
        self.vsepr.insertSeparator(1)
        self.vsepr.insertSeparator(0)
        changeelement_layout.addRow("geometry:", self.vsepr)
        
        self.change_bonds = QCheckBox()
        self.change_bonds.setChecked(self.settings.change_bonds)
        changeelement_layout.addRow("adjust bond lengths:", self.change_bonds)
        
        change_element_button = QPushButton("change selected elements")
        change_element_button.clicked.connect(self.do_change_element)
        changeelement_layout.addRow(change_element_button)
        self.change_element_button = change_element_button

        start_structure_button = QPushButton("place in:")
        self.model_selector = ModelComboBox(self.session, addNew=True)
        start_structure_button.clicked.connect(self.do_new_atom)
        changeelement_layout.addRow(start_structure_button, self.model_selector)
        
        delete_atoms_button = QPushButton("delete selected atoms")
        delete_atoms_button.clicked.connect(self.delete_atoms)
        changeelement_layout.addRow(delete_atoms_button)

        self.alchemy_tabs.addTab(substitute_tab, "substitute")
        self.alchemy_tabs.addTab(maplig_tab, "swap ligand")
        self.alchemy_tabs.addTab(closering_tab, "fuse ring")
        self.alchemy_tabs.addTab(changeelement_tab, "change element")

        layout.addWidget(self.alchemy_tabs)

        self.tool_window.ui_area.setLayout(layout)

        self.tool_window.manage(None)
    
    def close_previous_change(self, state):
        if state == Qt.Checked:
            self.settings.modify = True
            for checkbox in [self.close_previous_lig, self.close_previous_sub, self.close_previous_ring]:
                checkbox.setChecked(True)
            self.close_previous_bool = True
        else:
            self.settings.modify = False
            for checkbox in [self.close_previous_lig, self.close_previous_sub, self.close_previous_ring]:
                checkbox.setChecked(False)
            self.close_previous_bool = False
    
    def do_substitute(self):
        subnames = self.subname.text()
        
        new_name = self.new_sub_name.text()

        use_attached = not self.guess_old.isChecked()
        
        minimize = self.minimize.isChecked()
        
        new_residue = self.new_residue.isChecked()

        use_greek = self.use_greek.isChecked()
        
        self.settings.minimize = minimize
        self.settings.use_greek = use_greek

        if len(new_name.strip()) > 0:
            run(
                self.session, 
                "substitute sel substituents %s newName %s guessAttachment %s modify %s minimize %s useRemoteness %s newResidue %s" %
                (
                    subnames,
                    new_name,
                    not use_attached,
                    self.close_previous_bool,
                    minimize,
                    use_greek,
                    new_residue,
                )
            )

        else:
            run(
                self.session,
                "substitute sel substituents %s guessAttachment %s modify %s minimize %s useRemoteness %s newResidue %s" %
                (
                    subnames,
                    not use_attached,
                    self.close_previous_bool,
                    minimize,
                    use_greek,
                    new_residue,
                )
            )

    def open_sub_selector(self):
        self.tool_window.create_child_window("select substituents", window_class=SubstituentSelection, textBox=self.subname)

    def do_maplig(self):
        lignames = self.ligname.text()
        selection = selected_atoms(self.session)
        
        if len(selection) < 1:
            raise RuntimeWarning("nothing selected")
        
        models = {}
        for atom in selection:
            if atom.structure not in models:
                models[atom.structure] = [AtomSpec(atom.atomspec)]
            else:
                models[atom.structure].append(AtomSpec(atom.atomspec))        
        
        first_pass = True
        new_structures = []
        for ligname in lignames.split(','):
            ligname = ligname.strip()
            lig = Component(ligname)
            for model in models:
                if self.close_previous_bool and first_pass:
                    rescol = ResidueCollection(model)
                elif self.close_previous_bool and not first_pass:
                    raise RuntimeError("only the first model can be replaced")
                else:
                    model_copy = model.copy()
                    rescol = ResidueCollection(model_copy)
                    for i, atom in enumerate(model.atoms):
                        rescol.atoms[i].atomspec = atom.atomspec
                        rescol.atoms[i].add_tag(atom.atomspec)
                        rescol.atoms[i].chix_atom = atom

                target = rescol.find(models[model])
                if len(target) % len(lig.key_atoms) == 0:
                    k = 0
                    ligands = []
                    while k != len(target):
                        res_lig = ResidueCollection(lig.copy(), comment=lig.comment)
                        res_lig.parse_comment()
                        res_lig = Component(res_lig, key_atoms = ",".join([str(k + 1) for k in res_lig.other["key_atoms"]]))
                        ligands.append(res_lig)
                        k += len(lig.key_atoms)
                else:
                    raise RuntimeError("number of key atoms no not match: %i now, new ligand has %i" % (len(target), len(lig.key_atoms)))
                
                rescol.map_ligand(ligands, target)

                for center_atom in rescol.center:
                    center_atom.connected = set([])
                    for atom in rescol.atoms:
                        if atom not in rescol.center:
                            if center_atom.is_connected(atom):
                                atom.connected.add(center_atom)
                                center_atom.connected.add(atom)
                
                if self.close_previous_bool:    
                    rescol.update_chix(model)
                else:
                    struc = rescol.get_chimera(self.session)
                    new_structures.append(struc)
            
            first_pass = False
        
        if not self.close_previous_bool:
            self.session.models.add(new_structures)

    def open_lig_selector(self):
        self.tool_window.create_child_window("select ligands", window_class=LigandSelection, textBox=self.ligname)
    
    def do_fusering(self):
        ring_names = self.ringname.text()
        
        new_name = self.new_ring_name.text()

        minimize_ring = self.minimize_ring.isChecked()
        self.settings.minimize_ring = minimize_ring

        if len(new_name.strip()) > 0:
            run(
                self.session,
                "fuseRing sel rings %s newName %s modify %s minimize %s" % (
                    ring_names,
                    new_name,
                    self.close_previous_bool,
                    minimize_ring,
                )
            )

        else:
            run(
                self.session,
                "fuseRing sel rings %s modify %s minimize %s" % (
                    ring_names,
                    self.close_previous_bool,
                    minimize_ring,
                )
            )

    def open_ring_selector(self):
        self.tool_window.create_child_window("select rings", window_class=RingSelection, textBox=self.ringname)

    def open_ptable(self):
        self.tool_window.create_child_window("select element", window_class=_PTable, button=self.element)
    
    def display_help(self):
        """Show the help for this tool in the help viewer."""
        from chimerax.core.commands import run
        run(self.session,
            'open %s' % self.help if self.help is not None else "")
    
    def do_change_element(self):
        element = self.element.text()
        adjust_bonds = self.change_bonds.isChecked()
        self.settings.change_bonds = adjust_bonds
        vsepr = self.vsepr.currentText()
        
        if vsepr == "do not change":
            vsepr = False
        elif vsepr == "linear (1 bond)":
            vsepr = "linear 1"
            goal = 1
        elif vsepr == "linear (2 bonds)":
            vsepr = "linear 2"
            goal = 2
        elif vsepr == "trigonal planar (2 bonds)":
            vsepr = "bent 2 planar"
            goal = 2
        elif vsepr == "tetrahedral (2 bonds)":
            vsepr = "bent 2 tetrahedral"
            goal = 2
        elif vsepr == "trigonal planar":
            goal = 3
        elif vsepr == "tetrahedral (3 bonds)":
            vsepr = "bent 3 tetrahedral"
            goal = 3
        else:
            goal = len(Atom.get_shape(vsepr)) - 1
        
        sel = selected_atoms(self.session)
        models, _ = guessAttachmentTargets(sel, self.session, allow_adjacent=False)
        for model in models:
            conv_res = list(models[model].keys())
            for res in models[model]:
                for target in models[model][res]:
                    for neighbor in target.neighbors:
                        if neighbor.residue not in conv_res:
                            conv_res.append(neighbor.residue)
            
                    for pbg in self.session.models.list(type=PseudobondGroup):
                        for pbond in pbg.pseudobonds:
                            if target in pbond.atoms and all(atom.structure is model for atom in pbond.atoms):
                                other_atom = pbond.other_atom(target)
                                if other_atom.residue not in conv_res:
                                    conv_res.append(other_atom.residue)
            
            rescol = ResidueCollection(model, convert_residues=conv_res)
            for res in models[model]:
                residue = [resi for resi in rescol.residues if resi.chix_residue is res][0]
                
                for target in models[model][res]:
                    targ = rescol.find_exact(AtomSpec(target.atomspec))[0]
                    adjust_hydrogens = vsepr
                    if vsepr is not False:
                        cur_bonds = len(targ.connected)
                        change_Hs = goal - cur_bonds
                        adjust_hydrogens = (change_Hs, vsepr)

                    residue.change_element(targ, 
                                           element, 
                                           adjust_bonds=adjust_bonds, 
                                           adjust_hydrogens=adjust_hydrogens,
                    )
                
                residue.update_chix(res)    
    
    def do_new_ring(self):
        rings = self.ringname.text()
        
        for ring in rings.split(","):
            ring = ring.strip()
            
            rescol = ResidueCollection(Ring(ring))
        
            model = self.ring_model_selector.currentData()
            if model is None:
                chix = rescol.get_chimera(self.session)
                self.session.models.add([chix])
                apply_seqcrow_preset(chix, fallback="Ball-Stick-Endcap")
                self.ring_model_selector.setCurrentIndex(self.ring_model_selector.count()-1)
    
            else:
                res = model.new_residue("new", "a", len(model.residues)+1)
                rescol.residues[0].update_chix(res)
                run(self.session, "select add %s" % " ".join([atom.atomspec for atom in res.atoms]))
    
    def do_new_lig(self):
        ligands = self.ligname.text()
        
        for lig in ligands.split(","):
            lig = lig.strip()
            
            rescol = ResidueCollection(Component(lig))
        
            model = self.lig_model_selector.currentData()
            if model is None:
                chix = rescol.get_chimera(self.session)
                self.session.models.add([chix])
                apply_seqcrow_preset(chix, fallback="Ball-Stick-Endcap")
                self.lig_model_selector.setCurrentIndex(self.lig_model_selector.count()-1)
    
            else:
                res = model.new_residue("new", "a", len(model.residues)+1)
                rescol.residues[0].update_chix(res)
                run(self.session, "select add %s" % " ".join([atom.atomspec for atom in res.atoms]))

    def do_new_atom(self):
        element = self.element.text()
        adjust_bonds = self.change_bonds.isChecked()
        self.settings.change_bonds = adjust_bonds
        vsepr = self.vsepr.currentText()
        
        if vsepr == "do not change":
            vsepr = False
        elif vsepr == "linear (1 bond)":
            vsepr = "linear 1"
        elif vsepr == "linear (2 bonds)":
            vsepr = "linear 2"
        elif vsepr == "trigonal planar (2 bonds)":
            vsepr = "bent 2 planar"
        elif vsepr == "tetrahedral (2 bonds)":
            vsepr = "bent 2 tetrahedral"
        elif vsepr == "tetrahedral (3 bonds)":
            vsepr = "bent 3 tetrahedral"
        
        if vsepr:
            atoms = Atom.get_shape(vsepr)
            atoms[0].element = element
            for atom in atoms[1:]:
                atom.element = "H"
            if adjust_bonds:
                # this works b/c all atoms are 1 angstrom from the center
                # just multiply by the distance we want
                expected_dist = RADII[element] + RADII["H"]
                for atom in atoms[1:]:
                    atom.coords *= expected_dist
            for atom in atoms[1:]:
                atoms[0].connected.add(atom)
                atom.connected.add(atoms[0])
        else:
            atoms = [Atom(element=element, coords=np.zeros(3))]

        rescol = ResidueCollection(atoms, name="new", refresh_connected=False)

        model = self.model_selector.currentData()
        if model is None:
            chix = rescol.get_chimera(self.session)
            self.session.models.add([chix])
            apply_seqcrow_preset(chix, fallback="Ball-Stick-Endcap")
            self.model_selector.setCurrentIndex(self.model_selector.count()-1)

        else:
            res = model.new_residue("new", "a", len(model.residues)+1)
            rescol.residues[0].update_chix(res)
            run(self.session, "select add %s" % " ".join([atom.atomspec for atom in res.atoms]))
    
    def delete_atoms(self, *args):
        atoms = selected_atoms(self.session)
        for atom in atoms:
            atom.delete()
    
    def delete(self):
        self.ring_model_selector.deleteLater()
        self.lig_model_selector.deleteLater()
        self.model_selector.deleteLater()

        return super().delete()    
    
    def close(self):
        self.ring_model_selector.deleteLater()
        self.lig_model_selector.deleteLater()
        self.model_selector.deleteLater()

        return super().close()