class GroupView(QWidget, View): def __init__(self, context=None, **kwargs): super().__init__(**kwargs) self._list = QListView() self._list.setItemDelegate(PersonItemDelegate()) self._details = PersonView() self.bind("people", self._list, "model", flags=BIND_READ) self.bind("current", self._details, "context", flags=BIND_READ) layout = QGridLayout() self.setLayout(layout) layout.addWidget(self._list, 0, 0) layout.addWidget(self._details, 0, 1, 1, 1, QtCore.Qt.AlignTop) self.context = context self._list.selectionModel().selectionChanged.connect(self._on_selection_changed) def _on_selection_changed(self, new_selection, old_selection): sel = new_selection.indexes() if len(sel) != 1: return self.context.set_current(sel[0].row())
class TeamChooserWidget(QWidget): def __init__(self, parent, on_next, league=None): super().__init__(parent) self.layout = QVBoxLayout() self.list_view = QListView() self.league = league self.model = TeamListModel(league) self.list_view.setModel(self.model) self.list_view.setSelectionMode(QAbstractItemView.MultiSelection) self.list_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.list_view.customContextMenuRequested.connect(self.list_context_menu) self.layout.addWidget(self.list_view) self.team_add = AddItemWidget(self, "New Team Name: ", self.add_team, unavailable_options=self.model.all_team_names) self.layout.addWidget(self.team_add) self.button_h_layout = QHBoxLayout() self.button_cancel = QPushButton("Cancel") self.button_cancel.clicked.connect(self.on_cancel) self.button_next = QPushButton("Next") self.button_next.clicked.connect(on_next) self.button_h_layout.addWidget(self.button_cancel) self.button_h_layout.addWidget(self.button_next) self.layout.addLayout(self.button_h_layout) self.setLayout(self.layout) self.new_teams = [] def add_team(self, name): self.new_teams.append(name) team = Team.create(name=name) self.model.add_team(team) def list_context_menu(self, pos): self.listMenu = QMenu() current_index = self.list_view.currentIndex() select = self.listMenu.addAction("Select") select.triggered.connect( lambda: self.list_view.selectionModel().select(current_index, QtCore.QItemSelectionModel.Select) ) deselect = self.listMenu.addAction("Deselect") deselect.triggered.connect( lambda: self.list_view.selectionModel().select(current_index, QtCore.QItemSelectionModel.Deselect) ) delete = self.listMenu.addAction("Delete") delete.setDisabled(current_index.data() not in self.new_teams) delete.triggered.connect(lambda: self.model.delete_team(current_index.row())) parentPosition = self.list_view.mapToGlobal(QtCore.QPoint(0, 0)) self.listMenu.move(parentPosition + pos) self.listMenu.show() def on_cancel(self): self.model.delete_added_teams() self.window().close() def get_selected_teams(self): teams = [] for i in self.list_view.selectedIndexes(): teams.append(self.model.get_team(i.row())) return teams
class Browser(): def __init__(self, app): self.listViewModel = QStandardItemModel() self.app = app self.listView = QListView(app) self.listView.move(15, 145) self.listView.setFixedSize(app.width - 30, app.height - 190) self.listView.setModel(self.listViewModel) self.listView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.listView.doubleClicked.connect(self.processItem) self.listView.keyPressEvent = self.keyPressEvent self.listView.selectionModel().selectionChanged.connect( self.selectionChanged) def populate(self, entries): self.listViewModel.clear() for entry in entries: item = QStandardItem( QIcon('icons/' + ( 'file.png' if entry['type'] == 'file' else 'folder.png')), entry['name']) item.setData(entry) self.listViewModel.appendRow(item) def processItem(self): if self.item.data()['type'] == 'dir': self.app.navigateDown(self.selectedItem()) else: self.app.extract() def keyPressEvent(self, event): super(QListView, self.listView).keyPressEvent(event) if event.key() == Qt.Key_Return: self.processItem() def deselect(self): self.item = None self.app.disableFileActions() def selectedItem(self): return self.item.text() if self.item else None def selectionChanged(self, selected, deselected): if len(selected.indexes()): modelIndex = selected.indexes()[0] self.item = modelIndex.model().item(modelIndex.row()) self.app.enableFileActions() else: self.deselect()
def synchronize_selection(self, from_list: QListView, to_list: QListView): source_selection_model: QItemSelectionModel = from_list.selectionModel() destination_selection_model: QItemSelectionModel = to_list.selectionModel() rows = source_selection_model.selectedRows() if len(rows) > 0: idx = [r.row() for r in rows] min_idx, max_idx = min(idx), max(idx) top_index = QModelIndex(to_list.model().index(min_idx, 0)) bottom_index = QModelIndex(to_list.model().index(max_idx, 0)) destination_selection_model.select(QItemSelection(top_index, bottom_index), QItemSelectionModel.ClearAndSelect)
class DatabaseWidget(QSplitter): def __init__(self): super().__init__() self.setOrientation(Qt.Vertical) self.create_ui() def create_ui(self): top = QWidget() box = QVBoxLayout() top.setLayout(box) box.addWidget(label('<strong>Stored regions</strong>')) self.listview = QListView() self.listview.setModel(DatabaseModel(db)) self.listview.selectionModel().selectionChanged.connect(self.selection_changed) self.listview.doubleClicked.connect(self.list_double_clicked) self.listview.setEditTriggers(QListView.EditKeyPressed | QListView.SelectedClicked) box.addWidget(self.listview) self.addWidget(top) self.poly = PolyWidget() self.addWidget(self.poly) def unselect(self): selection_model = self.listview.selectionModel() selection_model.select(QModelIndex(), QItemSelectionModel.SelectCurrent) def select(self, row): selection_model = self.listview.selectionModel() index = self.listview.model().index(row, 0, QModelIndex()) selection_model.select(index, QItemSelectionModel.SelectCurrent) def selection_changed(self, selected, deselected): try: index = selected.indexes()[0] except IndexError: main_widget.set_selected() self.poly.show() return poly = db[index.row()] main_widget.set_selected(poly.lfid) self.poly.show(poly) def list_double_clicked(self, item): main_widget.focus(db[item.row()].lfid)
def __init_ui__(self): self.setWindowTitle(_("Manage configurations")) vbox = QVBoxLayout(self) list_view = QListView() list_view.setSelectionMode(QAbstractItemView.MultiSelection) list_view.setAlternatingRowColors(True) self.list_model = QStandardItemModel(list_view) self.populate_model() list_view.setModel(self.list_model) self.selection_model = list_view.selectionModel() self.selection_model.selectionChanged.connect( self.on_selection_changed) hbox = QHBoxLayout() hbox.addWidget(list_view) hbox.addStretch(1) vbox.addLayout(hbox) btn_box = QHBoxLayout() self.btn_delete = QPushButton(_("Delete")) self.btn_delete.setEnabled(False) self.btn_delete.clicked.connect(self.on_btn_delete_clicked) btn_box.addWidget(self.btn_delete) btn_close = QPushButton(_("Close")) btn_close.setDefault(True) btn_close.clicked.connect(self.close) btn_box.addWidget(btn_close) btn_box.addStretch(1) vbox.addLayout(btn_box) self.setLayout(vbox)
class OWPySparkScript(SparkEnvironment, widget.OWWidget): priority = 3 name = "PySpark Script" description = "Write a PySpark script and run it on input" icon = "../assets/Spark.svg" class Inputs: df = widget.Input('df', pyspark.sql.DataFrame, default=True) df1 = widget.Input('df1', pyspark.sql.DataFrame) df2 = widget.Input('df2', pyspark.sql.DataFrame) df3 = widget.Input('df3', pyspark.sql.DataFrame) transformer = widget.Input('transformer', pyspark.ml.Transformer) estimator = widget.Input('transformer', pyspark.ml.Estimator) model = widget.Input('model', pyspark.ml.Model) data = widget.Input('data', object) class Outputs: df = widget.Output('df', pyspark.sql.DataFrame, default=True) df1 = widget.Output('df1', pyspark.sql.DataFrame) df2 = widget.Output('df2', pyspark.sql.DataFrame) df3 = widget.Output('df3', pyspark.sql.DataFrame) transformer = widget.Output('transformer', pyspark.ml.Transformer) estimator = widget.Output('transformer', pyspark.ml.Estimator) model = widget.Output('model', pyspark.ml.Model) data = widget.Output('data', object) # inputs = [("in_object", object, "setObject")] # outputs = [("out_object", object, widget.Dynamic)] df = None df1 = None df2 = None df3 = None transformer = None estimator = None model = None data = None libraryListSource = Setting( [Script("Hello world", "print('Hello world')\n")]) currentScriptIndex = Setting(0) splitterState = Setting(None) auto_execute = Setting(False) _script = Setting("") @Inputs.data def set_data(self, obj): self.data = obj self.console.shell.push({'data': self.data}) @Inputs.df def set_df(self, df): self.df = df self.console.shell.push({'df': self.df}) @Inputs.df1 def set_df1(self, df): self.df1 = df self.console.shell.push({'df1': self.df1}) @Inputs.df2 def set_df2(self, df): self.df2 = df self.console.shell.push({'df2': self.df2}) @Inputs.df3 def set_df3(self, df): self.df3 = df self.console.shell.push({'df3': self.df3}) @Inputs.transformer def set_transformer(self, transformer): self.transformer = transformer self.console.shell.push({'transformer': self.transformer}) @Inputs.estimator def set_estimator(self, estimator): self.estimator = estimator self.console.shell.push({'estimator': self.estimator}) @Inputs.model def set_model(self, model): self.model = model self.console.shell.push({'model': self.model}) def __init__(self): super().__init__() self.spark_logo = " ____ __ / __/__ ___ _____/ /__ _\ \/ _ \/ _ `/ __/ '_/ /__ / .__/\_,_/_/ /_/\_\ version {version} /_/".format( version=self.sc.version) for s in self.libraryListSource: s.flags = 0 self._cachedDocuments = {} self.infoBox = gui.widgetBox(self.controlArea, 'Info') gui.label( self.infoBox, self, "<p>Execute python script.</p><p>Input variables:<ul><li> " + \ "<li>".join(t for t in dir(self.Inputs) if isinstance(getattr(self.Inputs, t), widget.Input)) + \ "</ul></p><p>Output variables:<ul><li>" + \ "<li>".join(t for t in dir(self.Outputs) if isinstance(getattr(self.Outputs, t), widget.Output)) + \ "</ul></p>" ) self.libraryList = itemmodels.PyListModel( [], self, flags=Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable) self.libraryList.wrap(self.libraryListSource) self.controlBox = gui.widgetBox(self.controlArea, 'Library') self.controlBox.layout().setSpacing(1) self.libraryView = QListView( editTriggers=QListView.DoubleClicked | QListView.EditKeyPressed, sizePolicy=QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred)) self.libraryView.setItemDelegate(ScriptItemDelegate(self)) self.libraryView.setModel(self.libraryList) self.libraryView.selectionModel().selectionChanged.connect( self.onSelectedScriptChanged) self.controlBox.layout().addWidget(self.libraryView) w = itemmodels.ModelActionsWidget() self.addNewScriptAction = action = QAction("+", self) action.setToolTip("Add a new script to the library") action.triggered.connect(self.onAddScript) w.addAction(action) action = QAction(unicodedata.lookup("MINUS SIGN"), self) action.setToolTip("Remove script from library") action.triggered.connect(self.onRemoveScript) w.addAction(action) action = QAction("Update", self) action.setToolTip("Save changes in the editor to library") action.setShortcut(QKeySequence(QKeySequence.Save)) action.triggered.connect(self.commitChangesToLibrary) w.addAction(action) action = QAction("More", self, toolTip="More actions") new_from_file = QAction("Import a script from a file", self) save_to_file = QAction("Save selected script to a file", self) save_to_file.setShortcut(QKeySequence(QKeySequence.SaveAs)) new_from_file.triggered.connect(self.onAddScriptFromFile) save_to_file.triggered.connect(self.saveScript) menu = QMenu(w) menu.addAction(new_from_file) menu.addAction(save_to_file) action.setMenu(menu) button = w.addAction(action) button.setPopupMode(QToolButton.InstantPopup) w.layout().setSpacing(1) self.controlBox.layout().addWidget(w) gui.auto_commit(self.controlArea, self, "auto_execute", "Execute") self.splitCanvas = QSplitter(Qt.Vertical, self.mainArea) self.mainArea.layout().addWidget(self.splitCanvas) self.defaultFont = defaultFont = "Monaco" if sys.platform == "darwin" else "Courier" self.textBox = gui.widgetBox(self, 'Python script') self.splitCanvas.addWidget(self.textBox) self.text = PythonScriptEditor(self) self.textBox.layout().addWidget(self.text) self.textBox.setAlignment(Qt.AlignVCenter) self.text.setTabStopWidth(4) self.text.modificationChanged[bool].connect(self.onModificationChanged) self.saveAction = action = QAction("&Save", self.text) action.setToolTip("Save script to file") action.setShortcut(QKeySequence(QKeySequence.Save)) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) action.triggered.connect(self.saveScript) self.consoleBox = gui.widgetBox(self, 'Console') self.splitCanvas.addWidget(self.consoleBox) # self.console = PySparkConsole(self.__dict__, self, sc = self.sc) self.console = EmbedIPython(sc=self.sc, hc=self.hc, sqlContext=self.sqlContext, data=self.data, df=self.df, df1=self.df1, df2=self.df2, df3=self.df3, transformer=self.transformer, estimator=self.estimator, model=self.model) # self.console.shell.run_cell('%pylab qt') self.console.shell.run_cell( 'print("{sparklogo}")'.format(sparklogo=self.spark_logo)) self.consoleBox.layout().addWidget(self.console) self.consoleBox.setAlignment(Qt.AlignBottom) select_row(self.libraryView, self.currentScriptIndex) self.splitCanvas.setSizes([2, 1]) # if self.splitterState is not None: # self.splitCanvas.restoreState(QByteArray(self.splitterState)) # # self.splitCanvas.splitterMoved[int, int].connect(self.onSpliterMoved) self.controlArea.layout().addStretch(1) self.resize(800, 600) def handleNewSignals(self): self.unconditional_commit() def selectedScriptIndex(self): rows = self.libraryView.selectionModel().selectedRows() if rows: return [i.row() for i in rows][0] else: return None def setSelectedScript(self, index): select_row(self.libraryView, index) def onAddScript(self, *args): self.libraryList.append(Script("New script", "", 0)) self.setSelectedScript(len(self.libraryList) - 1) def onAddScriptFromFile(self, *args): filename = QFileDialog.getOpenFileName( self, 'Open Python Script', os.path.expanduser("~/"), 'Python files (*.py)\nAll files(*.*)') filename = str(filename[0]) if filename: name = os.path.basename(filename) contents = open( filename, "rb", encoding="utf-8").read() #.decode("utf-8", errors = "ignore") self.libraryList.append(Script(name, contents, 0, filename)) self.setSelectedScript(len(self.libraryList) - 1) def onRemoveScript(self, *args): index = self.selectedScriptIndex() if index is not None: del self.libraryList[index] select_row(self.libraryView, max(index - 1, 0)) def onSaveScriptToFile(self, *args): index = self.selectedScriptIndex() if index is not None: self.saveScript() def onSelectedScriptChanged(self, selected, deselected): index = [i.row() for i in selected.indexes()] if index: current = index[0] if current >= len(self.libraryList): self.addNewScriptAction.trigger() return self.text.setDocument(self.documentForScript(current)) self.currentScriptIndex = current def documentForScript(self, script=0): if type(script) != Script: script = self.libraryList[script] if script not in self._cachedDocuments: doc = QtGui.QTextDocument(self) doc.setDocumentLayout(QtGui.QPlainTextDocumentLayout(doc)) doc.setPlainText(script.script) doc.setDefaultFont(QFont(self.defaultFont)) doc.highlighter = PythonSyntaxHighlighter(doc) doc.modificationChanged[bool].connect(self.onModificationChanged) doc.setModified(False) self._cachedDocuments[script] = doc return self._cachedDocuments[script] def commitChangesToLibrary(self, *args): index = self.selectedScriptIndex() if index is not None: self.libraryList[index].script = self.text.toPlainText() self.text.document().setModified(False) self.libraryList.emitDataChanged(index) def onModificationChanged(self, modified): index = self.selectedScriptIndex() if index is not None: self.libraryList[index].flags = Script.Modified if modified else 0 self.libraryList.emitDataChanged(index) def onSpliterMoved(self, pos, ind): self.splitterState = str(self.splitCanvas.saveState()) def updateSelecetdScriptState(self): index = self.selectedScriptIndex() if index is not None: script = self.libraryList[index] self.libraryList[index] = Script(script.name, self.text.toPlainText(), 0) def saveScript(self): index = self.selectedScriptIndex() if index is not None: script = self.libraryList[index] filename = script.filename else: filename = os.path.expanduser("~/") filename = QFileDialog.getSaveFileName( self, 'Save Python Script', filename, 'Python files (*.py)\nAll files(*.*)') if filename: fn = "" head, tail = filename #os.path.splitext(filename) if not tail: fn = head + ".py" else: fn = head f = open(fn, 'w', encoding='utf-8') f.write(self.text.toPlainText()) f.close() def commit(self): self._script = str(self.text.toPlainText()) inputs = [ 'data', 'df', 'df1', 'df2', 'df3', 'transformer', 'estimator', 'model' ] self.console.shell.user_ns.update( {input: getattr(self, input) for input in inputs}) self.console.execute(self._script) for input in inputs: getattr(self.Outputs, input).send(self.console.shell.user_ns[input])
class PatchPanel(QGroupBox): """Group of widget to patch an universe""" def __init__(self, parent): super(PatchPanel, self).__init__() self.ola = parent.ola self.parent = parent self.device_selected = None self.universe = None grid = QGridLayout() self.inputs_model = PortList(self, 'input_mode') self.outputs_model = PortList(self, 'output_mode') self.devices = QListView() self.devices_model = DeviceList(self) self.devices.setModel(self.devices_model) self.inputs = QListView() self.inputs.setModel(self.inputs_model) self.inputs.setMinimumHeight(400) self.inputs.setMinimumHeight(120) self.outputs = QListView() self.outputs.setModel(self.outputs_model) self.outputs.setMinimumHeight(400) self.outputs.setMinimumHeight(120) # Universe Selected Change self.devices.selectionModel().selectionChanged.connect(self.device_selection_changed) devices_label = QLabel('Devices') grid.addWidget(devices_label, 0, 0, 1, 1) grid.addWidget(self.devices, 1, 0, 21, 1) inputs_label = QLabel('Inputs') grid.addWidget(inputs_label, 0, 1, 1, 1) grid.addWidget(self.inputs, 1, 1, 10, 1) outputs_label = QLabel('Outputs') grid.addWidget(outputs_label, 11, 1, 1, 1) grid.addWidget(self.outputs, 12, 1, 10, 1) grid.setSpacing(5) self.setLayout(grid) def display_ports(self, universe=None): """ Request a list of Devices if universe == None, a list of None-Already-Patched ports is send """ if universe is None: result = self.ola.client.GetCandidatePorts(self.GetCandidatePortsCallback, None) return result result = self.ola.client.FetchDevices(self.GetDevicesCallback, 0) return result def GetCandidatePortsCallback(self, status, devices): """ Called for a new universe """ if status.Succeeded(): # clear the list of devices self.devices_model.devices = [] if debug: print('found', len(devices), 'candidate devices') for device in devices: self.devices_model.devices.append(device) self.parent.ola.devicesList.emit() self.refresh_ports() def GetDevicesCallback(self, status, devices): """ Fill-in universe menus with candidate devices/ports We need to make menus checkable to be able to patch ports """ if status.Succeeded(): # clear the list of devices self.devices_model.devices = [] for device in devices: if device.input_ports == []: # there is no input ports if device.output_ports == []: # no in + no out = no device pass else: self.devices_model.devices.append(device) else: self.devices_model.devices.append(device) if debug: print('found', len(self.devices_model.devices), 'devices') self.parent.ola.devicesList.emit() self.refresh_ports() # if there was a selection before, restore it #if self.device_selected: #self.devices.setSelection(self.device_selected) def refresh_ports(self): device = self.device_selected if device: # reset the models of inputs and outputs self.inputs_model.ports = [] self.outputs_model.ports = [] # Append input ports of this device to the inputs list model for port in device.input_ports: self.inputs_model.ports.append(port) # Append output ports of this device to the outputs list model for port in device.output_ports: self.outputs_model.ports.append(port) # please refresh Qlistview self.parent.ola.inPortsList.emit() self.parent.ola.outPortsList.emit() def device_selection_changed(self, device): # tell me which is the row selected row = device.indexes()[0].row() # tell me which device is associated with this row device = device.indexes()[0].model().object(row) self.device_selected = device # refresh ports list self.refresh_ports() if debug: print('selected device :', device.name)
class UploadDialog(QDialog): """文件上传对话框""" new_infos = pyqtSignal(object) def __init__(self): super().__init__() self.cwd = os.getcwd() self.selected = [] self.max_len = 400 self.initUI() self.set_size() self.setStyleSheet(dialog_qss_style) def set_values(self, folder_name): self.setWindowTitle("上传文件至 ➩ " + str(folder_name)) def initUI(self): self.setWindowTitle("上传文件") self.setWindowIcon(QIcon("./icon/upload.ico")) self.logo = QLabel() self.logo.setPixmap(QPixmap("./icon/logo3.gif")) self.logo.setStyleSheet("background-color:rgb(0,153,255);") self.logo.setAlignment(Qt.AlignCenter) # btn 1 self.btn_chooseDir = QPushButton("选择文件夹", self) self.btn_chooseDir.setObjectName("btn_chooseDir") self.btn_chooseDir.setObjectName("btn_chooseDir") self.btn_chooseDir.setIcon(QIcon("./icon/folder.gif")) # btn 2 self.btn_chooseMutiFile = QPushButton("选择多文件", self) self.btn_chooseDir.setObjectName("btn_chooseMutiFile") self.btn_chooseMutiFile.setObjectName("btn_chooseMutiFile") self.btn_chooseMutiFile.setIcon(QIcon("./icon/file.ico")) # btn 3 self.btn_deleteSelect = QPushButton("删除", self) self.btn_deleteSelect.setObjectName("btn_deleteSelect") self.btn_deleteSelect.setIcon(QIcon("./icon/delete.ico")) # 列表 self.list_view = QListView(self) self.list_view.setViewMode(QListView.ListMode) self.slm = QStandardItem() self.model = QStandardItemModel() self.list_view.setModel(self.model) self.model.removeRows(0, self.model.rowCount()) # 清除旧的选择 self.list_view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.list_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.list_view.setSelectionMode(QAbstractItemView.ExtendedSelection) self.buttonBox = QDialogButtonBox() self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) grid = QGridLayout() grid.setSpacing(10) grid.addWidget(self.logo, 1, 0, 1, 3) grid.addWidget(self.btn_chooseDir, 2, 0) grid.addWidget(self.btn_chooseMutiFile, 2, 2) grid.addWidget(self.list_view, 3, 0, 2, 3) grid.addWidget(self.btn_deleteSelect, 5, 0) grid.addWidget(self.buttonBox, 5, 1, 1, 2) self.setLayout(grid) self.setMinimumWidth(350) # 设置信号 self.btn_chooseDir.clicked.connect(self.slot_btn_chooseDir) self.btn_chooseMutiFile.clicked.connect(self.slot_btn_chooseMutiFile) self.btn_deleteSelect.clicked.connect(self.slot_btn_deleteSelect) self.buttonBox.accepted.connect(self.slot_btn_ok) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.clear_old) self.buttonBox.rejected.connect(self.reject) def set_size(self): rows = self.model.rowCount() for i in range(rows): m_len = int(len(self.model.item(i, 0).text()) * 4) if m_len > self.max_len: self.max_len = m_len rows = 10 if rows >= 10 else rows # 限制最大高度 self.resize(self.max_len, 250 + rows * 28) def clear_old(self): self.selected = [] self.model.removeRows(0, self.model.rowCount()) self.set_size() def slot_btn_ok(self): if self.selected: self.new_infos.emit(self.selected) self.clear_old() def slot_btn_deleteSelect(self): _indexes = self.list_view.selectionModel().selection().indexes() if not _indexes: return indexes = [] for i in _indexes: # 获取所选行号 indexes.append(i.row()) indexes = set(indexes) for i in sorted(indexes, reverse=True): self.selected.remove(self.model.item(i, 0).text()) self.model.removeRow(i) self.set_size() def slot_btn_chooseDir(self): dir_choose = QFileDialog.getExistingDirectory(self, "选择文件夹", self.cwd) # 起始路径 if dir_choose == "": return if dir_choose not in self.selected: self.selected.append(dir_choose) self.model.appendRow( QStandardItem(QIcon("./icon/folder.gif"), dir_choose)) self.set_size() def slot_btn_chooseMutiFile(self): files, _ = QFileDialog.getOpenFileNames(self, "选择多文件", self.cwd, "All Files (*)") if len(files) == 0: return for _file in files: if _file not in self.selected: self.selected.append(_file) self.model.appendRow( QStandardItem(QIcon("./icon/file.ico"), _file)) self.set_size()
class MDIHistory(QWidget, _HalWidgetBase): def __init__(self, parent=None): super(MDIHistory, self).__init__(parent) self.setMinimumSize(QSize(200, 150)) self.setWindowTitle("PyQt5 editor test example") lay = QVBoxLayout() lay.setContentsMargins(0, 0, 0, 0) self.setLayout(lay) self.list = QListView() self.list.setEditTriggers(QListView.NoEditTriggers) self.list.activated.connect(self.activated) self.list.setAlternatingRowColors(True) self.list.selectionChanged = self.selectionChanged self.model = QStandardItemModel(self.list) self.MDILine = MDILine() self.MDILine.soft_keyboard = False self.MDILine.line_up = self.line_up self.MDILine.line_down = self.line_down STATUS.connect('mdi-history-changed', self.reload) # add widgets lay.addWidget(self.list) lay.addWidget(self.MDILine) self.fp = os.path.expanduser(INFO.MDI_HISTORY_PATH) try: open(self.fp, 'r') except: open(self.fp, 'a+') LOG.debug('MDI History file created: {}'.format(self.fp)) self.reload() self.select_row('last') def _hal_init(self): STATUS.connect('state-off', lambda w: self.setEnabled(False)) STATUS.connect('state-estop', lambda w: self.setEnabled(False)) STATUS.connect( 'interp-idle', lambda w: self.setEnabled(STATUS.machine_is_on( ) and (STATUS.is_all_homed() or INFO.NO_HOME_REQUIRED))) STATUS.connect('interp-run', lambda w: self.setEnabled(not STATUS.is_auto_mode())) STATUS.connect('all-homed', lambda w: self.setEnabled(STATUS.machine_is_on())) def reload(self, w=None): self.model.clear() try: with open(self.fp, 'r') as inputfile: for line in inputfile: line = line.rstrip('\n') item = QStandardItem(line) self.model.appendRow(item) self.list.setModel(self.model) self.list.scrollToBottom() if self.MDILine.hasFocus(): self.select_row('last') except: LOG.debug('File path is not valid: {}'.format(fp)) def selectionChanged(self, old, new): cmd = self.getSelected() self.MDILine.setText(cmd) selectionModel = self.list.selectionModel() if selectionModel.hasSelection(): self.row = selectionModel.currentIndex().row() def getSelected(self): selected_indexes = self.list.selectedIndexes() selected_rows = [item.row() for item in selected_indexes] # iterates each selected row in descending order for selected_row in sorted(selected_rows, reverse=True): text = self.model.item(selected_row).text() return text def activated(self): cmd = self.getSelected() self.MDILine.setText(cmd) self.MDILine.submit() self.select_row('down') def run_command(self): self.MDILine.submit() self.select_row('last') def select_row(self, style): style = style.lower() selectionModel = self.list.selectionModel() parent = QModelIndex() self.rows = self.model.rowCount(parent) - 1 if style == 'last': self.row = self.rows print 'last =', self.row elif style == 'up': if self.row > 0: self.row -= 1 else: self.row = 0 elif style == 'down': if self.row < self.rows: self.row += 1 else: self.row = self.rows else: return top = self.model.index(self.row, 0, parent) bottom = self.model.index(self.row, 0, parent) selectionModel.setCurrentIndex( top, QItemSelectionModel.Select | QItemSelectionModel.Rows) selection = QItemSelection(top, top) selectionModel.clearSelection() selectionModel.select(selection, QItemSelectionModel.Select) def line_up(self): self.select_row('up') def line_down(self): self.select_row('down') ######################################################################### # This is how designer can interact with our widget properties. # designer will show the pyqtProperty properties in the editor # it will use the get set and reset calls to do those actions ######################################################################### def set_soft_keyboard(self, data): self.MDILine.soft_keyboard = data def get_soft_keyboard(self): return self.MDILine.soft_keyboard def reset_soft_keyboard(self): self.MDILine.soft_keyboard = False # designer will show these properties in this order: soft_keyboard_option = pyqtProperty(bool, get_soft_keyboard, set_soft_keyboard, reset_soft_keyboard)
class ErrorVisualizeWidget(QWidget): def __init__(self, parent, mainwindow): super().__init__(parent) self.__widget_mainwindow = mainwindow self.__widget_matplotlib = ErrorVisualizeMatplotlibWidget(self) self.__current_layer = 0 self.__widget_label_wrong_dimension = QLabel("", parent=self) self.__widget_label_layer = QLabel("<b>Layer</b>: ", parent=self) self.__widget_list_layer = QListView(self) self.__widget_list_layer.setModel(QStandardItemModel()) self.__widget_list_layer.clicked.connect(self.set_layer) self.__widget_list_layer.selectionModel().selectionChanged.connect(self.set_layer) if not SDB_HAS_MATPLOTLIB: self.__widget_label_layer.setEnabled(False) self.__widget_list_layer.setEnabled(False) hbox_top = QHBoxLayout() hbox_top.addWidget(self.__widget_matplotlib) vbox_top = QVBoxLayout() vbox_top.addWidget(self.__widget_label_layer) vbox_top.addWidget(self.__widget_list_layer) hbox_top.addLayout(vbox_top) hbox_bottom = QHBoxLayout() hbox_bottom.addWidget(self.__widget_label_wrong_dimension) hbox_bottom.addStretch(1) vbox = QVBoxLayout() vbox.addLayout(hbox_top) vbox.addLayout(hbox_bottom) self.setLayout(vbox) def make_update(self, comparison_result): Logger.info("Updating ErrorVisualizeWidget") if not SDB_HAS_MATPLOTLIB: return self.__error_positions = comparison_result.get_error_positions() if self.__error_positions.ndim in (2, 3): self.__current_layer = 0 self.__widget_matplotlib.draw_layer(self.__error_positions, self.__current_layer) self.__widget_list_layer.model().clear() if self.__error_positions.ndim == 3: self.__widget_label_layer.setEnabled(True) self.__widget_list_layer.setEnabled(True) for k in range(self.__error_positions.shape[2]): item = QStandardItem(" %i" % k) if any(self.__error_positions[:, :, k]): item.setIcon(Icon("failure-small.png")) else: item.setIcon(Icon("success.png")) item.setEditable(False) self.__widget_list_layer.model().insertRow(k, item) else: self.__widget_label_layer.setEnabled(False) self.__widget_list_layer.setEnabled(False) self.__widget_label_wrong_dimension.setText("") else: self.__widget_matplotlib.draw_nothing() self.__widget_label_layer.setEnabled(False) self.__widget_list_layer.model().clear() self.__widget_list_layer.setEnabled(False) self.__widget_label_wrong_dimension.setText( "Visualization is only supported for 2 and 3-dimensional fields.") def set_layer(self, layer): if isinstance(layer, QItemSelection): layer = layer.indexes()[0] layer_idx = layer.row() self.__current_layer = layer_idx self.__widget_matplotlib.draw_layer(self.__error_positions, self.__current_layer)
class PatchPanel(QGroupBox): """Group of widget to patch an universe""" def __init__(self, parent): super(PatchPanel, self).__init__() self.ola = parent.ola self.parent = parent self.device_selected = None self.universe = None grid = QGridLayout() self.inputs_model = PortList(self, 'input_mode') self.outputs_model = PortList(self, 'output_mode') self.devices = QListView() self.devices_model = DeviceList(self) self.devices.setModel(self.devices_model) self.inputs = QListView() self.inputs.setModel(self.inputs_model) self.inputs.setMinimumHeight(400) self.inputs.setMinimumHeight(120) self.outputs = QListView() self.outputs.setModel(self.outputs_model) self.outputs.setMinimumHeight(400) self.outputs.setMinimumHeight(120) # Universe Selected Change self.devices.selectionModel().selectionChanged.connect( self.device_selection_changed) devices_label = QLabel('Devices') grid.addWidget(devices_label, 0, 0, 1, 1) grid.addWidget(self.devices, 1, 0, 21, 1) inputs_label = QLabel('Inputs') grid.addWidget(inputs_label, 0, 1, 1, 1) grid.addWidget(self.inputs, 1, 1, 10, 1) outputs_label = QLabel('Outputs') grid.addWidget(outputs_label, 11, 1, 1, 1) grid.addWidget(self.outputs, 12, 1, 10, 1) grid.setSpacing(5) self.setLayout(grid) def display_ports(self, universe=None): """ Request a list of Devices if universe == None, a list of None-Already-Patched ports is send """ if universe is None: result = self.ola.client.GetCandidatePorts( self.GetCandidatePortsCallback, None) return result result = self.ola.client.FetchDevices(self.GetDevicesCallback, 0) return result def GetCandidatePortsCallback(self, status, devices): """ Called for a new universe """ if status.Succeeded(): # clear the list of devices self.devices_model.devices = [] if debug: print('found', len(devices), 'candidate devices') for device in devices: self.devices_model.devices.append(device) self.parent.ola.devicesList.emit() self.refresh_ports() def GetDevicesCallback(self, status, devices): """ Fill-in universe menus with candidate devices/ports We need to make menus checkable to be able to patch ports """ if status.Succeeded(): # clear the list of devices self.devices_model.devices = [] for device in devices: if device.input_ports == []: # there is no input ports if device.output_ports == []: # no in + no out = no device pass else: self.devices_model.devices.append(device) else: self.devices_model.devices.append(device) if debug: print('found', len(self.devices_model.devices), 'devices') self.parent.ola.devicesList.emit() self.refresh_ports() # if there was a selection before, restore it #if self.device_selected: #self.devices.setSelection(self.device_selected) def refresh_ports(self): device = self.device_selected if device: # reset the models of inputs and outputs self.inputs_model.ports = [] self.outputs_model.ports = [] # Append input ports of this device to the inputs list model for port in device.input_ports: self.inputs_model.ports.append(port) # Append output ports of this device to the outputs list model for port in device.output_ports: self.outputs_model.ports.append(port) # please refresh Qlistview self.parent.ola.inPortsList.emit() self.parent.ola.outPortsList.emit() def device_selection_changed(self, device): # tell me which is the row selected row = device.indexes()[0].row() # tell me which device is associated with this row device = device.indexes()[0].model().object(row) self.device_selected = device # refresh ports list self.refresh_ports() if debug: print('selected device :', device.name)
class MDIHistory(QWidget, _HalWidgetBase): def __init__(self, parent=None): super(MDIHistory, self).__init__(parent) self.setMinimumSize(QSize(200, 150)) self.setWindowTitle("PyQt5 editor test example") lay = QVBoxLayout() lay.setContentsMargins(0,0,0,0) self.setLayout(lay) self.list = QListView() self.list.setEditTriggers(QListView.NoEditTriggers) self.list.activated.connect(self.activated) self.list.setAlternatingRowColors(True) self.list.selectionChanged = self.selectionChanged self.model = QStandardItemModel(self.list) self.MDILine = MDILine() self.MDILine.soft_keyboard = False self.MDILine.line_up = self.line_up self.MDILine.line_down = self.line_down STATUS.connect('reload-mdi-history', self.reload) # add widgets lay.addWidget(self.list) lay.addWidget(self.MDILine) self.fp = os.path.expanduser(INFO.MDI_HISTORY_PATH) try: open(self.fp, 'r') except: open(self.fp, 'a+') LOG.debug('MDI History file created: {}'.format(self.fp)) self.reload() self.select_row('last') def _hal_init(self): STATUS.connect('state-off', lambda w: self.setEnabled(False)) STATUS.connect('state-estop', lambda w: self.setEnabled(False)) STATUS.connect('interp-idle', lambda w: self.setEnabled(STATUS.machine_is_on() and (STATUS.is_all_homed() or INFO.NO_HOME_REQUIRED))) STATUS.connect('interp-run', lambda w: self.setEnabled(not STATUS.is_auto_mode())) STATUS.connect('all-homed', lambda w: self.setEnabled(STATUS.machine_is_on())) def reload(self, w=None ): self.model.clear() try: with open(self.fp,'r') as inputfile: for line in inputfile: line = line.rstrip('\n') item = QStandardItem(line) self.model.appendRow(item) self.list.setModel(self.model) self.list.scrollToBottom() if self.MDILine.hasFocus(): self.select_row('last') except: LOG.debug('File path is not valid: {}'.format(fp)) def selectionChanged(self,old, new): cmd = self.getSelected() self.MDILine.setText(cmd) selectionModel = self.list.selectionModel() if selectionModel.hasSelection(): self.row = selectionModel.currentIndex().row() def getSelected(self): selected_indexes = self.list.selectedIndexes() selected_rows = [item.row() for item in selected_indexes] # iterates each selected row in descending order for selected_row in sorted(selected_rows, reverse=True): text = self.model.item(selected_row).text() return text def activated(self): cmd = self.getSelected() self.MDILine.setText(cmd) self.MDILine.submit() self.select_row('down') def select_row(self, style): selectionModel = self.list.selectionModel() parent = QModelIndex() self.rows = self.model.rowCount(parent) - 1 if style == 'last': self.row = self.rows elif style == 'up': if self.row > 0: self.row -= 1 else: self.row = self.rows elif style == 'down': if self.row < self.rows: self.row += 1 else: self.row = 0 else: return top = self.model.index(self.row, 0, parent) bottom = self.model.index(self.row, 0, parent) selectionModel.setCurrentIndex(top, QItemSelectionModel.Select | QItemSelectionModel.Rows) selection = QItemSelection(top, top) selectionModel.clearSelection() selectionModel.select(selection, QItemSelectionModel.Select) def line_up(self): self.select_row('up') def line_down(self): self.select_row('down') ######################################################################### # This is how designer can interact with our widget properties. # designer will show the pyqtProperty properties in the editor # it will use the get set and reset calls to do those actions ######################################################################### def set_soft_keyboard(self, data): self.MDILine.soft_keyboard = data def get_soft_keyboard(self): return self.MDILine.soft_keyboard def reset_soft_keyboard(self): self.MDILine.soft_keyboard = False # designer will show these properties in this order: soft_keyboard_option = pyqtProperty(bool, get_soft_keyboard, set_soft_keyboard, reset_soft_keyboard)
class LabelSelectionWidget(QWidget): """ A widget for selection of label values. The widget displays the contents of the model with two widgets: * The top level model items are displayed in a combo box. * The children of the current selected top level item are displayed in a subordinate list view. .. note:: This is not a QAbstractItemView subclass. """ #: Current group/root index has changed. groupChanged = Signal(int) #: Selection for the current group/root has changed. groupSelectionChanged = Signal() def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.__model = None self.__selectionMode = QListView.ExtendedSelection self.__currentIndex = -1 self.__selections = {} layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) def group_box(title): box = QGroupBox(title) box.setFlat(True) lay = QVBoxLayout() lay.setContentsMargins(0, 0, 0, 0) box.setLayout(lay) return box self.labels_combo = QComboBox() self.values_view = QListView(selectionMode=self.__selectionMode) self.labels_combo.currentIndexChanged.connect( self.__onCurrentIndexChanged) l_box = group_box(self.tr("Label")) v_box = group_box(self.tr("Values")) l_box.layout().addWidget(self.labels_combo) v_box.layout().addWidget(self.values_view) layout.addWidget(l_box) layout.addWidget(v_box) self.setLayout(layout) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) def clear(self): """ Clear the widget/model (same as ``setModel(None)``). """ if self.__model is not None: self.values_view.selectionModel().clearSelection() self.values_view.selectionModel().selectionChanged.disconnect( self.__onSelectionChanged) self.values_view.setModel(None) self.labels_combo.setModel(QStandardItemModel(self.labels_combo)) self.__currentIndex = -1 self.__selections = {} self.__model = None def setModel(self, model): """ Set the source model for display. The model should be a tree model with depth 2. Parameters ---------- model : QtCore.QAbstractItemModel """ if model is self.__model: return self.clear() if model is None: return self.__model = model self.values_view.setModel(model) self.values_view.setRootIndex(model.index(0, 0)) self.values_view.selectionModel().selectionChanged.connect( self.__onSelectionChanged) # will emit the currentIndexChanged (if the model is not empty) self.labels_combo.setModel(model) def model(self): """ Return the current model. Returns ------- model : QtCore.QAbstractItemModel """ return self.__model def setCurrentGroupIndex(self, index): """ Set the current selected group/root index row. Parameters ---------- index : int Group index. """ self.labels_combo.setCurrentIndex(index) def currentGroupIndex(self): """ Return the current selected group/root index row. Returns ------- row : index Current group row index (-1 if there is no current index) """ return self.labels_combo.currentIndex() def setSelection(self, selection): """ Set the model item selection. Parameters ---------- selection : QtCore.QItemSelection Item selection. """ if self.values_view.selectionModel() is not None: indices = selection.indexes() pind = defaultdict(list) for index in indices: parent = index.parent() if parent.isValid(): if parent == self.__model.index(parent.row(), parent.column()): pind[parent.row()].append(QPersistentModelIndex(index)) else: warnings.warn("Die Die Die") else: # top level index pass self.__selections = pind self.__restoreSelection() def selection(self): """ Return the item selection. Returns ------- selection : QtCore.QItemSelection """ selection = QItemSelection() if self.__model is None: return selection for pind in chain(*self.__selections.values()): ind = self.__model.index(pind.row(), pind.column(), pind.parent()) if ind.isValid(): selection.select(ind, ind) return selection def currentGroupSelection(self): """ Return the item selection for the current group only. """ if self.values_view.selectionModel() is not None: return self.values_view.selectionModel().selection() else: return QItemSelection() def __onCurrentIndexChanged(self, index): self.__storeSelection(self.__currentIndex, self.values_view.selectedIndexes()) self.__currentIndex = index if self.__model is not None: root = self.__model.index(index, 0) self.values_view.setRootIndex(root) self.__restoreSelection() self.groupChanged.emit(index) def __onSelectionChanged(self, old, new): self.__storeSelection(self.__currentIndex, self.values_view.selectedIndexes()) self.groupSelectionChanged.emit() def __storeSelection(self, groupind, indices): # Store current values selection for the current group groupind = self.__currentIndex indices = [ QPersistentModelIndex(ind) for ind in self.values_view.selectedIndexes() ] self.__selections[groupind] = indices def __restoreSelection(self): # Restore previous selection for root (if available) assert self.__model is not None groupind = self.__currentIndex root = self.__model.index(groupind, 0) sel = self.__selections.get(groupind, []) indices = [ self.__model.index(pind.row(), pind.column(), root) for pind in sel if pind.isValid() and pind.parent() == root ] selection = QItemSelection() for ind in indices: selection.select(ind, ind) self.values_view.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) def sizeHint(self): """Reimplemented from QWidget.sizeHint""" return QSize(100, 200)
class DictView(QWidget): BTN_ADDWORD_TEXT = 'Add' BTN_RMWORD_TEXT = 'Remove' def __init__(self, parent: QObject = None, model: WordListModel = None, **kwargs): super().__init__(parent, **kwargs) self.lhb_control = QHBoxLayout() self.layout = QVBoxLayout() self.b_addword = QPushButton(self.BTN_ADDWORD_TEXT) self.b_rmword = QPushButton(self.BTN_RMWORD_TEXT) self.cmb_wordclass = QComboBox() for wc in WordClass: self.cmb_wordclass.addItem(wc.name) self.hsplitter = QSplitter(Qt.Horizontal) self.wordlistview = QListView() self.wordeditview = WordEditView() self.wordlsmdl = model self.wordlistview.activated.connect(self.wordeditview.handle_wordlistitem_activated) self.hsplitter.addWidget(self.wordlistview) self.hsplitter.addWidget(self.wordeditview) self.hsplitter.setSizes([PyDictAppView.DESKTOP_DEFAULT_WIDTH * 0.4, PyDictAppView.DESKTOP_DEFAULT_WIDTH * 0.6]) self.lhb_control.addWidget(self.cmb_wordclass) self.lhb_control.addWidget(self.b_addword) self.lhb_control.addWidget(self.b_rmword) self.lhb_control.addStretch() self.layout.addLayout(self.lhb_control) self.layout.addWidget(self.hsplitter) self.setLayout(self.layout) self.b_addword.clicked.connect(self.handle_b_addword_clicked) self.b_rmword.clicked.connect(self.handle_b_rmword_clicked) @property def wordlsmdl(self) -> WordListModel: return self.wordlistview.model() @wordlsmdl.setter def wordlsmdl(self, value: WordListModel) -> None: assert (value is None) or isinstance(value, WordListModel), 'The wordlsmdl property of {} class shall have {} type.'\ .format(self.__class__.__name__, WordListModel.__name__) self.wordlistview.setModel(value) self.wordeditview.wordlsmdl = value def handle_b_addword_clicked(self) -> None: wc = self.parse_wordclass() word_dialog = WordDialog(wc, self.wordlsmdl, self) word_dialog.show() word_dialog.exec() def handle_b_rmword_clicked(self) -> None: self.wordeditview.activate_wordview(None) sel_indexes = self.wordlistview.selectionModel().selectedIndexes() if sel_indexes is not None: for index in sel_indexes: guid = self.wordlsmdl.get_guid(index) event_wordremreq = EventWordRemoveRequest(guid) event_wordremreq.fire() def parse_wordclass(self) -> WordClass: wordclass_text = self.cmb_wordclass.currentText() if WordClass.__members__.get(wordclass_text) is None: return WordClass.NOUN else: return WordClass[wordclass_text]
class SelectColumnDialog(QDialog): """ Dialog for selecting a single column from the current dataframe """ def __init__(self, columns=None, selected=None, parent=None): super(SelectColumnDialog, self).__init__(parent) self.setWindowTitle("Select Column") self.columns = columns self.selected = selected # Name of selected variable, or None. # Available self.varlist_model = QStandardItemModel(self) # Proxy model for filtering/sorting self.proxy = QSortFilterProxyModel(self) self.proxy.setSourceModel(self.varlist_model) self.proxy.setFilterKeyColumn(0) # Filters based on the only column self.proxy.setFilterCaseSensitivity( Qt.CaseInsensitive ) # Case insensitive search # Setup Layout layout = QVBoxLayout(self) # Left Side Group Box ("Available") varlist_box = QGroupBox("Available Variables") varlist_box_layout = QVBoxLayout() # Multiselect listing available columns self.varlist = QListView(self) self.varlist.setModel(self.proxy) self.varlist.setSelectionMode(QAbstractItemView.SingleSelection) self.varlist.selectionModel().selectionChanged.connect(self.selected_change) self.varlist.setEditTriggers(QAbstractItemView.NoEditTriggers) varlist_box_layout.addWidget(self.varlist) # Add a search box self.varlist_search = QLineEdit(parent=self) self.varlist_search.setPlaceholderText("Search...") self.varlist_search.textChanged.connect(self.proxy.setFilterFixedString) varlist_box_layout.addWidget(self.varlist_search) # Set layout and add to the main layout varlist_box.setLayout(varlist_box_layout) layout.addWidget(varlist_box) # Ok/Cancel QBtn = QDialogButtonBox.Ok | QDialogButtonBox.Cancel self.buttonBox = QDialogButtonBox(QBtn) self.buttonBox.accepted.connect(self.submit) self.buttonBox.rejected.connect(self.reject) layout.addWidget(self.buttonBox) # Reset to update self.reset_list() def selected_change(self): """ Update the current selection. Disable "Ok" if nothing is selected. """ selection_indexes = self.varlist.selectedIndexes() if len(selection_indexes) == 0: self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) else: self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True) selected_index = selection_indexes[0] self.selected = self.proxy.itemData(selected_index)[0] def reset_list(self): """Clear the search field and show the full list""" self.varlist_search.setText("") self.varlist_model.clear() for idx, v in enumerate(self.columns): self.varlist_model.appendRow(QStandardItem(v)) if v == self.selected: selection_index = self.varlist_model.index(idx, 0) mode = ( QtCore.QItemSelectionModel.Select | QtCore.QItemSelectionModel.Rows ) self.varlist.selectionModel().select(selection_index, mode) def submit(self): # TODO: Add any warnings here self.selected = self.selected self.accept() @staticmethod def get_column(columns=None, selected=None, parent=None): if columns is None: return "No columns", None, None # Launch dialog to select a column dlg = SelectColumnDialog(columns, selected, parent) result = dlg.exec_() if result: # Update the selected value if the dialog accepted selected = dlg.selected return selected
def add_action(self, action): self.actions.append(action) def list_view_current_changed(): index = list_view.selectionModel().currentIndex() action = list_view.model().data(index, QtCore.Qt.UserRole) action.print_data() action = index.internalPointer() print(str(action)) if __name__ == "__main__": app = QApplication(sys.argv) list_view = QListView() actions_model = ActionsModel() actions_model.add_action(RandomList("l1")) actions_model.add_action(RandomList("l2")) actions_model.add_action(RandomList("l3")) list_view.setModel(actions_model) list_view.selectionModel().currentChanged.connect(list_view_current_changed) list_view.show() app.exec_()
class FileManager(QWidget, _HalWidgetBase): def __init__(self, parent=None): super(FileManager, self).__init__(parent) self.title = 'Qtvcp File System View' self.left = 10 self.top = 10 self.width = 640 self.height = 480 self.media_path = (os.path.join(os.path.expanduser('~'), 'linuxcnc/nc_files')) user = os.path.split(os.path.expanduser('~'))[-1] self.user_path = (os.path.join('/media', user)) self.currentPath = None self.currentFolder = None self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) pasteBox = QHBoxLayout() self.textLine = QLineEdit() self.textLine.setToolTip('Current Director/selected File') self.pasteButton = QToolButton() self.pasteButton.setEnabled(False) self.pasteButton.setText('Paste') self.pasteButton.setToolTip( 'Copy file from copy path to current directory/file') self.pasteButton.clicked.connect(self.paste) self.pasteButton.hide() pasteBox.addWidget(self.textLine) pasteBox.addWidget(self.pasteButton) self.copyBox = QFrame() hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) self.copyLine = QLineEdit() self.copyLine.setToolTip('File path to copy from, when pasting') self.copyButton = QToolButton() self.copyButton.setText('Copy') self.copyButton.setToolTip('Record current file as copy path') self.copyButton.clicked.connect(self.recordCopyPath) hbox.addWidget(self.copyButton) hbox.addWidget(self.copyLine) self.copyBox.setLayout(hbox) self.copyBox.hide() self.model = QFileSystemModel() self.model.setRootPath(QDir.currentPath()) self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files) self.model.setNameFilterDisables(False) self.model.rootPathChanged.connect(self.folderChanged) self.list = QListView() self.list.setModel(self.model) self.updateDirectoryView(self.media_path) self.list.resize(640, 480) self.list.clicked[QModelIndex].connect(self.listClicked) self.list.activated.connect(self._getPathActivated) self.list.setAlternatingRowColors(True) self.cb = QComboBox() self.cb.currentIndexChanged.connect(self.filterChanged) self.fillCombobox(INFO.PROGRAM_FILTERS_EXTENSIONS) self.cb.setMinimumHeight(30) self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button2 = QToolButton() self.button2.setText('Media') self.button2.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button2.setMinimumSize(60, 30) self.button2.setToolTip('Jump to Media directory') self.button2.clicked.connect(self.onJumpClicked) SettingMenu = QMenu(self) self.settingMenu = SettingMenu for i in ('Media', 'User'): axisButton = QAction(QIcon.fromTheme('user-home'), i, self) # weird lambda i=i to work around 'function closure' axisButton.triggered.connect( lambda state, i=i: self.jumpTriggered(i)) SettingMenu.addAction(axisButton) self.button2.setMenu(SettingMenu) self.button3 = QToolButton() self.button3.setText('Add Jump') self.button3.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button3.setMinimumSize(60, 30) self.button3.setToolTip('Add current directory to jump button list') self.button3.clicked.connect(self.onActionClicked) hbox = QHBoxLayout() hbox.addWidget(self.button2) hbox.addWidget(self.button3) hbox.insertStretch(2, stretch=0) hbox.addWidget(self.cb) windowLayout = QVBoxLayout() windowLayout.addLayout(pasteBox) windowLayout.addWidget(self.copyBox) windowLayout.addWidget(self.list) windowLayout.addLayout(hbox) self.setLayout(windowLayout) self.show() def _hal_init(self): if self.PREFS_: last_path = self.PREFS_.getpref('last_loaded_directory', self.media_path, str, 'BOOK_KEEPING') self.updateDirectoryView(last_path) LOG.debug("lAST FILE PATH: {}".format(last_path)) else: LOG.debug("lAST FILE PATH: {}".format(self.media_path)) self.updateDirectoryView(self.media_path) ######################### # callbacks ######################### # add shown text and hidden filter data from the INI def fillCombobox(self, data): for i in data: self.cb.addItem(i[0], i[1]) def folderChanged(self, data): self.currentFolder = data self.textLine.setText(data) def updateDirectoryView(self, path): self.list.setRootIndex(self.model.setRootPath(path)) # retrieve selected filter (it's held as QT.userData) def filterChanged(self, index): userdata = self.cb.itemData(index) self.model.setNameFilters(userdata) def listClicked(self, index): # the signal passes the index of the clicked item dir_path = self.model.filePath(index) if self.model.fileInfo(index).isFile(): self.currentPath = dir_path self.textLine.setText(self.currentPath) return root_index = self.model.setRootPath(dir_path) self.list.setRootIndex(root_index) def onUserClicked(self): self.showUserDir() def onMediaClicked(self): self.showMediaDir() def onJumpClicked(self): data = self.button2.text() if data == 'Media': self.showMediaDir() elif data == 'User': self.showUserDir() else: self.updateDirectoryView(self.button2.text()) def jumpTriggered(self, data): if data == 'Media': self.button2.setText('{}'.format(data)) self.button2.setToolTip('Jump to Media directory') self.showMediaDir() elif data == 'User': self.button2.setText('{}'.format(data)) self.button2.setToolTip('Jump to User directory') self.showUserDir() else: self.button2.setText('{}'.format(data)) self.button2.setToolTip('Jump to directory: {}'.format(data)) self.updateDirectoryView(self.button2.text()) def onActionClicked(self): i = self.currentFolder button = QAction(QIcon.fromTheme('user-home'), i, self) # weird lambda i=i to work around 'function closure' button.triggered.connect(lambda state, i=i: self.jumpTriggered(i)) self.settingMenu.addAction(button) # get current selection and update the path # then if the path is good load it into linuxcnc # record it in the preference file if available def _getPathActivated(self): row = self.list.selectionModel().currentIndex() self.listClicked(row) fname = self.currentPath if fname is None: return if fname: self.load(fname) def recordCopyPath(self): data, isFile = self.getCurrentSelected() if isFile: self.copyLine.setText(os.path.normpath(data)) self.pasteButton.setEnabled(True) else: self.copyLine.setText('') self.pasteButton.setEnabled(False) STATUS.emit('error', OPERATOR_ERROR, 'Can only copy a file, not a folder') def paste(self): res = self.copyFile(self.copyLine.text(), self.textLine.text()) if res: self.copyLine.setText('') self.pasteButton.setEnabled(False) ######################## # helper functions ######################## def showCopyControls(self, state): if state: self.copyBox.show() self.pasteButton.show() else: self.copyBox.hide() self.pasteButton.hide() def showMediaDir(self): self.updateDirectoryView(self.user_path) def showUserDir(self): self.updateDirectoryView(self.media_path) def copyFile(self, s, d): try: shutil.copy(s, d) return True except Exception as e: LOG.error("Copy file error: {}".format(e)) STATUS.emit('error', OPERATOR_ERROR, "Copy file error: {}".format(e)) return False # moves the selection up # used with MPG scrolling def up(self): self.select_row('up') # moves the selection down # used with MPG scrolling def down(self): self.select_row('down') def select_row(self, style='down'): style = style.lower() selectionModel = self.list.selectionModel() row = selectionModel.currentIndex().row() self.rows = self.model.rowCount(self.list.rootIndex()) if style == 'last': row = self.rows elif style == 'up': if row > 0: row -= 1 else: row = 0 elif style == 'down': if row < self.rows: row += 1 else: row = self.rows else: return top = self.model.index(row, 0, self.list.rootIndex()) selectionModel.setCurrentIndex( top, QItemSelectionModel.Select | QItemSelectionModel.Rows) selection = QItemSelection(top, top) selectionModel.clearSelection() selectionModel.select(selection, QItemSelectionModel.Select) # returns the current highlighted (selected) path as well as # whether it's a file or not. def getCurrentSelected(self): selectionModel = self.list.selectionModel() index = selectionModel.currentIndex() dir_path = self.model.filePath(index) if self.model.fileInfo(index).isFile(): return (dir_path, True) else: return (dir_path, False) # This can be class patched to do something else def load(self, fname=None): if fname is None: self._getPathActivated() return self.recordBookKeeping() ACTION.OPEN_PROGRAM(fname) STATUS.emit('update-machine-log', 'Loaded: ' + fname, 'TIME') # This can be class patched to do something else def recordBookKeeping(self): fname = self.currentPath if fname is None: return if self.PREFS_: self.PREFS_.putpref('last_loaded_directory', self.model.rootPath(), str, 'BOOK_KEEPING') self.PREFS_.putpref('RecentPath_0', fname, str, 'BOOK_KEEPING')
class HardwareSelector(QDialog): def __init__(self, host, port, parent=None): QDialog.__init__(self, parent) self.host = host self.port = port self._layout = QVBoxLayout(self) self.setWindowTitle("Hardware on " + self.host + ":" + str(self.port)) self.setMinimumSize(800, 600) self.hardware = None self.selectedHW = None self._model = None self._lbl_status = QLabel() self._layout.addWidget(self._lbl_status) self._layoutH = QHBoxLayout() self._layout.addLayout(self._layoutH) self._hwlist = QListView() self._layoutH.addWidget(self._hwlist) self._lbl_hw = QLabel() self._lbl_hw.setMinimumWidth(400) self._lbl_hw.setMargin(10) self._lbl_hw.setFont(QFontDatabase.systemFont(QFontDatabase.FixedFont)) #self._layoutH.addWidget(self._hwlabel) self._hwscroll = QScrollArea() self._hwscroll.setWidget(self._lbl_hw) self._layoutH.addWidget(self._hwscroll) self._layoutB = QHBoxLayout() self._layout.addLayout(self._layoutB) self._btn_select = QPushButton("Select") self._layoutB.addWidget(self._btn_select) self._btn_rescan = QPushButton("Rescan") self._layoutB.addWidget(self._btn_rescan) self._btn_cancel = QPushButton("Cancel") self._layoutB.addWidget(self._btn_cancel) self._btn_select.clicked.connect(self._select) self._btn_cancel.clicked.connect(lambda: (self._quitScan(), self.close())) self._btn_rescan.clicked.connect(self._prepareScan) self._disable() self._start() def _start(self, ret=None): if not ret: self._prepareScan() ret = self._getHardware() if ret: self.hardware = ret[0] if len(self.hardware) == 0: self._lbl_status.setText( "No Hardware detected. Is Caffepath set?") elif ret[1] == 0: self._lbl_status.setText("Currently selected CPU: " + ret[0][0]["name"]) else: self._lbl_status.setText("Currently selected GPU " + str(ret[1]) + ": " + ret[0][ret[1]]["name"]) self._model = self.HardwareListModel(self.hardware) self._hwlist.setModel(self._model) self._hwlist.selectionModel().currentChanged.connect( self._onSelection) self._enable() def _enable(self): self._hwlist.setEnabled(True) self._btn_rescan.setEnabled(True) def _disable(self): self._hwlist.setEnabled(False) self._btn_select.setEnabled(False) self._btn_rescan.setEnabled(False) self._lbl_hw.setText("") if self._hwlist.selectionModel(): self._hwlist.selectionModel().currentChanged.disconnect() self._hwlist.setModel(None) def _select(self): self.selectedHW = self._hwlist.currentIndex().row() self.close() def _onSelection(self): row = self._hwlist.currentIndex().row() if row != -1: self._lbl_hw.setText(self._getText(row)) self._lbl_hw.adjustSize() self._btn_select.setEnabled(True) else: self._lbl_hw.setText("") def _getText(self, row): log = self.hardware[row]["log"] text = "" for l in log: text += l + "\n" return text def _prepareScan(self): self._disable() ct = buildTransaction(self.host, self.port) if ct: self.ct = ct msg = {"key": Protocol.SCANHARDWARE} self.ct.send(msg) self.ct.bufferReady.connect(self._processScan) self.ct.socketClosed.connect(self._socketClosed) self._lbl_status.setText("Start scanning...") else: self._lbl_status.setText("Failed to start Scan.") def _processScan(self): msg = self.ct.asyncRead() if msg["status"]: if "finished" in msg.keys(): if msg["finished"]: self._quitScan() self._lbl_status.setText("Scan finished.") self._start([msg["hardware"], msg["current"]]) else: if "id" in msg.keys(): self._lbl_status.setText("Found GPU " + str(msg["id"]) + ": " + msg["name"]) else: self._lbl_status.setText("Found CPU: " + msg["name"]) else: self._lbl_status.setText("Scan failed: " + msg["error"]) def _socketClosed(self): self._quitScan() self._enable() self._lbl_status.setText("Connection lost!") def _quitScan(self): if hasattr(self, "ct"): self.ct.bufferReady.disconnect() self.ct.socketClosed.disconnect() self.ct.close() del self.ct def _getHardware(self): msg = {"key": Protocol.GETHARDWARE} ret = sendMsgToHost(self.host, self.port, msg) if ret and "hardware" in ret: return [ret["hardware"], ret["current"]] class HardwareListModel(QAbstractListModel): def __init__(self, data): QAbstractListModel.__init__(self) self.data = data def rowCount(self, parent=None, *args, **kwargs): return len(self.data) def data(self, index, role=None): row = index.row() if role == Qt.DisplayRole: if row == 0: return "CPU: " + self.data[row]["name"] return "GPU " + str( self.data[row]["id"]) + ": " + self.data[row]["name"]
class AppWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.setGeometry(100, 100, 550, 400) self.setUpMenu() self.setUpLayout() self.checkBoxConnect.stateChanged.connect(self.connect_disconnect) self.addButton.clicked.connect(self.add_contact) self.deleteButton.clicked.connect(self.delete_contact) self.sendButton.clicked.connect(self.send_message) self.contactsList.clicked.connect(self.select_contact) # self.messageField.drop.connect(self.add_file_to_message) # model -controller - view self.contact_list_model = StandardItemModelContacts(self) self.messages_list_model = StandardItemModelMessages(self) self.model = ClientModel(self.contact_list_model, self.messages_list_model) self.contactsList.setModel(self.contact_list_model) self.messagesList.setModel(self.messages_list_model) self.controller = ClientController(self.model) # signal-slot self.controller.auth_recieved.connect(self.authentification_recieved) self.controller.gotPersonal.connect(self.new_personal_message) # not connected self.connected = False # nobody selected self.currently_selected = '' def setUpMenu(self): fileMenu = self.menuBar().addMenu('File') quitAct = QAction('Quit', self) quitAct.triggered.connect(self.doQuit) fileMenu.addAction(quitAct) sendMenu = self.menuBar().addMenu('Send') sendFile = QAction('Send File', self) sendFile.triggered.connect(self.doSendFile) sendMenu.addAction(sendFile) def setUpLayout(self): hBoxLayout = QHBoxLayout() mainFrame = QFrame() mainFrame.setLayout(hBoxLayout) self.contact = QLineEdit() self.contact.setFont(QFont('Calibri', 14)) self.contact.setPlaceholderText('Add Contact Here') self.contact.setMinimumHeight(30) self.contact.setMaximumHeight(30) self.addButton = QPushButton('+') self.addButton.setMinimumHeight(30) self.addButton.setMaximumHeight(30) self.addButton.setMinimumWidth(30) self.addButton.setMaximumWidth(30) self.deleteButton = QPushButton('-') self.deleteButton.setMinimumHeight(30) self.deleteButton.setMaximumHeight(30) self.deleteButton.setMinimumWidth(30) self.deleteButton.setMaximumWidth(30) self.contactsList = QListView() self.contactsList.setFrameShape(QFrame.Box) spacer = QFrame() spacer.setMaximumWidth(5) self.nameLabel = QLabel('Username') self.nameLabel.setMinimumHeight(30) self.nameLabel.setMaximumHeight(30) self.nameLabel.setFont(QFont('Calibri', 14)) self.checkBoxConnect = QCheckBox() self.checkBoxConnect.setText('Connect') self.checkBoxConnect.setChecked(False) self.checkBoxConnect.setMaximumHeight(30) self.checkBoxConnect.setMinimumHeight(30) self.checkBoxConnect.setMaximumWidth(70) self.checkBoxConnect.setMinimumWidth(70) self.messagesList = QListView() self.messagesList.setIconSize(QSize(30, 30)) self.messagesList.setFrameShape(QFrame.Box) self.messageField = MessageField() self.messageField.setMinimumHeight(50) self.messageField.setMaximumHeight(50) self.sendButton = QPushButton() self.sendButton.setText('>>') self.sendButton.setMinimumHeight(50) self.sendButton.setMaximumHeight(50) self.sendButton.setMinimumWidth(50) self.sendButton.setMaximumWidth(50) contBox = QGridLayout() contBox.addWidget(self.contact, 0, 0) contBox.addWidget(self.addButton, 0, 1) contBox.addWidget(self.deleteButton, 0, 2) contBox.addWidget(self.contactsList, 1, 0, 2, 3) contBox.addWidget(spacer, 0, 3, 3, 1) contBox.addWidget(self.nameLabel, 0, 4) contBox.addWidget(self.checkBoxConnect, 0, 5, 1, 2) contBox.addWidget(self.messagesList, 1, 4, 1, 3) contBox.addWidget(self.messageField, 2, 4, 1, 2) contBox.addWidget(self.sendButton, 2, 6) contBox.setColumnStretch(0, 3) contBox.setColumnStretch(4, 6) groupBoxCont = QFrame() groupBoxCont.setLayout(contBox) self.setCentralWidget(groupBoxCont) def doQuit(self): self.close() def doSendFile(self): filename = QFileDialog.getOpenFileName(self, 'Open file', '/home')[0] self.messageField.file = filename self.messageField.appendPlainText(filename) def connect_disconnect(self): self.checkBoxConnect.setEnabled(False) if self.checkBoxConnect.isChecked(): self.authentification() else: self.user_disconnect() self.checkBoxConnect.setEnabled(True) # Log in dialog def authentification(self): #read config file d = conf.read_conf() #show Authorization dialog auth_dialog = AuthDialog(self.model, d['username'], d['hostname'], d['port'], parent=self) auth_dialog.accepted.connect(self.auth_dialog_accepted) auth_dialog.rejected.connect(self.auth_dialog_rejected) auth_dialog.show() def auth_dialog_accepted(self): self.checkBoxConnect.setEnabled(True) self.controller.run_client() def auth_dialog_rejected(self): self.checkBoxConnect.setChecked(False) self.checkBoxConnect.setEnabled(True) @pyqtSlot(bool) def authentification_recieved(self, ok): if ok: self.connected = True self.checkBoxConnect.setText('Connected') self.nameLabel.setText('{}:'.format(self.model.username)) self.model.contactlist.clear() self.model.personal_messages = [] self.model.server_messages = [] self.model.sent_messages = [] self.model.open_db() self.controller.ask_contact_list() else: self.checkBoxConnect.setChecked(False) def user_disconnect(self): if self.connected: conf.save_conf(username=self.model.username, hostname=self.model.host, port=str(self.model.port)) self.model.clear_data() self.controller.user_disconnect() self.contact.setText('') self.nameLabel.setText('') self.checkBoxConnect.setText('Connect') self.connected = False self.currently_selected = '' @pyqtSlot(str) def get_contact_list(self): pass def add_contact(self): name = self.contact.text() if name != '': self.controller.add_contact(name) self.contact.setText('') def delete_contact(self): name = self.contact.text() if name != '': self.controller.delete_contact(name) self.contact.setText('') @pyqtSlot(QMimeData) def add_file_to_message(self, mime): self.messageField.setPlainText(mime.text()) def send_message(self): sel_list = self.contactsList.selectionModel().selectedIndexes() if len(sel_list) > 0: contact = self.model.contactlist.contacts[sel_list[0].row()] if self.messageField.file != '': self.controller.send_file(contact.name, self.messageField.file) self.messageField.file = '' else: self.controller.personal_message( contact.name, self.messageField.toPlainText()) self.messageField.clear() self.model.update_messages_for_contact(contact.name) else: pass @pyqtSlot(QModelIndex) def select_contact(self, modelindex): item = self.contact_list_model.data(modelindex, role=Qt.DisplayRole) contact_name = self.model.contactlist.contacts_name[modelindex.row()] self.contact.setText(contact_name) self.show_messages_for_contact(contact_name) self.contactsList.setCurrentIndex(modelindex) self.currently_selected = contact_name @pyqtSlot(str) def new_personal_message(self, sender): self.model.new_message_increase(sender, True) # sel_list = self.listViewContacts.selectionModel().selectedIndexes() if sender == self.currently_selected: self.show_messages_for_contact(self.currently_selected) @pyqtSlot(str) def show_messages_for_contact(self, contact_name): self.model.update_messages_for_contact(contact_name) self.model.new_message_increase(contact_name, False) self.messagesList.scrollToBottom()
class EditList(QWidget): """An editable List-Widget to display and manipulate the content of a list. Parameters ---------- data : List of str | None Input a list with contents to display parent : QWidget | None Parent Widget (QWidget or inherited) or None if there is no parent Notes ----- If you change the list outside of this class, call content_changed to update this widget """ def __init__(self, data=None, ui_buttons=True, parent=None): super().__init__(parent) self.ui_buttons = ui_buttons self.model = EditListModel(data) self.view = QListView() self.view.setModel(self.model) self.layout = QVBoxLayout() self.init_ui() def init_ui(self): self.layout.addWidget(self.view) if self.ui_buttons: bt_layout = QHBoxLayout() addrow_bt = QPushButton('Add Row') addrow_bt.clicked.connect(self.add_row) bt_layout.addWidget(addrow_bt) rmrow_bt = QPushButton('Remove Row') rmrow_bt.clicked.connect(self.remove_row) bt_layout.addWidget(rmrow_bt) edit_bt = QPushButton('Edit') edit_bt.clicked.connect(self.edit_item) bt_layout.addWidget(edit_bt) self.layout.addLayout(bt_layout) self.setLayout(self.layout) def content_changed(self): """Informs ModelView about external change made in data """ self.model.layoutChanged.emit() def replace_data(self, new_data): """Replaces model._data with new_data """ self.model._data = new_data self.content_changed() def add_row(self): row = self.view.selectionModel().currentIndex().row() self.model.insertRow(row) def remove_row(self): row_idxs = self.view.selectionModel().selectedRows() for row_idx in row_idxs: self.model.removeRow(row_idx.row()) def edit_item(self): self.view.edit(self.view.selectionModel().currentIndex())
class EDFilterListWidget(QWidget): """FilterListWidget Combines a QLineEdit and a QListView""" add = pyqtSignal() remove = pyqtSignal() def __init__(self, parent=None): super().__init__(parent=parent) v_layout = QVBoxLayout(self) h_layout = QHBoxLayout() filter_frame = QFrame(self) filter_h_layout = QHBoxLayout(filter_frame) filter_h_layout.setContentsMargins(0, 0, 0, 0) size_policy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) filter_frame.setSizePolicy(size_policy) filter_lbl = QLabel("Filter") self.line_edit = QLineEdit(self) filter_h_layout.addWidget(filter_lbl) filter_h_layout.addWidget(self.line_edit) h_layout.addWidget(filter_frame) self.line_edit.textEdited.connect(self.filter) self.list = QListView(self) self.model = QStandardItemModel(self.list) self.list.setModel(self.model) size_policy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.list.setSizePolicy(size_policy) v_layout.addLayout(h_layout) v_layout.addWidget(self.list) self.controls = EDAddRemoveButtons(parent=self) self.controls.add_btn.clicked.connect(self.add_item) self.controls.rm_btn.clicked.connect(self.remove_item) v_layout.addWidget(self.controls) def filter(self, filter_text): """Hides rows that do not have the pattern""" for row in range(self.model.rowCount()): if filter_text in str(self.model.item(row).text()).lower(): self.list.setRowHidden(row, False) else: self.list.setRowHidden(row, True) @pyqtSlot() def add_item(self): """Add item""" self.add.emit() @pyqtSlot() def remove_item(self): """Remove Item""" self.remove.emit() def clear(self): """Clear the model""" self.model.clear() # pylint: disable=invalid-name def takeItem(self, row: int): """Take Item from the list""" item = self.model.takeItem(row) self.model.takeRow(row) return item # pylint: disable=invalid-name def addItem(self, item: Union[QListWidgetItem, QStandardItem, str]): """Add Item to the list""" if isinstance(item, str): item = QStandardItem(item) self.model.appendRow(item) def count(self): """Convenience method""" return self.model.rowCount() def item(self, row): """Convenience method to reveal model method""" return self.model.item(row) # pylint: disable=invalid-name def selectedIndexes(self): """Convenience Function to revel selectionModel option""" return self.list.selectionModel().selectedIndexes() # pylint: disable=invalid-name def selectedItems(self): """Convenience to replicate functionality in QListWidget""" inds = self.selectedIndexes() items = [self.item(i.row()) for i in inds] return items
def _get_selected_items(self, view: W.QListView) -> List[int]: return [ index.row() for index in view.selectionModel().selectedIndexes() ]
class _StyleList(QWidget): def __init__( self, api: Api, model: AssStylesModel, selection_model: QItemSelectionModel, parent: QWidget, ) -> None: super().__init__(parent) self._api = api self._model = model selection_model.selectionChanged.connect(self._on_selection_change) self._styles_list_view = QListView(self) self._styles_list_view.setModel(model) self._styles_list_view.setSelectionModel(selection_model) self._add_button = QPushButton("Add", self) self._add_button.clicked.connect(self._on_add_button_click) self._remove_button = QPushButton("Remove", self) self._remove_button.setEnabled(False) self._remove_button.clicked.connect(self._on_remove_button_click) self._duplicate_button = QPushButton("Duplicate", self) self._duplicate_button.setEnabled(False) self._duplicate_button.clicked.connect(self._on_duplicate_button_click) self._move_up_button = QPushButton("Move up", self) self._move_up_button.setEnabled(False) self._move_up_button.clicked.connect(self._on_move_up_button_click) self._move_down_button = QPushButton("Move down", self) self._move_down_button.setEnabled(False) self._move_down_button.clicked.connect(self._on_move_down_button_click) self._rename_button = QPushButton("Rename", self) self._rename_button.setEnabled(False) self._rename_button.clicked.connect(self._on_rename_button_click) strip = QWidget(self) strip_layout = QGridLayout(strip) strip_layout.setContentsMargins(0, 0, 0, 0) strip_layout.addWidget(self._add_button, 0, 0) strip_layout.addWidget(self._remove_button, 0, 1) strip_layout.addWidget(self._duplicate_button, 0, 2) strip_layout.addWidget(self._move_up_button, 1, 0) strip_layout.addWidget(self._move_down_button, 1, 1) strip_layout.addWidget(self._rename_button, 1, 2) layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self._styles_list_view) layout.addWidget(strip) @property def _selected_style(self) -> Optional[AssStyle]: selected_row = self._selected_row if selected_row is None: return None return self._api.subs.styles[selected_row] @property def _selected_row(self) -> Optional[int]: indexes = self._styles_list_view.selectedIndexes() if not indexes: return None return cast(int, indexes[0].row()) def _on_selection_change( self, selected: QItemSelection, _deselected: QItemSelection, ) -> None: anything_selected = len(selected.indexes()) > 0 self._remove_button.setEnabled(anything_selected) self._rename_button.setEnabled(anything_selected) self._duplicate_button.setEnabled(anything_selected) self._move_up_button.setEnabled(anything_selected and selected.indexes()[0].row() > 0) self._move_down_button.setEnabled( anything_selected and selected.indexes()[0].row() < len(self._api.subs.styles) - 1) @async_slot() async def _on_add_button_click(self) -> None: style_name = await self._prompt_for_unique_style_name() if not style_name: return style = AssStyle(name=style_name) self._api.subs.styles.append(style) idx = style.index self._styles_list_view.selectionModel().select( self._model.index(idx, 0), QItemSelectionModel.SelectionFlag( QItemSelectionModel.SelectionFlag.Clear | QItemSelectionModel.SelectionFlag.Select), ) async def _prompt_for_unique_style_name(self, style_name: str = "" ) -> Optional[str]: prompt_text = "Name of the new style:" while True: dialog = QInputDialog(self) dialog.setLabelText(prompt_text) dialog.setTextValue(style_name) dialog.setInputMode(QInputDialog.TextInput) if not await async_dialog_exec(dialog): return None style_name = dialog.textValue() exists = False for style in self._api.subs.styles: if style.name == style_name: exists = True if not exists: return style_name prompt_text = '"{}" already exists. Choose different name:'.format( style_name) @async_slot() async def _on_remove_button_click(self) -> None: style = self._selected_style assert style is not None idx = style.index if not await show_prompt( f'Are you sure you want to remove style "{style.name}"?', self): return self._styles_list_view.selectionModel().clear() with self._api.undo.capture(): del self._api.subs.styles[idx] def _on_duplicate_button_click(self, event: QMouseEvent) -> None: style = self._selected_style assert style is not None idx = style.index style_copy = copy(style) style_copy.name += " (copy)" with self._api.undo.capture(): self._api.subs.styles.insert(idx + 1, style_copy) self._styles_list_view.selectionModel().select( self._model.index(idx + 1, 0), QItemSelectionModel.SelectionFlag( QItemSelectionModel.SelectionFlag.Clear | QItemSelectionModel.SelectionFlag.Select), ) def _on_move_up_button_click(self, event: QMouseEvent) -> None: style = self._selected_style assert style is not None idx = style.index with self._api.undo.capture(): self._api.subs.styles[idx:idx + 1] = [] self._api.subs.styles[idx - 1:idx - 1] = [style] self._styles_list_view.selectionModel().select( self._model.index(idx - 1, 0), QItemSelectionModel.SelectionFlag( QItemSelectionModel.SelectionFlag.Clear | QItemSelectionModel.SelectionFlag.Select), ) def _on_move_down_button_click(self, event: QMouseEvent) -> None: style = self._selected_style assert style is not None idx = style.index with self._api.undo.capture(): self._api.subs.styles[idx:idx + 1] = [] self._api.subs.styles[idx + 1:idx + 1] = [style] self._styles_list_view.selectionModel().select( self._model.index(idx + 1, 0), QItemSelectionModel.SelectionFlag( QItemSelectionModel.SelectionFlag.Clear | QItemSelectionModel.SelectionFlag.Select), ) @async_slot() async def _on_rename_button_click(self) -> None: style = self._selected_style assert style is not None idx = style.index old_name = style.name new_name = await self._prompt_for_unique_style_name(old_name) if not new_name: return with self._api.undo.capture(): style.name = new_name for line in self._api.subs.events: if line.style_name == old_name: line.style_name = new_name self._styles_list_view.selectionModel().select( self._model.index(idx, 0), QItemSelectionModel.SelectionFlag.Select)
class Explorer(QWidget): def __init__(self, rootdir=QDir.rootPath()): QWidget.__init__(self) self.treeview = QTreeView() self.listview = QListView() self.path = rootdir self.filename = '' self.filepath = rootdir self.canvas = None self.col_selector = None self.header = '' self.xcol = [1] self.ycol = [1] self.ncols = 0 self.dirModel = QFileSystemModel() self.dirModel.setRootPath(self.path) self.dirModel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) self.fileModel = QFileSystemModel() self.fileModel.setRootPath(self.filepath) self.fileModel.setFilter(QDir.NoDotAndDotDot | QDir.Files) self.fileModel.setNameFilters(['*.txt']) self.fileModel.setNameFilterDisables(0) self.treeview.setModel(self.dirModel) self.listview.setModel(self.fileModel) for i in [1, 2, 3]: self.treeview.setColumnHidden(i, True) self.treeview.setHeaderHidden(True) self.treeview.setRootIndex(self.dirModel.index(self.path)) self.listview.setRootIndex(self.fileModel.index(self.path)) self.treeview.clicked.connect(self.on_clicked) self.listview.selectionModel().currentChanged.connect(self.file_selected) self.listview.selectionModel().currentChanged.connect(lambda: self.canvas.update_plot(self)) self.listview.selectionModel().currentChanged.connect(lambda: self.col_selector.update_range(self.ncols)) def on_clicked(self, index): self.path = self.dirModel.fileInfo(index).absoluteFilePath() self.listview.setRootIndex(self.fileModel.setRootPath(self.path)) def file_selected(self, index): self.filename = self.fileModel.fileName(index) self.filepath = self.fileModel.filePath(index) self.load_file() def load_file(self): try: if self.filepath.endswith('.txt'): with open(self.filepath, 'r') as file: self.header, self.xcol, self.ycol = '', [], [] for ln in file: if ln.startswith('#'): self.header += ln[2:] else: cols = ln.split('\t') self.xcol.append(float(cols[0])) self.ycol.append(float(cols[self.col_selector.sp.value()])) self.ncols = len(cols) self.col_selector.update_range(self.ncols) except: self.header, self.xcol, self.ycol = '', [0], [0] def update_rootdir(self, rootdir): self.path = rootdir self.treeview.setRootIndex(self.dirModel.index(self.path)) self.listview.setRootIndex(self.fileModel.index(self.path))
class MainWindow(QWidget): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.playlistView = QListView() self.switch_status = 2 self.video_widget = QVideoWidget() self.playlist = QMediaPlaylist() self.model = PlaylistModel(self.playlist) self.titleBar = TitleBar(self) self.currentTimeLabel = QLabel() self.timeSlider = QSlider() self.totalTimeLabel = QLabel() self.mediaPlayer = QMediaPlayer() self.open_btn = QPushButton('Open File') self.play_btn = QPushButton() self.prev_btn = QPushButton() self.stop_btn = QPushButton() self.next_btn = QPushButton() self.switch_media_widgets_btn = QPushButton() self.pseudo_label = QLabel() self.vol_label = QLabel() self.volume_slider = Slider(Qt.Horizontal) self.gui() self.set_children_focus_policy(Qt.NoFocus) def gui(self): self.currentTimeLabel.setMinimumSize(QSize(80, 0)) self.currentTimeLabel.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) self.timeSlider.setOrientation(Qt.Horizontal) self.totalTimeLabel.setMinimumSize(QSize(80, 0)) self.totalTimeLabel.setAlignment(Qt.AlignLeading | Qt.AlignLeft | Qt.AlignVCenter) self.playlistView.setAcceptDrops(True) self.playlistView.setProperty("showDropIndicator", True) self.playlistView.setDragDropMode(QAbstractItemView.DropOnly) self.playlistView.setAlternatingRowColors(True) self.playlistView.setUniformItemSizes(True) self.setWindowFlags(Qt.FramelessWindowHint) self.setWindowTitle('Media Player') self.titleBar.label.setText('Media Player') self.setWindowIcon(QIcon('icon_png/media_player.png')) self.setGeometry(600, 200, 850, 600) self.timeSlider.setRange(0, 0) self.play_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.prev_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipBackward)) self.next_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipForward)) self.stop_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) self.switch_media_widgets_btn.setIcon(self.style().standardIcon(QStyle.SP_FileDialogDetailedView)) self.vol_label.setText("") self.vol_label.setPixmap(QPixmap("icon_png/speaker-volume.png")) self.currentTimeLabel.setText("00:00") self.totalTimeLabel.setText("00:00") self.volume_slider.setValue(self.mediaPlayer.volume()) self.mediaPlayer.setVideoOutput(self.video_widget) self.mediaPlayer.setPlaylist(self.playlist) self.playlistView.setModel(self.model) self.video_widget.hide() sizegrip = QSizeGrip(self) self.setAcceptDrops(True) inner_h_box = QHBoxLayout() inner_h_box.addWidget(self.prev_btn) inner_h_box.addWidget(self.stop_btn) inner_h_box.addWidget(self.next_btn) vol_h_box = QHBoxLayout() vol_h_box.addWidget(self.vol_label, 0) vol_h_box.addWidget(self.volume_slider, 1) h_box = QHBoxLayout() h_box.addWidget(self.open_btn) h_box.addWidget(self.play_btn, 0) h_box.addLayout(inner_h_box, 0) h_box.addWidget(self.switch_media_widgets_btn, 0) h_box.addWidget(self.pseudo_label, 1) h_box.addLayout(vol_h_box, 0) h_box.addWidget(sizegrip, 0, Qt.AlignBottom | Qt.AlignRight) video_slider_h_box = QHBoxLayout() video_slider_h_box.addWidget(self.currentTimeLabel) video_slider_h_box.addWidget(self.timeSlider) video_slider_h_box.addWidget(self.totalTimeLabel) v_box = QVBoxLayout() v_box.addWidget(self.titleBar, 0) v_box.addWidget(self.video_widget, 1) v_box.addWidget(self.playlistView, 1) v_box.addLayout(video_slider_h_box, 0) v_box.addLayout(h_box, 0) inner_h_box.setContentsMargins(20, 0, 10, 0) vol_h_box.setContentsMargins(0, 0, 20, 0) h_box.setContentsMargins(20, 0, 0, 0) v_box.setContentsMargins(0, 0, 0, 0) video_slider_h_box.setSpacing(10) h_box.setSpacing(0) v_box.setSpacing(0) self.setLayout(v_box) self.enabler() # connections self.open_btn.clicked.connect(self.open_file) self.play_btn.clicked.connect(self.play_media) self.stop_btn.clicked.connect(self.stop_media) self.prev_btn.pressed.connect(self.play_prev) self.next_btn.pressed.connect(self.play_next) self.switch_media_widgets_btn.pressed.connect(self.switch_media) self.playlist.currentIndexChanged.connect(self.playlist_position_changed) selection_model = self.playlistView.selectionModel() selection_model.selectionChanged.connect(self.playlist_selection_changed) self.mediaPlayer.durationChanged.connect(self.update_duration) self.mediaPlayer.positionChanged.connect(self.update_position) self.timeSlider.valueChanged.connect(self.mediaPlayer.setPosition) self.mediaPlayer.stateChanged.connect(self.media_state) self.mediaPlayer.volumeChanged.connect(self.volume_changed) self.volume_slider.valueChanged.connect(self.set_volume) def set_children_focus_policy(self, policy): def recursive_set_child_focus_policy(parent_q_widget): for childQWidget in parent_q_widget.findChildren(QWidget): childQWidget.setFocusPolicy(policy) recursive_set_child_focus_policy(childQWidget) recursive_set_child_focus_policy(self) def enabler(self, state=False): if state is False: self.play_btn.setEnabled(False) self.prev_btn.setEnabled(False) self.stop_btn.setEnabled(False) self.next_btn.setEnabled(False) else: self.play_btn.setEnabled(True) self.stop_btn.setEnabled(True) self.prev_btn.setEnabled(True) self.next_btn.setEnabled(True) def switch_media(self): if self.switch_status == 0: self.video_widget.hide() self.playlistView.show() self.switch_status = 1 self.switch_media_widgets_btn.setEnabled(True) elif self.switch_status == 1: self.video_widget.show() self.playlistView.hide() self.switch_status = 0 self.switch_media_widgets_btn.setEnabled(True) else: self.video_widget.hide() self.playlistView.show() self.switch_media_widgets_btn.setEnabled(False) def play_media(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() self.ui_handler() def ui_handler(self): if not self.playlist.isEmpty(): self.enabler(True) file_path = QFileInfo(self.mediaPlayer.currentMedia().canonicalUrl().toString()).fileName() ext = os.path.splitext(file_path)[-1].lower() audio_ext = ['.flac', '.mp3'] video_ext = ['.mp4', '.m4a', '.mov', '.flv', 'avi', '3gp', '.mkv', '.wmv'] if ext in audio_ext: self.switch_status = 2 self.switch_media() if self.isFullScreen(): self.fullscreen() elif ext in video_ext: self.switch_status = 1 self.switch_media() self.setWindowTitle(file_path + ' - Media Player') self.titleBar.label.setText(file_path + ' - Media Player') def stop_media(self): if self.mediaPlayer.state() != QMediaPlayer.StoppedState: self.mediaPlayer.stop() self.setWindowTitle('Media Player') self.titleBar.label.setText('Media Player') def fullscreen(self): if self.switch_status == 2 or self.isFullScreen(): self.titleBar.show() self.timeSlider.show() self.currentTimeLabel.show() self.totalTimeLabel.show() self.volume_slider.show() self.open_btn.show() self.play_btn.show() self.prev_btn.show() self.stop_btn.show() self.next_btn.show() self.switch_media_widgets_btn.show() self.pseudo_label.show() self.vol_label.show() self.showNormal() else: self.titleBar.hide() self.timeSlider.hide() self.currentTimeLabel.hide() self.totalTimeLabel.hide() self.volume_slider.hide() self.open_btn.hide() self.play_btn.hide() self.prev_btn.hide() self.stop_btn.hide() self.next_btn.hide() self.switch_media_widgets_btn.hide() self.pseudo_label.hide() self.vol_label.hide() self.showFullScreen() def mouseDoubleClickEvent(self, event: QMouseEvent): event.accept() if event.button() == Qt.LeftButton: self.fullscreen() def media_state(self): os_sleep = WindowsInhibitor() if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.play_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPause)) if os.name == 'nt': os_sleep = WindowsInhibitor() os_sleep.inhibit() else: self.play_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) if os_sleep: os_sleep.uninhibit() def play_next(self): self.playlist.next() def media_seek(self, seek): if not self.playlist.isEmpty(): player = self.mediaPlayer if (player.duration() - seek) > player.position(): player.setPosition(player.position() + seek) def play_prev(self): self.playlist.previous() def dragEnterEvent(self, e): if e.mimeData().hasUrls(): e.acceptProposedAction() def dropEvent(self, e): for url in e.mimeData().urls(): ext = os.path.splitext(url.fileName())[-1].lower() allowed_ext = ['.flac', '.mp3', '.mp4', '.m4a', '.mov', '.flv', 'avi', '3gp', '.mkv', '.wmv'] if ext in allowed_ext: self.playlist.addMedia( QMediaContent(url) ) self.model.layoutChanged.emit() if self.mediaPlayer.state() != QMediaPlayer.PlayingState: i = self.playlist.mediaCount() - len(e.mimeData().urls()) self.playlist.setCurrentIndex(i) if not self.playlist.isEmpty(): self.play_media() def open_file(self): filter_files = "Media (*.mp3 *.mp4 *.mkv);; Videos files (*.mp4 *.mkv);; Music Files(*.mp3)" paths, _ = QFileDialog.getOpenFileNames(self, "Open file", "", filter_files) if paths: self.mediaPlayer.pause() for path in paths: self.playlist.addMedia( QMediaContent( QUrl.fromLocalFile(path) ) ) i = self.playlist.mediaCount() - len(paths) self.playlist.setCurrentIndex(i) self.play_media() self.model.layoutChanged.emit() def update_duration(self, duration): self.mediaPlayer.duration() self.timeSlider.setMaximum(duration) if duration >= 0: self.totalTimeLabel.setText(hhmmss(duration)) def update_position(self, position): if position >= 0: self.currentTimeLabel.setText(hhmmss(position)) self.timeSlider.blockSignals(True) self.timeSlider.setValue(position) self.timeSlider.blockSignals(False) def playlist_selection_changed(self, ix): i = ix.indexes()[0].row() self.playlist.setCurrentIndex(i) self.ui_handler() def playlist_position_changed(self, i): if i > -1: ix = self.model.index(i) self.playlistView.setCurrentIndex(ix) def set_volume(self, value): self.mediaPlayer.setVolume(value) def volume_changed(self, value): self.volume_slider.setValue(value) def keyPressEvent(self, event): key = event.key() modifiers = int(event.modifiers()) if (modifiers and modifiers & MOD_MASK == modifiers and key > 0 and key != Qt.Key_Shift and key != Qt.Key_Alt and key != Qt.Key_Control and key != Qt.Key_Meta): key_name = QKeySequence(modifiers + key).toString() if key_name == 'Ctrl+Right': self.media_seek(30000) elif key_name == 'Ctrl+Left': self.media_seek(-30000) elif key_name == 'Ctrl+Up': self.mediaPlayer.setVolume(self.mediaPlayer.volume() + 5) elif key_name == 'Ctrl+Down': self.mediaPlayer.setVolume(self.mediaPlayer.volume() - 5) elif key_name == 'Ctrl+O': self.open_file() else: if event.key() == Qt.Key_Space: self.play_media() elif event.key() == Qt.Key_MediaPlay: self.play_media() elif event.key() == Qt.Key_MediaNext: self.play_next() elif event.key() == Qt.Key_MediaPrevious: self.play_prev() elif event.key() == Qt.Key_Escape: self.close() elif event.key() == Qt.Key_F: self.fullscreen() elif event.key() == Qt.Key_Right: self.media_seek(5000) elif event.key() == Qt.Key_Left: self.media_seek(-5000)
class FileManager(QWidget, _HalWidgetBase): def __init__(self, parent=None): super(FileManager, self).__init__(parent) self.title = 'PyQt5 file system view - pythonspot.com' self.left = 10 self.top = 10 self.width = 640 self.height = 480 self.default_path = (os.path.join(os.path.expanduser('~'), 'linuxcnc/nc_files/examples')) self.user_path = (os.path.join('/media')) self.currentPath = None self.EXT = INFO.PROGRAM_FILTERS_EXTENSIONS self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.model = QFileSystemModel() self.model.setRootPath(QDir.currentPath()) self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files) self.model.setNameFilterDisables(False) self.model.setNameFilters(self.EXT) self.list = QListView() self.list.setModel(self.model) self.updateDirectoryView(self.default_path) self.list.setWindowTitle("Dir View") self.list.resize(640, 480) self.list.clicked[QModelIndex].connect(self.clicked) self.list.activated.connect(self._getPathActivated) #self.list.currentChanged = self.currentChanged self.list.setAlternatingRowColors(True) self.cb = QComboBox() self.cb.currentTextChanged.connect(self.filterChanged) self.cb.addItems(self.EXT) #self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button = QPushButton() self.button.setText('Media') self.button.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button.setToolTip('Jump to Media directory') self.button.clicked.connect(self.onMediaClicked) self.button2 = QPushButton() self.button2.setText('User') self.button2.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button2.setToolTip('Jump to linuxcnc directory') self.button2.clicked.connect(self.onUserClicked) hbox = QHBoxLayout() hbox.addWidget(self.button) hbox.addWidget(self.button2) hbox.addWidget(self.cb) windowLayout = QVBoxLayout() windowLayout.addWidget(self.list) windowLayout.addLayout(hbox) self.setLayout(windowLayout) self.show() # this could return the current/previous selected as it's selected. # need to uncomment monkey patch of self.list.currentChanged above # so far this is not needed def currentChanged(self,c,p): dir_path = self.model.filePath(c) print('-> ',dir_path) def updateDirectoryView(self, path): self.list.setRootIndex(self.model.setRootPath(path)) def filterChanged(self, text): self.model.setNameFilters([text]) def clicked(self, index): # the signal passes the index of the clicked item dir_path = self.model.filePath(index) if self.model.fileInfo(index).isFile(): self.currentPath = dir_path return root_index = self.model.setRootPath(dir_path) self.list.setRootIndex(root_index) def onMediaClicked(self): self.updateDirectoryView(self.user_path) def onUserClicked(self): self.updateDirectoryView(self.default_path) def select_row(self, style): style = style.lower() selectionModel = self.list.selectionModel() row = selectionModel.currentIndex().row() self.rows = self.model.rowCount(self.list.rootIndex()) if style == 'last': row = self.rows elif style == 'up': if row > 0: row -= 1 else: row = 0 elif style == 'down': if row < self.rows: row += 1 else: row = self.rows else: return top = self.model.index(row, 0, self.list.rootIndex()) selectionModel.setCurrentIndex(top, QItemSelectionModel.Select | QItemSelectionModel.Rows) selection = QItemSelection(top, top) selectionModel.clearSelection() selectionModel.select(selection, QItemSelectionModel.Select) # returns the current highlighted (selected) path as well as # whether it's a file or not. def getCurrentSelected(self): selectionModel = self.list.selectionModel() index = selectionModel.currentIndex() dir_path = self.model.filePath(index) if self.model.fileInfo(index).isFile(): return (dir_path, True) else: return (dir_path, False) def _hal_init(self): if self.PREFS_: last_path = self.PREFS_.getpref('last_loaded_directory', self.default_path, str, 'BOOK_KEEPING') self.updateDirectoryView(last_path) LOG.debug("lAST FILE PATH: {}".format(last_path)) else: LOG.debug("lAST FILE PATH: {}".format(self.default_path)) self.updateDirectoryView(self.default_path) # get current selection and update the path # then if the path is good load it into linuxcnc # record it in the preference file if available def _getPathActivated(self): row = self.list.selectionModel().currentIndex() self.clicked(row) fname = self.currentPath if fname is None: return if fname: self.load(fname) # this can be class patched to do something else def load(self, fname=None): if fname is None: self._getPathActivated() return self.recordBookKeeping() ACTION.OPEN_PROGRAM(fname) STATUS.emit('update-machine-log', 'Loaded: ' + fname, 'TIME') # this can be class patched to do something else def recordBookKeeping(self): fname = self.currentPath if fname is None: return if self.PREFS_: self.PREFS_.putpref('last_loaded_directory', self.model.rootPath(), str, 'BOOK_KEEPING') self.PREFS_.putpref('RecentPath_0', fname, str, 'BOOK_KEEPING') # moves the selection up # used with MPG scrolling def up(self): self.select_row('up') # moves the selection down # used with MPG scrolling def down(self): self.select_row('down')
class FileManager(QWidget, _HalWidgetBase): def __init__(self, parent=None): super(FileManager, self).__init__(parent) self.title = 'Qtvcp File System View' self.left = 10 self.top = 10 self.width = 640 self.height = 480 self._last = 0 if INFO.PROGRAM_PREFIX is not None: self.user_path = os.path.expanduser(INFO.PROGRAM_PREFIX) else: self.user_path = (os.path.join(os.path.expanduser('~'), 'linuxcnc/nc_files')) user = os.path.split(os.path.expanduser('~'))[-1] self.media_path = (os.path.join('/media', user)) temp = [('User', self.user_path), ('Media', self.media_path)] self._jumpList = OrderedDict(temp) self.currentPath = None self.currentFolder = None self.PREFS_ = None self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) pasteBox = QHBoxLayout() self.textLine = QLineEdit() self.textLine.setToolTip('Current Director/selected File') self.pasteButton = QToolButton() self.pasteButton.setEnabled(False) self.pasteButton.setText('Paste') self.pasteButton.setToolTip( 'Copy file from copy path to current directory/file') self.pasteButton.clicked.connect(self.paste) self.pasteButton.hide() pasteBox.addWidget(self.textLine) pasteBox.addWidget(self.pasteButton) self.copyBox = QFrame() hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) self.copyLine = QLineEdit() self.copyLine.setToolTip('File path to copy from, when pasting') self.copyButton = QToolButton() self.copyButton.setText('Copy') self.copyButton.setToolTip('Record current file as copy path') self.copyButton.clicked.connect(self.recordCopyPath) hbox.addWidget(self.copyButton) hbox.addWidget(self.copyLine) self.copyBox.setLayout(hbox) self.copyBox.hide() self.model = QFileSystemModel() self.model.setRootPath(QDir.currentPath()) self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files) self.model.setNameFilterDisables(False) self.model.rootPathChanged.connect(self.folderChanged) self.list = QListView() self.list.setModel(self.model) self.list.resize(640, 480) self.list.clicked[QModelIndex].connect(self.listClicked) self.list.activated.connect(self._getPathActivated) self.list.setAlternatingRowColors(True) self.list.hide() self.table = QTableView() self.table.setModel(self.model) self.table.resize(640, 480) self.table.clicked[QModelIndex].connect(self.listClicked) self.table.activated.connect(self._getPathActivated) self.table.setAlternatingRowColors(True) header = self.table.horizontalHeader() header.setSectionResizeMode(0, QHeaderView.Stretch) header.setSectionResizeMode(1, QHeaderView.ResizeToContents) header.setSectionResizeMode(3, QHeaderView.ResizeToContents) header.swapSections(1, 3) header.setSortIndicator(1, Qt.AscendingOrder) self.table.setSortingEnabled(True) self.table.setColumnHidden(2, True) # type self.table.verticalHeader().setVisible(False) # row count header self.cb = QComboBox() self.cb.currentIndexChanged.connect(self.filterChanged) self.fillCombobox(INFO.PROGRAM_FILTERS_EXTENSIONS) self.cb.setMinimumHeight(30) self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button2 = QToolButton() self.button2.setText('User') self.button2.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button2.setMinimumSize(60, 30) self.button2.setToolTip( 'Jump to User directory.\nLong press for Options.') self.button2.clicked.connect(self.onJumpClicked) self.button3 = QToolButton() self.button3.setText('Add Jump') self.button3.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button3.setMinimumSize(60, 30) self.button3.setToolTip('Add current directory to jump button list') self.button3.clicked.connect(self.onActionClicked) self.settingMenu = QMenu(self) self.button2.setMenu(self.settingMenu) hbox = QHBoxLayout() hbox.addWidget(self.button2) hbox.addWidget(self.button3) hbox.insertStretch(2, stretch=0) hbox.addWidget(self.cb) windowLayout = QVBoxLayout() windowLayout.addLayout(pasteBox) windowLayout.addWidget(self.copyBox) windowLayout.addWidget(self.list) windowLayout.addWidget(self.table) windowLayout.addLayout(hbox) self.setLayout(windowLayout) self.show() def _hal_init(self): if self.PREFS_: last_path = self.PREFS_.getpref('last_loaded_directory', self.user_path, str, 'BOOK_KEEPING') LOG.debug("lAST FILE PATH: {}".format(last_path)) if not last_path == '': self.updateDirectoryView(last_path) else: self.updateDirectoryView(self.user_path) # get all the saved jumplist paths temp = self.PREFS_.getall('FILEMANAGER_JUMPLIST') self._jumpList.update(temp) else: LOG.debug("lAST FILE PATH: {}".format(self.user_path)) self.updateDirectoryView(self.user_path) # install jump paths into toolbutton menu for i in self._jumpList: self.addAction(i) # set recorded columns sort settings self.SETTINGS_.beginGroup("FileManager-{}".format(self.objectName())) sect = self.SETTINGS_.value('sortIndicatorSection', type=int) order = self.SETTINGS_.value('sortIndicatorOrder', type=int) self.SETTINGS_.endGroup() if not None in (sect, order): self.table.horizontalHeader().setSortIndicator(sect, order) # when qtvcp closes this gets called # record jump list paths def _hal_cleanup(self): if self.PREFS_: for i, key in enumerate(self._jumpList): if i in (0, 1): continue self.PREFS_.putpref(key, self._jumpList.get(key), str, 'FILEMANAGER_JUMPLIST') # record sorted columns h = self.table.horizontalHeader() self.SETTINGS_.beginGroup("FileManager-{}".format(self.objectName())) self.SETTINGS_.setValue('sortIndicatorSection', h.sortIndicatorSection()) self.SETTINGS_.setValue('sortIndicatorOrder', h.sortIndicatorOrder()) self.SETTINGS_.endGroup() ######################### # callbacks ######################### # add shown text and hidden filter data from the INI def fillCombobox(self, data): for i in data: self.cb.addItem(i[0], i[1]) def folderChanged(self, data): data = os.path.normpath(data) self.currentFolder = data self.textLine.setText(data) def updateDirectoryView(self, path, quiet=False): if os.path.exists(path): self.list.setRootIndex(self.model.setRootPath(path)) self.table.setRootIndex(self.model.setRootPath(path)) else: LOG.debug( "Set directory view error - no such path {}".format(path)) if not quiet: STATUS.emit( 'error', LOW_ERROR, "File Manager error - No such path: {}".format(path)) # retrieve selected filter (it's held as QT.userData) def filterChanged(self, index): userdata = self.cb.itemData(index) self.model.setNameFilters(userdata) def listClicked(self, index): # the signal passes the index of the clicked item dir_path = os.path.normpath(self.model.filePath(index)) if self.model.fileInfo(index).isFile(): self.currentPath = dir_path self.textLine.setText(self.currentPath) return root_index = self.model.setRootPath(dir_path) self.list.setRootIndex(root_index) self.table.setRootIndex(root_index) def onUserClicked(self): self.showUserDir() def onMediaClicked(self): self.showMediaDir() # jump directly to a saved path shown on the button def onJumpClicked(self): data = self.button2.text() if data.upper() == 'MEDIA': self.showMediaDir() elif data.upper() == 'USER': self.showUserDir() else: temp = self._jumpList.get(data) if temp is not None: self.updateDirectoryView(temp) else: STATUS.emit('error', linuxcnc.OPERATOR_ERROR, 'file jumopath: {} not valid'.format(data)) log.debug('file jumopath: {} not valid'.format(data)) # jump directly to a saved path from the menu def jumpTriggered(self, data): if data.upper() == 'MEDIA': self.button2.setText('{}'.format(data)) self.button2.setToolTip( 'Jump to Media directory.\nLong press for Options.') self.showMediaDir() elif data.upper() == 'USER': self.button2.setText('{}'.format(data)) self.button2.setToolTip( 'Jump to User directory.\nLong press for Options.') self.showUserDir() else: self.button2.setText('{}'.format(data)) self.button2.setToolTip('Jump to directory:\n{}'.format( self._jumpList.get(data))) self.updateDirectoryView(self._jumpList.get(data)) # add a jump list path def onActionClicked(self): i = self.currentFolder try: self._jumpList[i] = i except Exception as e: print(e) button = QAction(QIcon.fromTheme('user-home'), i, self) # weird lambda i=i to work around 'function closure' button.triggered.connect(lambda state, i=i: self.jumpTriggered(i)) self.settingMenu.addAction(button) # get current selection and update the path # then if the path is good load it into linuxcnc # record it in the preference file if available def _getPathActivated(self): if self.list.isVisible(): row = self.list.selectionModel().currentIndex() else: row = self.table.selectionModel().currentIndex() self.listClicked(row) fname = self.currentPath if fname is None: return if fname: self.load(fname) def recordCopyPath(self): data, isFile = self.getCurrentSelected() if isFile: self.copyLine.setText(os.path.normpath(data)) self.pasteButton.setEnabled(True) else: self.copyLine.setText('') self.pasteButton.setEnabled(False) STATUS.emit('error', OPERATOR_ERROR, 'Can only copy a file, not a folder') def paste(self): res = self.copyFile(self.copyLine.text(), self.textLine.text()) if res: self.copyLine.setText('') self.pasteButton.setEnabled(False) ######################## # helper functions ######################## def addAction(self, i): axisButton = QAction(QIcon.fromTheme('user-home'), i, self) # weird lambda i=i to work around 'function closure' axisButton.triggered.connect(lambda state, i=i: self.jumpTriggered(i)) self.settingMenu.addAction(axisButton) def showList(self, state=True): if state: self.table.hide() self.list.show() else: self.table.show() self.list.hide() def showTable(self, state=True): self.showList(not state) def showCopyControls(self, state): if state: self.copyBox.show() self.pasteButton.show() else: self.copyBox.hide() self.pasteButton.hide() def showMediaDir(self, quiet=False): self.updateDirectoryView(self.media_path, quiet) def showUserDir(self, quiet=False): self.updateDirectoryView(self.user_path, quiet) def copyFile(self, s, d): try: shutil.copy(s, d) return True except Exception as e: LOG.error("Copy file error: {}".format(e)) STATUS.emit('error', OPERATOR_ERROR, "Copy file error: {}".format(e)) return False @pyqtSlot(float) @pyqtSlot(int) def scroll(self, data): if data > self._last: self.up() elif data < self._last: self.down() self._last = data # moves the selection up # used with MPG scrolling def up(self): self.select_row('up') # moves the selection down # used with MPG scrolling def down(self): self.select_row('down') def select_row(self, style='down'): style = style.lower() if self.list.isVisible(): i = self.list.rootIndex() selectionModel = self.list.selectionModel() else: i = self.table.rootIndex() selectionModel = self.table.selectionModel() row = selectionModel.currentIndex().row() self.rows = self.model.rowCount(i) if style == 'last': row = self.rows elif style == 'up': if row > 0: row -= 1 else: row = 0 elif style == 'down': if row < self.rows - 1: row += 1 else: row = self.rows - 1 else: return top = self.model.index(row, 0, i) selectionModel.setCurrentIndex( top, QItemSelectionModel.Select | QItemSelectionModel.Rows) selection = QItemSelection(top, top) selectionModel.clearSelection() selectionModel.select(selection, QItemSelectionModel.Select) # returns the current highlighted (selected) path as well as # whether it's a file or not. def getCurrentSelected(self): if self.list.isVisible(): selectionModel = self.list.selectionModel() else: selectionModel = self.table.selectionModel() index = selectionModel.currentIndex() dir_path = os.path.normpath(self.model.filePath(index)) if self.model.fileInfo(index).isFile(): return (dir_path, True) else: return (dir_path, False) # This can be class patched to do something else def load(self, fname=None): try: if fname is None: self._getPathActivated() return self.recordBookKeeping() ACTION.OPEN_PROGRAM(fname) STATUS.emit('update-machine-log', 'Loaded: ' + fname, 'TIME') except Exception as e: LOG.error("Load file error: {}".format(e)) STATUS.emit('error', NML_ERROR, "Load file error: {}".format(e)) # This can be class patched to do something else def recordBookKeeping(self): fname = self.currentPath if fname is None: return if self.PREFS_: self.PREFS_.putpref('last_loaded_directory', self.model.rootPath(), str, 'BOOK_KEEPING') self.PREFS_.putpref('RecentPath_0', fname, str, 'BOOK_KEEPING')
class VideoPlayer(QWidget): def __init__(self, aPath, parent=None): super(VideoPlayer, self).__init__(parent) self.setAttribute(Qt.WA_NoSystemBackground, True) self.setAcceptDrops(True) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.StreamPlayback) self.mediaPlayer.setVolume(80) self.videoWidget = QVideoWidget(self) self.videoWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.videoWidget.setMinimumSize(QSize(640, 360)) self.lbl = QLineEdit('00:00:00') self.lbl.setReadOnly(True) self.lbl.setFixedWidth(70) self.lbl.setUpdatesEnabled(True) self.lbl.setStyleSheet(stylesheet(self)) self.elbl = QLineEdit('00:00:00') self.elbl.setReadOnly(True) self.elbl.setFixedWidth(70) self.elbl.setUpdatesEnabled(True) self.elbl.setStyleSheet(stylesheet(self)) self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setFixedWidth(32) self.playButton.setStyleSheet("background-color: black") self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.positionSlider = QSlider(Qt.Horizontal, self) self.positionSlider.setStyleSheet(stylesheet(self)) self.positionSlider.setRange(0, 100) self.positionSlider.sliderMoved.connect(self.setPosition) self.positionSlider.sliderMoved.connect(self.handleLabel) self.positionSlider.setSingleStep(2) self.positionSlider.setPageStep(20) self.positionSlider.setAttribute(Qt.WA_TranslucentBackground, True) self.clip = QApplication.clipboard() self.process = QProcess(self) self.process.readyRead.connect(self.dataReady) self.process.finished.connect(self.playFromURL) self.myurl = "" # channel list self.channelList = QListView(self) self.channelList.setMinimumSize(QSize(150, 0)) self.channelList.setMaximumSize(QSize(150, 4000)) self.channelList.setFrameShape(QFrame.Box) self.channelList.setObjectName("channelList") self.channelList.setStyleSheet("background-color: black; color: #585858;") self.channelList.setFocus() # for adding items to list must create a model self.model = QStandardItemModel() self.channelList.setModel(self.model) self.controlLayout = QHBoxLayout() self.controlLayout.setContentsMargins(5, 0, 5, 0) self.controlLayout.addWidget(self.playButton) self.controlLayout.addWidget(self.lbl) self.controlLayout.addWidget(self.positionSlider) self.controlLayout.addWidget(self.elbl) self.mainLayout = QHBoxLayout() # contains video and cotrol widgets to the left side self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.layout.addWidget(self.videoWidget) self.layout.addLayout(self.controlLayout) # adds channels list to the right self.mainLayout.addLayout(self.layout) self.mainLayout.addWidget(self.channelList) self.setLayout(self.mainLayout) self.myinfo = "©2020\nTIVOpy v1.0" self.widescreen = True #### shortcuts #### self.shortcut = QShortcut(QKeySequence("q"), self) self.shortcut.activated.connect(self.handleQuit) self.shortcut = QShortcut(QKeySequence("u"), self) self.shortcut.activated.connect(self.playFromURL) self.shortcut = QShortcut(QKeySequence(Qt.Key_Space), self) self.shortcut.activated.connect(self.play) self.shortcut = QShortcut(QKeySequence(Qt.Key_F), self) self.shortcut.activated.connect(self.handleFullscreen) self.shortcut = QShortcut(QKeySequence(Qt.Key_Escape), self) self.shortcut.activated.connect(self.exitFullscreen) self.shortcut.activated.connect(self.handleFullscreen) self.shortcut = QShortcut(QKeySequence("i"), self) self.shortcut.activated.connect(self.handleInfo) self.shortcut = QShortcut(QKeySequence("s"), self) self.shortcut.activated.connect(self.toggleSlider) self.shortcut = QShortcut(QKeySequence(Qt.Key_Right), self) self.shortcut.activated.connect(self.forwardSlider) self.shortcut = QShortcut(QKeySequence(Qt.Key_Left), self) self.shortcut.activated.connect(self.backSlider) self.mediaPlayer.setVideoOutput(self.videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.positionChanged.connect(self.handleLabel) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.error.connect(self.handleError) self.populateChannelList() self.selectChannel() self.initialPlay() def playFromURL(self): self.mediaPlayer.pause() self.myurl = self.clip.text() self.mediaPlayer.setMedia(QMediaContent(QUrl(self.myurl))) self.playButton.setEnabled(True) self.mediaPlayer.play() self.hideSlider() print(self.myurl) def dataReady(self): self.myurl = str(self.process.readAll(), encoding='utf8').rstrip() ### self.myurl = self.myurl.partition("\n")[0] print(self.myurl) self.clip.setText(self.myurl) self.playFromURL() def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPause)) else: self.playButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPlay)) def positionChanged(self, position): self.positionSlider.setValue(position) def durationChanged(self, duration): self.positionSlider.setRange(0, duration) mtime = QTime(0, 0, 0, 0) mtime = mtime.addMSecs(self.mediaPlayer.duration()) self.elbl.setText(mtime.toString()) def setPosition(self, position): self.mediaPlayer.setPosition(position) def handleError(self): self.playButton.setEnabled(False) print("Error: ", self.mediaPlayer.errorString()) def handleQuit(self): self.mediaPlayer.stop() print("Goodbye ...") app.quit() def contextMenuRequested(self, point): menu = QMenu() actionURL = menu.addAction(QIcon.fromTheme("browser"), "URL from Clipboard (u)") menu.addSeparator() actionToggle = menu.addAction(QIcon.fromTheme("next"), "Show / Hide Channels (s)") actionFull = menu.addAction(QIcon.fromTheme("view-fullscreen"), "Fullscreen (f)") menu.addSeparator() actionInfo = menu.addAction(QIcon.fromTheme("help-about"), "About (i)") menu.addSeparator() actionQuit = menu.addAction(QIcon.fromTheme("application-exit"), "Exit (q)") actionQuit.triggered.connect(self.handleQuit) actionFull.triggered.connect(self.handleFullscreen) actionInfo.triggered.connect(self.handleInfo) actionToggle.triggered.connect(self.toggleSlider) actionURL.triggered.connect(self.playFromURL) menu.exec_(self.mapToGlobal(point)) def wheelEvent(self, event): mscale = event.angleDelta().y() / 13 self.mediaPlayer.setVolume(self.mediaPlayer.volume() + mscale) print("Volume: " + str(self.mediaPlayer.volume())) def mouseDoubleClickEvent(self, event): if event.buttons() == Qt.LeftButton: self.handleFullscreen() def handleFullscreen(self): if self.windowState() and Qt.WindowFullScreen: self.showNormal() else: self.showFullScreen() def exitFullscreen(self): self.showNormal() def handleInfo(self): QMessageBox.about(self, "About", self.myinfo) def toggleSlider(self): if self.positionSlider.isVisible(): self.hideSlider() else: self.showSlider() def hideSlider(self): self.channelList.hide() self.playButton.hide() self.lbl.hide() self.positionSlider.hide() self.elbl.hide() def showSlider(self): self.channelList.show() self.playButton.show() self.lbl.show() self.positionSlider.show() self.elbl.show() self.channelList.setFocus() def forwardSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 1000 * 60) def backSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 1000 * 60) def volumeUp(self): self.mediaPlayer.setVolume(self.mediaPlayer.volume() + 10) print("Volume: " + str(self.mediaPlayer.volume())) def volumeDown(self): self.mediaPlayer.setVolume(self.mediaPlayer.volume() - 10) print("Volume: " + str(self.mediaPlayer.volume())) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() elif event.mimeData().hasText(): event.accept() else: event.ignore() def dropEvent(self, event): print("drop") if event.mimeData().hasUrls(): url = event.mimeData().urls()[0].toString() print("url = ", url) self.mediaPlayer.stop() self.mediaPlayer.setMedia(QMediaContent(QUrl(url))) self.playButton.setEnabled(True) self.mediaPlayer.play() elif event.mimeData().hasText(): mydrop = event.mimeData().text() print("generic url = ", mydrop) self.mediaPlayer.setMedia(QMediaContent(QUrl(mydrop))) self.playButton.setEnabled(True) self.mediaPlayer.play() self.hideSlider() def loadFilm(self, f): self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(f))) self.playButton.setEnabled(True) self.mediaPlayer.play() def populateChannelList(self): # file must be in same directory as the script FILEPATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "canaletv.txt") # lines from file with "channel name" -- "link" channelArray = [] # split file by line and adding it to the array with open(FILEPATH) as f: for line in f: channelArray.append(line.rstrip()) # dictionary with key = channel name and value = link self.channelDict = dict(ch.split(" -- ") for ch in channelArray) for channel in self.channelDict.keys(): item = QStandardItem(channel) self.model.appendRow(item) def selectedItemBehavior(self, index): # gets the link for the selected channel and plays it itms = self.channelList.selectedIndexes() for it in itms: channel = it.data() link = self.channelDict[channel] self.mediaPlayer.setMedia(QMediaContent(QUrl(link))) self.play() def selectChannel(self): # selecting channel from sidebar calls selectedItemBehavior self.selModel = self.channelList.selectionModel() self.selModel.selectionChanged.connect(self.selectedItemBehavior) def initialPlay(self): # play somenting when app opens self.mediaPlayer.setMedia(QMediaContent(QUrl("https://vid.hls.protv.ro/proxhdn/proxhd_3_34/index.m3u8?1"))) self.play() def handleLabel(self): self.lbl.clear() mtime = QTime(0, 0, 0, 0) self.time = mtime.addMSecs(self.mediaPlayer.position()) self.lbl.setText(self.time.toString())
class ConfigurationView(QWidget): """ Displays the configuration view. """ def __init__(self, parent=None): super(ConfigurationView, self).__init__(parent) self._layout = QBoxLayout(QBoxLayout.TopToBottom) self.setLayout(self._layout) self._editView = EditView(parent) # initialize list view self._listView = QListView() self._configuration_model = self._get_config_model() self._listView.setModel(self._configuration_model) # initialize detail view self._detailView = QWidget() self._detailLayout = QBoxLayout(QBoxLayout.TopToBottom) self._detailView.setLayout(self._detailLayout) self._detailPanels = {} self._currentDetailPanel = None self._currentConfiguration = None # type: Configuration self._config_wide_print_amounts = {} self._recalculateEffectivePrintAmounts = False # add widgets to layout self._layout.addWidget(QLabel("List of Configurations")) self._layout.addWidget(self._listView) self._layout.addWidget(self._detailView) self._create_detail_view() # hide detail view on start self._detailView.hide() # selected configs map self._selected_configs = {} self._selected_counter = 0 # add event listener for selection change self._listView.clicked.connect(self._on_selection_change) self._listView.selectionModel().currentChanged.connect(self._on_selection_change) def add_configuration(self, configuration): """ Adds the given configuration to the list view and opens the edit view. :param configuration: :type configuration: Configuration """ item = create_new_list_item(configuration.get_name()) self._configuration_model.appendRow(item) self._editView.show_for_configuration(configuration) def select_first_item(self): rect = QRect(0,0,1,1) self._listView.setSelection(rect, QItemSelectionModel.Select) def update_model(self): self._configuration_model = self._get_config_model() self._listView.setModel(self._configuration_model) @staticmethod def _get_config_model(): data = DataStorage() configurations_order = data.get_configurations_order() model = QStandardItemModel() for name in configurations_order: item = create_new_list_item(name) model.appendRow(item) return model def _on_selection_change(self, model_index): """ Called on selecting a new item in the listView. :param model_index: index of selected item :type model_index: QModelIndex """ data = DataStorage() configurations = data.get_configurations() selected_item = self._configuration_model.itemFromIndex(model_index) # type: QStandardItem current_config_name = selected_item.text() current_config = configurations[current_config_name] # type: Configuration self._show_detail_view(current_config) config_wide_print_amount = self._config_wide_print_amounts[current_config_name] material_print_amounts = current_config.get_effective_material_print_amounts( config_wide_print_amount, self._recalculateEffectivePrintAmounts ) self._recalculateEffectivePrintAmounts = False if self._selected_counter == 0: MaterialView.reset_check_state_and_print_amount() for material in current_config.get_materials(): item = get_item(MaterialView.get_model().invisibleRootItem(), material.get_name()) if item is not None: print_amount = material_print_amounts[material.get_name()] if is_checked(selected_item): check_item(item) if current_config_name not in self._selected_configs: print_amount += int(item.text(1)) else: print_amount = int(item.text(1)) item.setText(1, str(print_amount)) if is_checked(selected_item) and current_config_name not in self._selected_configs: self._selected_configs[current_config_name] = True self._selected_counter += 1 if not is_checked(selected_item) and current_config_name in self._selected_configs: self._selected_configs.pop(current_config_name) self._selected_counter -= 1 self._currentConfiguration = current_config def _create_detail_view(self): """ Adds the permanent elements to the detail view. """ edit_button = QPushButton("Edit") edit_button.clicked.connect(self._show_edit_view) self._detailLayout.addWidget(QLabel("Detail view for selected configuration")) self._detailLayout.addWidget(edit_button) def _change_config_wide_print_amount(self, new_value): self._config_wide_print_amounts[self._currentConfiguration.get_name()] = new_value self._recalculateEffectivePrintAmounts = True def _create_update_function_for_sub_configs(self, sub_config, configuration): def update_func(new_value): if self._currentConfiguration.get_name() == configuration.get_name(): self._currentConfiguration.set_config_print_amount(sub_config, new_value) self._recalculateEffectivePrintAmounts = True return update_func def _show_edit_view(self): """ Shows the edit view for the selected configuration. """ self._editView.show_for_configuration(self._currentConfiguration) selected_indexes = self._listView.selectedIndexes() self._on_selection_change(selected_indexes[0]) def _show_detail_view(self, configuration: Configuration): """ Shows the detail view for the selected configuration. :param configuration: :type configuration: Configuration """ if self._currentDetailPanel is not None: self._currentDetailPanel.hide() if configuration.get_name() in self._detailPanels: self._currentDetailPanel = self._detailPanels[configuration.get_name()] self._currentDetailPanel.show() else: panel = QWidget() layout = QFormLayout() panel.setLayout(layout) config_wide_counter = QSpinBox() config_wide_counter.setMinimum(1) config_wide_counter.setValue(1) config_wide_counter.valueChanged.connect(self._change_config_wide_print_amount) # add panel to parent layout self._detailLayout.addWidget(panel) # save panel for future use self._detailPanels[configuration.get_name()] = panel self._currentDetailPanel = panel self._config_wide_print_amounts[configuration.get_name()] = 1 # panel layout.addRow("Print this config x times", config_wide_counter) layout.addRow("Child configurations", QLabel()) configurations = configuration.get_configurations() config_print_amounts = configuration.get_config_print_amounts() for config in configurations: # type: Configuration config_counter = QSpinBox() config_counter.setMinimum(1) config_counter.setValue(config_print_amounts[config.get_name()]) update_func = self._create_update_function_for_sub_configs(config, configuration) config_counter.valueChanged.connect(update_func) layout.addRow("Print config " + config.get_name() + " x times", config_counter) self._detailView.show()
class comic_export_setting_dialog(QDialog): acbfStylesList = [ "speech", "commentary", "formal", "letter", "code", "heading", "audio", "thought", "sign", "sound", "emphasis", "strong" ] def __init__(self): super().__init__() self.setLayout(QVBoxLayout()) self.setWindowTitle(i18n("Export Settings")) buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) mainWidget = QTabWidget() self.layout().addWidget(mainWidget) self.layout().addWidget(buttons) # Set basic crop settings # Set which layers to remove before export. mainExportSettings = QWidget() mainExportSettings.setLayout(QVBoxLayout()) groupExportCrop = QGroupBox(i18n("Crop Settings")) formCrop = QFormLayout() groupExportCrop.setLayout(formCrop) self.chk_toOutmostGuides = QCheckBox(i18n("Crop to outmost guides")) self.chk_toOutmostGuides.setChecked(True) self.chk_toOutmostGuides.setToolTip( i18n( "This will crop to the outmost guides if possible and otherwise use the underlying crop settings." )) formCrop.addRow("", self.chk_toOutmostGuides) btn_fromSelection = QPushButton( i18n("Set Margins from Active Selection")) btn_fromSelection.clicked.connect(self.slot_set_margin_from_selection) # This doesn't work. formCrop.addRow("", btn_fromSelection) self.spn_marginLeft = QSpinBox() self.spn_marginLeft.setMaximum(99999) self.spn_marginLeft.setSuffix(" px") formCrop.addRow(i18n("Left:"), self.spn_marginLeft) self.spn_marginTop = QSpinBox() self.spn_marginTop.setMaximum(99999) self.spn_marginTop.setSuffix(" px") formCrop.addRow(i18n("Top:"), self.spn_marginTop) self.spn_marginRight = QSpinBox() self.spn_marginRight.setMaximum(99999) self.spn_marginRight.setSuffix(" px") formCrop.addRow(i18n("Right:"), self.spn_marginRight) self.spn_marginBottom = QSpinBox() self.spn_marginBottom.setMaximum(99999) self.spn_marginBottom.setSuffix(" px") formCrop.addRow(i18n("Bottom:"), self.spn_marginBottom) groupExportLayers = QGroupBox(i18n("Layers")) formLayers = QFormLayout() groupExportLayers.setLayout(formLayers) self.cmbLabelsRemove = labelSelector() formLayers.addRow(i18n("Label for removal:"), self.cmbLabelsRemove) self.ln_text_layer_name = QLineEdit() self.ln_text_layer_name.setToolTip( i18n( "These are keywords that can be used to identify text layers. A layer only needs to contain the keyword to be recognized. Keywords should be comma separated." )) self.ln_panel_layer_name = QLineEdit() self.ln_panel_layer_name.setToolTip( i18n( "These are keywords that can be used to identify panel layers. A layer only needs to contain the keyword to be recognized. Keywords should be comma separated." )) formLayers.addRow(i18n("Text Layer Key:"), self.ln_text_layer_name) formLayers.addRow(i18n("Panel Layer Key:"), self.ln_panel_layer_name) mainExportSettings.layout().addWidget(groupExportCrop) mainExportSettings.layout().addWidget(groupExportLayers) mainWidget.addTab(mainExportSettings, i18n("General")) # CBZ, crop, resize, which metadata to add. CBZexportSettings = QWidget() CBZexportSettings.setLayout(QVBoxLayout()) self.CBZactive = QCheckBox(i18n("Export to CBZ")) CBZexportSettings.layout().addWidget(self.CBZactive) self.CBZgroupResize = comic_export_resize_widget("CBZ") CBZexportSettings.layout().addWidget(self.CBZgroupResize) self.CBZactive.clicked.connect(self.CBZgroupResize.setEnabled) CBZgroupMeta = QGroupBox(i18n("Metadata to Add")) # CBZexportSettings.layout().addWidget(CBZgroupMeta) CBZgroupMeta.setLayout(QFormLayout()) mainWidget.addTab(CBZexportSettings, i18n("CBZ")) # ACBF, crop, resize, creator name, version history, panel layer, text layers. ACBFExportSettings = QWidget() ACBFform = QFormLayout() ACBFExportSettings.setLayout(QVBoxLayout()) ACBFdocInfo = QGroupBox() ACBFdocInfo.setTitle(i18n("ACBF Document Info")) ACBFdocInfo.setLayout(ACBFform) self.lnACBFID = QLabel() self.lnACBFID.setToolTip( i18n( "By default this will be filled with a generated universal unique identifier. The ID by itself is merely so that comic book library management programs can figure out if this particular comic is already in their database and whether it has been rated. Of course, the UUID can be changed into something else by manually changing the JSON, but this is advanced usage." )) self.spnACBFVersion = QSpinBox() self.ACBFhistoryModel = QStandardItemModel() acbfHistoryList = QListView() acbfHistoryList.setModel(self.ACBFhistoryModel) btn_add_history = QPushButton(i18n("Add History Entry")) btn_add_history.clicked.connect(self.slot_add_history_item) self.chkIncludeTranslatorComments = QCheckBox() self.chkIncludeTranslatorComments.setText( i18n("Include translator's comments")) self.chkIncludeTranslatorComments.setToolTip( i18n( "A PO file can contain translator's comments. If this is checked, the translations comments will be added as references into the ACBF file." )) self.lnTranslatorHeader = QLineEdit() ACBFform.addRow(i18n("ACBF UID:"), self.lnACBFID) ACBFform.addRow(i18n("Version:"), self.spnACBFVersion) ACBFform.addRow(i18n("Version history:"), acbfHistoryList) ACBFform.addRow("", btn_add_history) ACBFform.addRow("", self.chkIncludeTranslatorComments) ACBFform.addRow(i18n("Translator header:"), self.lnTranslatorHeader) ACBFAuthorInfo = QWidget() acbfAVbox = QVBoxLayout(ACBFAuthorInfo) infoLabel = QLabel( i18n( "The people responsible for the generation of the CBZ/ACBF files." )) infoLabel.setWordWrap(True) ACBFAuthorInfo.layout().addWidget(infoLabel) self.ACBFauthorModel = QStandardItemModel(0, 6) labels = [ i18n("Nick Name"), i18n("Given Name"), i18n("Middle Name"), i18n("Family Name"), i18n("Email"), i18n("Homepage") ] self.ACBFauthorModel.setHorizontalHeaderLabels(labels) self.ACBFauthorTable = QTableView() acbfAVbox.addWidget(self.ACBFauthorTable) self.ACBFauthorTable.setModel(self.ACBFauthorModel) self.ACBFauthorTable.verticalHeader().setDragEnabled(True) self.ACBFauthorTable.verticalHeader().setDropIndicatorShown(True) self.ACBFauthorTable.verticalHeader().setSectionsMovable(True) self.ACBFauthorTable.verticalHeader().sectionMoved.connect( self.slot_reset_author_row_visual) AuthorButtons = QHBoxLayout() btn_add_author = QPushButton(i18n("Add Author")) btn_add_author.clicked.connect(self.slot_add_author) AuthorButtons.addWidget(btn_add_author) btn_remove_author = QPushButton(i18n("Remove Author")) btn_remove_author.clicked.connect(self.slot_remove_author) AuthorButtons.addWidget(btn_remove_author) acbfAVbox.addLayout(AuthorButtons) ACBFStyle = QWidget() ACBFStyle.setLayout(QHBoxLayout()) self.ACBFStylesModel = QStandardItemModel() self.ACBFStyleClass = QListView() self.ACBFStyleClass.setModel(self.ACBFStylesModel) ACBFStyle.layout().addWidget(self.ACBFStyleClass) ACBFStyleEdit = QWidget() ACBFStyleEditVB = QVBoxLayout(ACBFStyleEdit) self.ACBFuseFont = QCheckBox(i18n("Use font")) self.ACBFFontList = QListView() self.ACBFFontList.setItemDelegate(font_list_delegate()) self.ACBFuseFont.toggled.connect(self.font_slot_enable_font_view) self.ACBFFontListModel = QStandardItemModel() self.ACBFFontListModel.rowsRemoved.connect( self.slot_font_current_style) self.ACBFFontListModel.itemChanged.connect( self.slot_font_current_style) self.btnAcbfAddFont = QPushButton() self.btnAcbfAddFont.setIcon(Application.icon("list-add")) self.btnAcbfAddFont.clicked.connect(self.font_slot_add_font) self.btn_acbf_remove_font = QPushButton() self.btn_acbf_remove_font.setIcon(Application.icon("edit-delete")) self.btn_acbf_remove_font.clicked.connect(self.font_slot_remove_font) self.ACBFFontList.setModel(self.ACBFFontListModel) self.ACBFdefaultFont = QComboBox() self.ACBFdefaultFont.addItems( ["sans-serif", "serif", "monospace", "cursive", "fantasy"]) acbfFontButtons = QHBoxLayout() acbfFontButtons.addWidget(self.btnAcbfAddFont) acbfFontButtons.addWidget(self.btn_acbf_remove_font) self.ACBFBold = QCheckBox(i18n("Bold")) self.ACBFItal = QCheckBox(i18n("Italic")) self.ACBFStyleClass.clicked.connect(self.slot_set_style) self.ACBFStyleClass.selectionModel().selectionChanged.connect( self.slot_set_style) self.ACBFStylesModel.itemChanged.connect(self.slot_set_style) self.ACBFBold.toggled.connect(self.slot_font_current_style) self.ACBFItal.toggled.connect(self.slot_font_current_style) colorWidget = QGroupBox(self) colorWidget.setTitle(i18n("Text Colors")) colorWidget.setLayout(QVBoxLayout()) self.regularColor = QColorDialog() self.invertedColor = QColorDialog() self.btn_acbfRegColor = QPushButton(i18n("Regular Text"), self) self.btn_acbfRegColor.clicked.connect(self.slot_change_regular_color) self.btn_acbfInvColor = QPushButton(i18n("Inverted Text"), self) self.btn_acbfInvColor.clicked.connect(self.slot_change_inverted_color) colorWidget.layout().addWidget(self.btn_acbfRegColor) colorWidget.layout().addWidget(self.btn_acbfInvColor) ACBFStyleEditVB.addWidget(colorWidget) ACBFStyleEditVB.addWidget(self.ACBFuseFont) ACBFStyleEditVB.addWidget(self.ACBFFontList) ACBFStyleEditVB.addLayout(acbfFontButtons) ACBFStyleEditVB.addWidget(self.ACBFdefaultFont) ACBFStyleEditVB.addWidget(self.ACBFBold) ACBFStyleEditVB.addWidget(self.ACBFItal) ACBFStyleEditVB.addStretch() ACBFStyle.layout().addWidget(ACBFStyleEdit) ACBFTabwidget = QTabWidget() ACBFTabwidget.addTab(ACBFdocInfo, i18n("Document Info")) ACBFTabwidget.addTab(ACBFAuthorInfo, i18n("Author Info")) ACBFTabwidget.addTab(ACBFStyle, i18n("Style Sheet")) ACBFExportSettings.layout().addWidget(ACBFTabwidget) mainWidget.addTab(ACBFExportSettings, i18n("ACBF")) # Epub export, crop, resize, other questions. EPUBexportSettings = QWidget() EPUBexportSettings.setLayout(QVBoxLayout()) self.EPUBactive = QCheckBox(i18n("Export to EPUB")) EPUBexportSettings.layout().addWidget(self.EPUBactive) self.EPUBgroupResize = comic_export_resize_widget("EPUB") EPUBexportSettings.layout().addWidget(self.EPUBgroupResize) self.EPUBactive.clicked.connect(self.EPUBgroupResize.setEnabled) mainWidget.addTab(EPUBexportSettings, i18n("EPUB")) # For Print. Crop, no resize. TIFFExportSettings = QWidget() TIFFExportSettings.setLayout(QVBoxLayout()) self.TIFFactive = QCheckBox(i18n("Export to TIFF")) TIFFExportSettings.layout().addWidget(self.TIFFactive) self.TIFFgroupResize = comic_export_resize_widget("TIFF") TIFFExportSettings.layout().addWidget(self.TIFFgroupResize) self.TIFFactive.clicked.connect(self.TIFFgroupResize.setEnabled) mainWidget.addTab(TIFFExportSettings, i18n("TIFF")) # SVG, crop, resize, embed vs link. #SVGExportSettings = QWidget() #mainWidget.addTab(SVGExportSettings, i18n("SVG")) """ Add a history item to the acbf version history list. """ def slot_add_history_item(self): newItem = QStandardItem() newItem.setText( str(i18n("v{version}-in this version...")).format( version=str(self.spnACBFVersion.value()))) self.ACBFhistoryModel.appendRow(newItem) """ Get the margins by treating the active selection in a document as the trim area. This allows people to snap selections to a vector or something, and then get the margins. """ def slot_set_margin_from_selection(self): doc = Application.activeDocument() if doc is not None: if doc.selection() is not None: self.spn_marginLeft.setValue(doc.selection().x()) self.spn_marginTop.setValue(doc.selection().y()) self.spn_marginRight.setValue(doc.width() - (doc.selection().x() + doc.selection().width())) self.spn_marginBottom.setValue(doc.height() - (doc.selection().y() + doc.selection().height())) """ Add an author with default values initialised. """ def slot_add_author(self): listItems = [] listItems.append(QStandardItem(i18n("Anon"))) # Nick name listItems.append(QStandardItem(i18n("John"))) # First name listItems.append(QStandardItem()) # Middle name listItems.append(QStandardItem(i18n("Doe"))) # Last name listItems.append(QStandardItem()) # email listItems.append(QStandardItem()) # homepage self.ACBFauthorModel.appendRow(listItems) """ Remove the selected author from the author list. """ def slot_remove_author(self): self.ACBFauthorModel.removeRow( self.ACBFauthorTable.currentIndex().row()) """ Ensure that the drag and drop of authors doesn't mess up the labels. """ def slot_reset_author_row_visual(self): headerLabelList = [] for i in range(self.ACBFauthorTable.verticalHeader().count()): headerLabelList.append(str(i)) for i in range(self.ACBFauthorTable.verticalHeader().count()): logicalI = self.ACBFauthorTable.verticalHeader().logicalIndex(i) headerLabelList[logicalI] = str(i + 1) self.ACBFauthorModel.setVerticalHeaderLabels(headerLabelList) """ Set the style item to the gui item's style. """ def slot_set_style(self): index = self.ACBFStyleClass.currentIndex() if index.isValid(): item = self.ACBFStylesModel.item(index.row()) fontUsed = item.data(role=styleEnum.FONT) if fontUsed is not None: self.ACBFuseFont.setChecked(fontUsed) else: self.ACBFuseFont.setChecked(False) self.font_slot_enable_font_view() fontList = item.data(role=styleEnum.FONTLIST) self.ACBFFontListModel.clear() for font in fontList: NewItem = QStandardItem(font) NewItem.setEditable(True) self.ACBFFontListModel.appendRow(NewItem) self.ACBFdefaultFont.setCurrentText( str(item.data(role=styleEnum.FONTGENERIC))) bold = item.data(role=styleEnum.BOLD) if bold is not None: self.ACBFBold.setChecked(bold) else: self.ACBFBold.setChecked(False) italic = item.data(role=styleEnum.ITALIC) if italic is not None: self.ACBFItal.setChecked(italic) else: self.ACBFItal.setChecked(False) """ Set the gui items to the currently selected style. """ def slot_font_current_style(self): index = self.ACBFStyleClass.currentIndex() if index.isValid(): item = self.ACBFStylesModel.item(index.row()) fontList = [] for row in range(self.ACBFFontListModel.rowCount()): font = self.ACBFFontListModel.item(row) fontList.append(font.text()) item.setData(self.ACBFuseFont.isChecked(), role=styleEnum.FONT) item.setData(fontList, role=styleEnum.FONTLIST) item.setData(self.ACBFdefaultFont.currentText(), role=styleEnum.FONTGENERIC) item.setData(self.ACBFBold.isChecked(), role=styleEnum.BOLD) item.setData(self.ACBFItal.isChecked(), role=styleEnum.ITALIC) self.ACBFStylesModel.setItem(index.row(), item) """ Change the regular color """ def slot_change_regular_color(self): if (self.regularColor.exec_() == QDialog.Accepted): square = QPixmap(32, 32) square.fill(self.regularColor.currentColor()) self.btn_acbfRegColor.setIcon(QIcon(square)) """ change the inverted color """ def slot_change_inverted_color(self): if (self.invertedColor.exec_() == QDialog.Accepted): square = QPixmap(32, 32) square.fill(self.invertedColor.currentColor()) self.btn_acbfInvColor.setIcon(QIcon(square)) def font_slot_enable_font_view(self): self.ACBFFontList.setEnabled(self.ACBFuseFont.isChecked()) self.btn_acbf_remove_font.setEnabled(self.ACBFuseFont.isChecked()) self.btnAcbfAddFont.setEnabled(self.ACBFuseFont.isChecked()) self.ACBFdefaultFont.setEnabled(self.ACBFuseFont.isChecked()) if self.ACBFFontListModel.rowCount() < 2: self.btn_acbf_remove_font.setEnabled(False) def font_slot_add_font(self): NewItem = QStandardItem(QFont().family()) NewItem.setEditable(True) self.ACBFFontListModel.appendRow(NewItem) def font_slot_remove_font(self): index = self.ACBFFontList.currentIndex() if index.isValid(): self.ACBFFontListModel.removeRow(index.row()) if self.ACBFFontListModel.rowCount() < 2: self.btn_acbf_remove_font.setEnabled(False) """ Load the UI values from the config dictionary given. """ def setConfig(self, config): if "cropToGuides" in config.keys(): self.chk_toOutmostGuides.setChecked(config["cropToGuides"]) if "cropLeft" in config.keys(): self.spn_marginLeft.setValue(config["cropLeft"]) if "cropTop" in config.keys(): self.spn_marginTop.setValue(config["cropTop"]) if "cropRight" in config.keys(): self.spn_marginRight.setValue(config["cropRight"]) if "cropBottom" in config.keys(): self.spn_marginBottom.setValue(config["cropBottom"]) if "labelsToRemove" in config.keys(): self.cmbLabelsRemove.setLabels(config["labelsToRemove"]) if "textLayerNames" in config.keys(): self.ln_text_layer_name.setText(", ".join( config["textLayerNames"])) else: self.ln_text_layer_name.setText("text") if "panelLayerNames" in config.keys(): self.ln_panel_layer_name.setText(", ".join( config["panelLayerNames"])) else: self.ln_panel_layer_name.setText("panels") self.CBZgroupResize.set_config(config) if "CBZactive" in config.keys(): self.CBZactive.setChecked(config["CBZactive"]) self.EPUBgroupResize.set_config(config) if "EPUBactive" in config.keys(): self.EPUBactive.setChecked(config["EPUBactive"]) self.TIFFgroupResize.set_config(config) if "TIFFactive" in config.keys(): self.TIFFactive.setChecked(config["TIFFactive"]) if "acbfAuthor" in config.keys(): if isinstance(config["acbfAuthor"], list): for author in config["acbfAuthor"]: listItems = [] listItems.append(QStandardItem(author.get("nickname", ""))) listItems.append( QStandardItem(author.get("first-name", ""))) listItems.append(QStandardItem(author.get("initials", ""))) listItems.append(QStandardItem(author.get("last-name", ""))) listItems.append(QStandardItem(author.get("email", ""))) listItems.append(QStandardItem(author.get("homepage", ""))) self.ACBFauthorModel.appendRow(listItems) pass else: listItems = [] listItems.append(QStandardItem( config["acbfAuthor"])) # Nick name for i in range(0, 5): listItems.append(QStandardItem()) # First name self.ACBFauthorModel.appendRow(listItems) if "uuid" in config.keys(): self.lnACBFID.setText(config["uuid"]) elif "acbfID" in config.keys(): self.lnACBFID.setText(config["acbfID"]) else: config["uuid"] = QUuid.createUuid().toString() self.lnACBFID.setText(config["uuid"]) if "acbfVersion" in config.keys(): self.spnACBFVersion.setValue(config["acbfVersion"]) if "acbfHistory" in config.keys(): for h in config["acbfHistory"]: item = QStandardItem() item.setText(h) self.ACBFhistoryModel.appendRow(item) if "acbfStyles" in config.keys(): styleDict = config.get("acbfStyles", {}) for key in self.acbfStylesList: keyDict = styleDict.get(key, {}) style = QStandardItem(key.title()) style.setCheckable(True) if key in styleDict.keys(): style.setCheckState(Qt.Checked) else: style.setCheckState(Qt.Unchecked) fontOn = False if "font" in keyDict.keys() or "genericfont" in keyDict.keys(): fontOn = True style.setData(fontOn, role=styleEnum.FONT) if "font" in keyDict: fontlist = keyDict["font"] if isinstance(fontlist, list): font = keyDict.get("font", QFont().family()) style.setData(font, role=styleEnum.FONTLIST) else: style.setData([fontlist], role=styleEnum.FONTLIST) else: style.setData([QFont().family()], role=styleEnum.FONTLIST) style.setData(keyDict.get("genericfont", "sans-serif"), role=styleEnum.FONTGENERIC) style.setData(keyDict.get("bold", False), role=styleEnum.BOLD) style.setData(keyDict.get("ital", False), role=styleEnum.ITALIC) self.ACBFStylesModel.appendRow(style) keyDict = styleDict.get("general", {}) self.regularColor.setCurrentColor( QColor(keyDict.get("color", "#000000"))) square = QPixmap(32, 32) square.fill(self.regularColor.currentColor()) self.btn_acbfRegColor.setIcon(QIcon(square)) keyDict = styleDict.get("inverted", {}) self.invertedColor.setCurrentColor( QColor(keyDict.get("color", "#FFFFFF"))) square.fill(self.invertedColor.currentColor()) self.btn_acbfInvColor.setIcon(QIcon(square)) else: for key in self.acbfStylesList: style = QStandardItem(key.title()) style.setCheckable(True) style.setCheckState(Qt.Unchecked) style.setData(False, role=styleEnum.FONT) style.setData(QFont().family(), role=styleEnum.FONTLIST) style.setData("sans-serif", role=styleEnum.FONTGENERIC) style.setData(False, role=styleEnum.BOLD) #Bold style.setData(False, role=styleEnum.ITALIC) #Italic self.ACBFStylesModel.appendRow(style) self.CBZgroupResize.setEnabled(self.CBZactive.isChecked()) self.lnTranslatorHeader.setText( config.get("translatorHeader", "Translator's Notes")) self.chkIncludeTranslatorComments.setChecked( config.get("includeTranslComment", False)) """ Store the GUI values into the config dictionary given. @return the config diactionary filled with new values. """ def getConfig(self, config): config["cropToGuides"] = self.chk_toOutmostGuides.isChecked() config["cropLeft"] = self.spn_marginLeft.value() config["cropTop"] = self.spn_marginTop.value() config["cropBottom"] = self.spn_marginRight.value() config["cropRight"] = self.spn_marginBottom.value() config["labelsToRemove"] = self.cmbLabelsRemove.getLabels() config["CBZactive"] = self.CBZactive.isChecked() config = self.CBZgroupResize.get_config(config) config["EPUBactive"] = self.EPUBactive.isChecked() config = self.EPUBgroupResize.get_config(config) config["TIFFactive"] = self.TIFFactive.isChecked() config = self.TIFFgroupResize.get_config(config) authorList = [] for row in range(self.ACBFauthorTable.verticalHeader().count()): logicalIndex = self.ACBFauthorTable.verticalHeader().logicalIndex( row) listEntries = [ "nickname", "first-name", "initials", "last-name", "email", "homepage" ] author = {} for i in range(len(listEntries)): entry = self.ACBFauthorModel.data( self.ACBFauthorModel.index(logicalIndex, i)) if entry is None: entry = " " if entry.isspace() is False and len(entry) > 0: author[listEntries[i]] = entry elif listEntries[i] in author.keys(): author.pop(listEntries[i]) authorList.append(author) config["acbfAuthor"] = authorList config["acbfVersion"] = self.spnACBFVersion.value() versionList = [] for r in range(self.ACBFhistoryModel.rowCount()): index = self.ACBFhistoryModel.index(r, 0) versionList.append( self.ACBFhistoryModel.data(index, Qt.DisplayRole)) config["acbfHistory"] = versionList acbfStylesDict = {} for row in range(0, self.ACBFStylesModel.rowCount()): entry = self.ACBFStylesModel.item(row) if entry.checkState() == Qt.Checked: key = entry.text().lower() style = {} if entry.data(role=styleEnum.FONT): font = entry.data(role=styleEnum.FONTLIST) if font is not None: style["font"] = font genericfont = entry.data(role=styleEnum.FONTGENERIC) if font is not None: style["genericfont"] = genericfont bold = entry.data(role=styleEnum.BOLD) if bold is not None: style["bold"] = bold italic = entry.data(role=styleEnum.ITALIC) if italic is not None: style["ital"] = italic acbfStylesDict[key] = style acbfStylesDict["general"] = { "color": self.regularColor.currentColor().name() } acbfStylesDict["inverted"] = { "color": self.invertedColor.currentColor().name() } config["acbfStyles"] = acbfStylesDict config["translatorHeader"] = self.lnTranslatorHeader.text() config[ "includeTranslComment"] = self.chkIncludeTranslatorComments.isChecked( ) # Turn this into something that retrieves from a line-edit when string freeze is over. config["textLayerNames"] = self.ln_text_layer_name.text().split(",") config["panelLayerNames"] = self.ln_panel_layer_name.text().split(",") return config
class FileManager(QWidget, _HalWidgetBase): def __init__(self, parent=None): super(FileManager, self).__init__(parent) self.title = 'PyQt5 file system view - pythonspot.com' self.left = 10 self.top = 10 self.width = 640 self.height = 480 self.default_path = (os.path.join(os.path.expanduser('~'), 'labvcnc/nc_files/examples')) self.user_path = (os.path.join('/media')) self.currentPath = None self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.model = QFileSystemModel() self.model.setRootPath(QDir.currentPath()) self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files) self.model.setNameFilterDisables(False) self.model.setNameFilters(["*.ngc", '*.py']) self.list = QListView() self.list.setModel(self.model) self.updateDirectoryView(self.default_path) self.list.setWindowTitle("Dir View") self.list.resize(640, 480) self.list.clicked[QModelIndex].connect(self.clicked) self.list.activated.connect(self.load) self.list.setAlternatingRowColors(True) self.cb = QComboBox() self.cb.currentTextChanged.connect(self.filterChanged) self.cb.addItems(sorted({'*.ngc', '*.py', '*'})) #self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button = QPushButton() self.button.setText('Media') self.button.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button.setToolTip('Jump to Media directory') self.button.clicked.connect(self.onMediaClicked) self.button2 = QPushButton() self.button2.setText('User') self.button2.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button2.setToolTip('Jump to labvcnc directory') self.button2.clicked.connect(self.onUserClicked) hbox = QHBoxLayout() hbox.addWidget(self.button) hbox.addWidget(self.button2) hbox.addWidget(self.cb) windowLayout = QVBoxLayout() windowLayout.addWidget(self.list) windowLayout.addLayout(hbox) self.setLayout(windowLayout) self.show() def updateDirectoryView(self, path): self.list.setRootIndex(self.model.setRootPath(path)) def filterChanged(self, text): self.model.setNameFilters([text]) def clicked(self, index): # the signal passes the index of the clicked item dir_path = self.model.filePath(index) if self.model.fileInfo(index).isFile(): self.currentPath = dir_path return root_index = self.model.setRootPath(dir_path) self.list.setRootIndex(root_index) def onMediaClicked(self): self.updateDirectoryView(self.user_path) def onUserClicked(self): self.updateDirectoryView(self.default_path) def select_row(self, style): style = style.lower() selectionModel = self.list.selectionModel() row = selectionModel.currentIndex().row() self.rows = self.model.rowCount(self.list.rootIndex()) if style == 'last': row = self.rows elif style == 'up': if row > 0: row -= 1 else: row = 0 elif style == 'down': if row < self.rows: row += 1 else: row = self.rows else: return top = self.model.index(row, 0, self.list.rootIndex()) selectionModel.setCurrentIndex( top, QItemSelectionModel.Select | QItemSelectionModel.Rows) selection = QItemSelection(top, top) selectionModel.clearSelection() selectionModel.select(selection, QItemSelectionModel.Select) def _hal_init(self): if self.PREFS_: last_path = self.PREFS_.getpref('last_file_path', self.default_path, str, 'BOOK_KEEPING') self.updateDirectoryView(last_path) LOG.debug("lAST FILE PATH: {}".format(last_path)) else: LOG.debug("lAST FILE PATH: {}".format(self.default_path)) self.updateDirectoryView(self.default_path) # get current selection and update the path # then if the path is good load it into labvcnc # record it in the preference file if available def load(self): row = self.list.selectionModel().currentIndex() self.clicked(row) fname = self.currentPath if fname is None: return if fname: if self.PREFS_: self.PREFS_.putpref('last_file_path', fname, str, 'BOOK_KEEPING') ACTION.OPEN_PROGRAM(fname) STATUS.emit('update-machine-log', 'Loaded: ' + fname, 'TIME') def up(self): self.select_row('up') def down(self): self.select_row('down')