class Table(QtWidgets.QMainWindow): def __init__(self, parent=None): super(Table, self).__init__(parent) self.centralwidget = QtWidgets.QWidget(self) self.view = QTableView(self.centralwidget) self.comboBox = QtWidgets.QComboBox() self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.addWidget(self.view, 1, 0, 1, 3) self.setCentralWidget(self.centralwidget) self.model = QtGui.QStandardItemModel(self) self.data = [("Йода.mp3", "dsad", "ddd", ' ', ' '), ('d', 'asd', '1', "asdas", "asdasd"), ("ddd", 'asd', '1', "asdas", "asdasd"), ("ww", 'asd', '1', "asdas", "asdasd")] for rowName in self.data: self.model.invisibleRootItem().appendRow( [QtGui.QStandardItem(rowName[column]) for column in range(5)]) self.model.setHorizontalHeaderLabels([ 'Название', 'Жанр', 'Автор', 'Дата создания', 'Альбом', 'Скачать музыку', 'Удальть музыку' ]) self.proxy = QtCore.QSortFilterProxyModel(self) self.proxy.setSourceModel(self.model) self.view.setModel(self.proxy) self.comboBox.addItems( ["Column {0}".format(x) for x in range(self.model.columnCount())]) self.buttonGroup = QButtonGroup(self) self.buttonGroupDelete = QButtonGroup(self) row = 0 flag = False for tup in self.data: col = 0 for item in tup: cellinfo = QTableWidgetItem(item) cellinfo.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) if (flag == False and col > 3): button = QPushButton("Скачать") self.buttonGroup.addButton(button, row) self.view.setIndexWidget(self.proxy.index(row, 5), button) flag = True col += 1 flag = False row += 1 self.buttonGroup.buttonClicked[int].connect(self.copyMusic) row = 0 flag = False # for tup in self.data: col = 0 for item in tup: cellinfo = QTableWidgetItem(item) cellinfo.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) if (flag == False and col > 3): button = QPushButton("Удалить") self.buttonGroupDelete.addButton(button, row) self.view.setIndexWidget(self.proxy.index(row, 6), button) flag = True col += 1 flag = False row += 1 self.buttonGroupDelete.buttonClicked[int].connect(self.copyMusic) # self.lineEdit.textChanged.connect(self.on_lineEdit_textChanged) # self.comboBox.currentIndexChanged.connect(self.on_comboBox_currentIndexChanged) # self.horizontalHeader = self.view.horizontalHeader() self.horizontalHeader.sectionClicked.connect( self.on_view_horizontalHeader_sectionClicked) @QtCore.pyqtSlot(int) def on_view_horizontalHeader_sectionClicked(self, logicalIndex): self.logicalIndex = logicalIndex self.menuValues = QtWidgets.QMenu(self) self.signalMapper = QtCore.QSignalMapper(self) self.comboBox.blockSignals(True) self.comboBox.setCurrentIndex(self.logicalIndex) self.comboBox.blockSignals(True) valuesUnique = [ self.model.item(row, self.logicalIndex).text() for row in range(self.model.rowCount()) ] actionAll = QtWidgets.QAction("All", self) actionAll.triggered.connect(self.on_actionAll_triggered) self.menuValues.addAction(actionAll) self.menuValues.addSeparator() for actionNumber, actionName in enumerate( sorted(list(set(valuesUnique)))): action = QtWidgets.QAction(actionName, self) self.signalMapper.setMapping(action, actionNumber) action.triggered.connect(self.signalMapper.map) self.menuValues.addAction(action) self.signalMapper.mapped.connect(self.on_signalMapper_mapped) headerPos = self.view.mapToGlobal(self.horizontalHeader.pos()) posY = headerPos.y() + self.horizontalHeader.height() posX = headerPos.x() + self.horizontalHeader.sectionPosition( self.logicalIndex) self.menuValues.exec_(QtCore.QPoint(posX, posY)) @QtCore.pyqtSlot() def on_actionAll_triggered(self): filterColumn = self.logicalIndex filterString = QtCore.QRegExp("", QtCore.Qt.CaseInsensitive, QtCore.QRegExp.RegExp) self.proxy.setFilterRegExp(filterString) self.proxy.setFilterKeyColumn(filterColumn) @QtCore.pyqtSlot(int) def on_signalMapper_mapped(self, i): stringAction = self.signalMapper.mapping(i).text() filterColumn = self.logicalIndex filterString = QtCore.QRegExp(stringAction, QtCore.Qt.CaseSensitive, QtCore.QRegExp.FixedString) self.proxy.setFilterRegExp(filterString) self.proxy.setFilterKeyColumn(filterColumn) @QtCore.pyqtSlot(str) def on_lineEdit_textChanged(self, text): search = QtCore.QRegExp(text, QtCore.Qt.CaseInsensitive, QtCore.QRegExp.RegExp) self.proxy.setFilterRegExp(search) @QtCore.pyqtSlot(int) def on_comboBox_currentIndexChanged(self, index): self.proxy.setFilterKeyColumn(index) def copyMusic(self, row): self.nameMusic = self.view.indexAt(QPoint(0, 30 * row)).data( Qt.DisplayRole) self.albumMusic = self.view.indexAt(QPoint(400, 30 * row)).data( Qt.DisplayRole) self.dirlist = QFileDialog.getExistingDirectory( self, "Выбрать папку", ".") if self.dirlist != "": if (str(self.albumMusic) != ' ' and str(self.albumMusic) != ''): shutil.copy( "C:\\" + self.albumMusic + '\\' + self.nameMusic, # место "E:\\"+self.albumMusic+'\\'+self.nameMusic str(self.dirlist)) # написать директорию с музыкой else: shutil.copy("C:\\" + self.nameMusic, str(self.dirlist)) def deleteMusic(self, row): self.nameMusic = self.view.indexAt(QPoint(0, 30 * row)).data( Qt.DisplayRole) self.albumMusic = self.view.indexAt(QPoint(400, 30 * row)).data( Qt.DisplayRole)
class PacketListWidget(QWidget): on_data_selected = pyqtSignal(QObject) def __init__(self): super().__init__() self.dv = None self.initUI() def showData(self, data): if not self.dv: self.dv = DynamicDataWidget() self.dv.setWindowTitle("Data view") self.dv.setContents(data) self.dv.show() def initUI(self): layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) #tabs = QTabWidget() #layout.addWidget(tabs) self.packetlist = QTableView() self.packetlist.setSortingEnabled(True) self.packetlist.setContextMenuPolicy(Qt.CustomContextMenu) self.packetlist.customContextMenuRequested.connect( self.onPacketlistContextMenu) self.packetlist.horizontalHeader().setContextMenuPolicy( Qt.CustomContextMenu) self.packetlist.horizontalHeader().customContextMenuRequested.connect( self.onHeaderContextMenu) self.packetlist.setSelectionBehavior(QAbstractItemView.SelectRows) self.packetlistmodel = PacketListModel() #self.packetlistmodel.rowsInserted.connect(lambda a,b,c: tabs.setTabText(0, "Raw Frames (%d)"%self.packetlistmodel.rowCount(QModelIndex()))) self.packetlist.setModel(self.packetlistmodel) self.packetlist.selectionModel().selectionChanged.connect( self.onPacketlistSelectionChanged) self.packetlist.selectionModel().currentChanged.connect( self.onPacketlistCurrentChanged) #tabs.addTab(self.packetlist, "Raw Frames") layout.addWidget(self.packetlist) def setContents(self, lstObj): self.listObject = lstObj print("PacketListWidget::setContents", lstObj, len(lstObj)) self.setWindowTitle(str(lstObj)) #for bbuf in lstObj.buffers: # self.addPacketToList(bbuf) self.packetlistmodel.setList(self.listObject) def onPacketlistSelectionChanged(self, selected, deselected): pass def onPacketlistCurrentChanged(self, current, previous): if current.isValid(): bbuf = self.listObject.buffers[current.row()] self.on_data_selected.emit(bbuf) def onPacketlistContextMenu(self, point): index = self.packetlist.indexAt(point) ctx = QMenu("Context menu", self.packetlist) if index.isValid(): bbuf = self.listObject.buffers[index.row()] ctx.addAction("Item details", lambda: self.showData(bbuf)) ctx.addSeparator() ctx.addAction("Select all", lambda: self.packetlist.selectAll()) ctx.exec(self.packetlist.viewport().mapToGlobal(point)) def onHeaderContextMenu(self, point): index = self.packetlist.horizontalHeader().logicalIndexAt(point) print(index) ctx = QMenu("Context menu", self.packetlist) if index > -1: ctx.addAction("Header " + str(index)) ctx.addAction("Edit", lambda: self.onEditColumn(index)) ctx.addAction("Remove column", lambda: self.packetlistmodel.removeColumn(index)) ctx.addSeparator() addIdx = None if index == -1 else index ctx.addAction("Add column ...", lambda: self.onAddColumn(addIdx)) for key in self.listObject.getAllKeys(metadataKeys=True, fieldKeys=False): ctx.addAction(key, lambda key=key: self.packetlistmodel.addColumn( ColumnInfo(key, src="meta"), addIdx)) ctx.addSeparator() for key in self.listObject.getAllKeys(metadataKeys=False, fieldKeys=True): ctx.addAction(key, lambda key=key: self.packetlistmodel.addColumn( ColumnInfo(key, src="field"), addIdx)) ctx.exec(self.packetlist.horizontalHeader().mapToGlobal(point)) def getColumnInfoDefinition(self): return [ ("key", "Key", "text", { "autocomplete": self.listObject.getAllKeys() }), ("title", "Column title", "text", {}), ("src", "Data source", "select", { "options": [("meta", "Packet meta data"), ("field", "Packet field")] }), ("show", "Display mode", "select", { "options": [("show", "Display contents"), ("showname", "Tree display contents"), ("hex", "Hex value")] }), ] def onAddColumn(self, insertBefore): par = showSettingsDlg(self.getColumnInfoDefinition()) if par is not None: if par["title"] == "": par["title"] = par["key"] self.packetlistmodel.addColumn(ColumnInfo(**par), insertBefore) def onEditColumn(self, index): par = showSettingsDlg(self.getColumnInfoDefinition(), self.packetlistmodel.columns[index].toDict()) if par is not None: if par["title"] == "": par["title"] = par["key"] self.packetlistmodel.removeColumn(index) self.packetlistmodel.addColumn(ColumnInfo(**par), index) def run_ndis(self): pass def addPacketToList(self, bbuf): idx = self.packetlist.rowCount() self.packetlist.insertRow(idx) c = 0 #print(bbuf.ranges) for k, v in bbuf.metadata.items(): #print(k,v) self.packetlist.setItem(idx, c, QTableWidgetItem(str(v))) c += 1 if c > 10: break for rr in bbuf.ranges: #print(rr) self.packetlist.setItem(idx, c, QTableWidgetItem(str(rr.metadata))) c += 1 if c > 10: break
class FileManager(QWidget): def __init__(self, parent): QWidget.__init__(self) self.parent = parent self.name = 'File Manager' self.port = '9080' self.server = None drives = win32api.GetLogicalDriveStrings().split('\\\000')[:-1] self.logical_drives = drives + [d+'/' for d in drives] # create file manager tab self.file_manager_layout = QGridLayout(self) # create left manager (PC) self.left_up_btn = QPushButton() self.left_up_btn.setIcon(QIcon('images/up_btn.png')) self.left_up_btn.setFixedWidth(25) self.file_manager_layout.addWidget(self.left_up_btn, 0, 0, 1, 1) self.left_dir_path = QLineEdit(self.parent.expanduser_dir) self.file_manager_layout.addWidget(self.left_dir_path, 0, 1, 1, 8) self.left_go_to_btn = QPushButton() self.left_go_to_btn.setIcon(QIcon('images/right_btn.png')) self.left_go_to_btn.setFixedWidth(25) self.file_manager_layout.addWidget(self.left_go_to_btn, 0, 9, 1, 1) self.lefttableview = QTableView() self.lefttableview.setSelectionBehavior(QTableView.SelectRows) self.lefttableview.verticalHeader().hide() self.lefttableview.setShowGrid(False) self.lefttableview.contextMenuEvent = lambda event: self.left_context(event) self.left_file_model = QFileSystemModel() self.left_file_model.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot) self.left_file_model.setRootPath(self.parent.expanduser_dir) self.left_file_model_path = self.parent.expanduser_dir self.lefttableview.setModel(self.left_file_model) self.lefttableview.setColumnWidth(0, 150) self.lefttableview.setRootIndex(self.left_file_model.index(self.parent.expanduser_dir)) self.file_manager_layout.addWidget(self.lefttableview, 1, 0, 5, 10) # central buttons self.download_file_from_device_btn = QPushButton() self.download_file_from_device_btn.setIcon(QIcon('images/left_btn.png')) self.download_file_from_device_btn.setFixedWidth(30) self.download_file_from_device_btn.setEnabled(False) self.upload_file_to_device_btn = QPushButton() self.upload_file_to_device_btn.setIcon(QIcon('images/right_btn.png')) self.upload_file_to_device_btn.setFixedWidth(30) self.upload_file_to_device_btn.setEnabled(False) self.delete_file_btn = QPushButton() self.delete_file_btn.setIcon(QIcon('images/delete_btn.png')) self.delete_file_btn.setFixedWidth(30) self.file_manager_layout.addWidget(self.download_file_from_device_btn, 3, 10, 1, 1) self.file_manager_layout.addWidget(self.delete_file_btn, 4, 10, 1, 1) # create right manager (Device) self.right_up_btn = QPushButton() self.right_up_btn.setIcon(QIcon('images/up_btn.png')) self.right_up_btn.setFixedWidth(25) self.right_up_btn.setEnabled(False) self.file_manager_layout.addWidget(self.right_up_btn, 0, 11, 1, 1) self.add_folder_btn = QPushButton() self.add_folder_btn.setIcon(QIcon('images/folder_add.png')) self.add_folder_btn.setFixedWidth(25) self.add_folder_btn.setToolTip(_('Add new folder')) self.add_folder_btn.setEnabled(False) self.file_manager_layout.addWidget(self.add_folder_btn, 0, 12, 1, 1) self.right_dir_path = QLineEdit() self.file_manager_layout.addWidget(self.right_dir_path, 0, 13, 1, 7) self.right_update_btn = QPushButton() self.right_update_btn.setIcon(QIcon('images/update.png')) self.right_update_btn.setFixedWidth(25) self.file_manager_layout.addWidget(self.right_update_btn, 0, 20, 1, 1) self.righttableview = QTableView() self.righttableview.setSelectionBehavior(QTableView.SelectRows) self.righttableview.contextMenuEvent = lambda event: self.right_context(event) self.righttableview.verticalHeader().hide() self.righttableview.setShowGrid(False) self.right_file_model = QStandardItemModel() self.right_file_model_path = [] self.right_active_dir = None self.righttableview.setModel(self.right_file_model) self.file_manager_layout.addWidget(self.righttableview, 1, 11, 5, 10) # auto sync self.timer = QTimer() self.timer.setInterval(10000) self.file_models_auto_sync = QCheckBox(_('Auto sync')) self.left_file_model_auto_sync_label = QLineEdit() self.left_file_model_auto_sync_label.setReadOnly(True) self.right_file_model_auto_sync_label = QLineEdit() self.right_file_model_auto_sync_label.setReadOnly(True) self.file_manager_layout.addWidget(self.file_models_auto_sync, 6, 9, 1, 3, alignment=Qt.AlignCenter) self.file_manager_layout.addWidget(self.left_file_model_auto_sync_label, 6, 0, 1, 9) self.file_manager_layout.addWidget(self.right_file_model_auto_sync_label, 6, 12, 1, 9) self.timer.timeout.connect(lambda: self.check_device_sync()) self.lefttableview.clicked.connect(lambda idx: self.left_file_model_clicked(idx)) self.lefttableview.doubleClicked.connect(lambda idx: self.left_file_model_doubleclicked(idx)) self.left_up_btn.clicked.connect(lambda: self.left_file_model_up(self.left_file_model.index(self.left_dir_path.text()))) self.left_go_to_btn.clicked.connect(lambda: self.left_file_model_go_to_dir()) self.right_update_btn.clicked.connect(lambda: self.right_file_model_update()) self.righttableview.doubleClicked.connect(lambda idx: self.right_file_model_doubleclicked(idx)) self.right_up_btn.clicked.connect(lambda: self.right_file_model_up()) self.add_folder_btn.clicked.connect(lambda: self.right_file_model_add_folder()) self.righttableview.clicked.connect(lambda idx: self.right_file_model_clicked(idx)) self.download_file_from_device_btn.clicked.connect(lambda: self.download_file_from_device()) self.upload_file_to_device_btn.clicked.connect(lambda: self.upload_file_to_device()) self.delete_file_btn.clicked.connect(lambda: self.delete_file_from_file_model()) self.parent.settings_widget.signal_ip_changed.connect(lambda ip: self.change_ip(ip)) self.parent.signal_language_changed.connect(lambda: self.retranslate()) def retranslate(self): self.file_models_auto_sync.setText(_('Auto sync')) self.right_file_model.setHorizontalHeaderLabels([_('Name'), _('Size'), _('Changed date')]) def change_ip(self, ip): self.server = ':'.join([ip, self.port]) self.right_file_model_path = [] self.right_file_model.clear() def left_file_model_clicked(self, idx): if os.path.isfile(self.left_file_model.filePath(idx)) and self.parent.geoshark_widget.device_on_connect: self.upload_file_to_device_btn.setEnabled(True) else: self.upload_file_to_device_btn.setEnabled(False) def left_file_model_doubleclicked(self, idx): self.left_up_btn.setEnabled(True) fileinfo = self.left_file_model.fileInfo(idx) if fileinfo.isDir(): self.lefttableview.setRootIndex(idx) self.left_dir_path.setText(self.left_file_model.filePath(idx)) self.left_file_model_path = self.left_file_model.filePath(idx) def left_file_model_up(self, idx): self.upload_file_to_device_btn.setEnabled(False) if self.left_dir_path.text() in self.logical_drives: self.left_file_model = QFileSystemModel() self.left_file_model.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot) self.left_file_model.setRootPath('') self.lefttableview.setModel(self.left_file_model) self.left_dir_path.setText('My computer') self.left_up_btn.setEnabled(False) else: fileinfo = self.left_file_model.fileInfo(idx) dir = fileinfo.dir() self.left_dir_path.setText(dir.path()) self.left_file_model_path = dir.path() self.lefttableview.setRootIndex(self.left_file_model.index(dir.absolutePath())) def left_file_model_go_to_dir(self): if os.path.isdir(self.left_dir_path.text()): self.left_file_model_path = self.left_dir_path.text() self.left_up_btn.setEnabled(True) self.upload_file_to_device_btn.setEnabled(False) self.left_file_model.setRootPath(self.left_dir_path.text()) self.lefttableview.setRootIndex(self.left_file_model.index(self.left_dir_path.text())) def right_file_model_update(self): if not self.parent.geoshark_widget.device_on_connect: return url = 'http://{}/active_dir'.format(self.server) try: res = requests.get(url, timeout=5) if res.ok: self.right_active_dir = res.text except requests.exceptions.RequestException: pass file_list = self.get_folder_list() if file_list is None: return self.fill_right_file_model(file_list) self.download_file_from_device_btn.setEnabled(False) def get_folder_list(self, folder_path=None): if self.server is None: return if folder_path is None: folder_path = '/'.join(self.right_file_model_path) url = 'http://{}/data/{}'.format(self.server, folder_path) try: res = requests.get(url, timeout=1) except requests.exceptions.RequestException: show_error(_('GeoShark error'), _('GeoShark is not responding.')) return if res.ok: res = res.json() return res else: return None def check_device_sync(self): pc_path = self.left_file_model_auto_sync_label.text() device_path = self.right_file_model_auto_sync_label.text() if self.file_models_auto_sync.isChecked() and pc_path != '' and device_path != '': file_list = self.get_folder_list(self.right_file_model_auto_sync_label.text()) left_list_of_files = os.listdir(self.left_file_model_auto_sync_label.text()) for f in file_list: if f['name'] not in left_list_of_files or os.path.getsize('{}/{}'.format(pc_path, f['name'])) != f['size']: self.download_file_from_device(device_path='{}/{}'.format(device_path, f['name']), pc_path=pc_path) def fill_right_file_model(self, directory): self.add_folder_btn.setEnabled(True) if len(self.right_file_model_path) < 1: self.right_up_btn.setEnabled(False) else: self.right_up_btn.setEnabled(True) self.add_folder_btn.setEnabled(False) self.right_file_model.removeRows(0, self.right_file_model.rowCount()) self.right_dir_path.setText('/'.join(self.right_file_model_path)) self.right_file_model.setHorizontalHeaderLabels([_('Name'), _('Size'), _('Changed date')]) for row, instance in enumerate(directory): if instance['name'] == self.right_active_dir: image = QIcon('images/directory_active.png') else: image = QIcon('images/{}.png'.format(instance['type'])) item = QStandardItem(image, instance['name']) item.setData(instance['type'], 5) item.setEditable(False) self.right_file_model.setItem(row, 0, item) item = QStandardItem(str(instance['size'])) item.setEditable(False) self.right_file_model.setItem(row, 1, item) item = QStandardItem(str(datetime.datetime.fromtimestamp(instance['changed']).strftime('%d.%m.%Y %H:%M'))) item.setEditable(False) self.right_file_model.setItem(row, 2, item) self.righttableview.setColumnWidth(0, max(150, self.righttableview.columnWidth(0))) def left_context(self, event): context_menu = {} index = self.lefttableview.indexAt(event.pos()) if index.row() == -1: return context_menu[_('Set active directory')] = lambda: self.set_pc_active_directory(self.left_file_model.filePath(index)) context_menu[_('Remove element')] = lambda: self.delete_file_from_file_model(index) if not self.left_file_model.isDir(index): del context_menu[_('Set active directory')] menu = QMenu() actions = [QAction(a) for a in context_menu.keys()] menu.addActions(actions) action = menu.exec_(event.globalPos()) if action: context_menu[action.text()]() def set_pc_active_directory(self, path): self.left_file_model_auto_sync_label.setText(path) self.parent.settings_widget.left_folder_tracked.setText(path) def right_context(self, event): context_menu = {} index = self.righttableview.indexAt(event.pos()) if index.row() == -1: return item = self.right_file_model.itemFromIndex(index) item_row = item.row() context_menu[_('Set active directory')] = lambda: self.set_active_directory(item) context_menu[_('Remove element')] = lambda: self.delete_file_from_file_model(index) if self.right_file_model.item(item_row, 0).data(5) != 'directory': del context_menu[_('Set active directory')] menu = QMenu() actions = [QAction(a) for a in context_menu.keys()] menu.addActions(actions) action = menu.exec_(event.globalPos()) if action: context_menu[action.text()]() def set_active_directory(self, item): if not self.parent.geoshark_widget.device_on_connect: return dirname = item.text() url = 'http://{}/active_dir'.format(self.server) try: res = requests.post(url=url, data=dirname, timeout=5) except requests.exceptions.RequestException: show_error(_('GeoShark error'), _('Can not set active directory.\nGeoShark is not responding.')) return if res.ok: self.right_file_model_update() self.set_active_path(dirname) elif res.status_code == 400: show_error(_('GeoShark error'), _('Request declined - request body specifies invalid path.')) return elif res.status_code == 409: show_error(_('GeoShark error'), _('Request declined - switching active directory is forbidden during active session.')) return else: print(res.status_code) return def set_active_path(self, dirname): path = '/'.join(self.right_file_model_path + [dirname]) self.parent.settings_widget.right_folder_tracked.setText(path) self.right_file_model_auto_sync_label.setText(path) def right_file_model_clicked(self, idx): if not self.parent.geoshark_widget.device_on_connect: return if self.right_file_model.item(idx.row(), 0).data(5) == 'file': self.download_file_from_device_btn.setEnabled(True) else: self.download_file_from_device_btn.setEnabled(False) def right_file_model_doubleclicked(self, idx): if not self.parent.geoshark_widget.device_on_connect: return model_path = '/'.join(self.right_file_model_path) idx_name = self.right_file_model.item(idx.row(), 0).text() if model_path != '': dir = '{}/{}'.format(model_path, idx_name) else: dir = '{}'.format(idx_name) file_list = self.get_folder_list(dir) if file_list is None: return self.right_file_model_path = dir.split('/') self.fill_right_file_model(file_list) def right_file_model_up(self): if not self.parent.geoshark_widget.device_on_connect: return self.download_file_from_device_btn.setEnabled(False) up_dir = '/'.join(self.right_file_model_path[:-1]) file_list = self.get_folder_list(up_dir) if file_list is None: return if up_dir == '': self.right_file_model_path = [] else: self.right_file_model_path = up_dir.split('/') self.fill_right_file_model(file_list) def right_file_model_add_folder(self): if not self.parent.geoshark_widget.device_on_connect: return row = self.right_file_model.rowCount() item = QStandardItem(QIcon('images/folder.png'), 'New Directory') item.setData('directory', 5) item.setEditable(True) self.right_file_model.setItem(row, 0, item) item = QStandardItem(str(0.0)) item.setEditable(False) self.right_file_model.setItem(row, 1, item) item = QStandardItem(str(datetime.datetime.today().strftime('%d.%m.%Y %H:%M'))) item.setEditable(False) self.right_file_model.setItem(row, 2, item) def download_file_from_device(self, device_path=None, pc_path=None): if not self.parent.geoshark_widget.device_on_connect or self.server is None: return if not device_path: fileName = self.find_selected_idx() if fileName: fileName = fileName.data() device_path = '/'.join(self.right_file_model_path + [fileName]) else: return right_file_model_filename = device_path.split('/')[-1] save_to_file = '{}/{}'.format(self.left_file_model_path, right_file_model_filename) \ if not pc_path else '{}/{}'.format(pc_path, right_file_model_filename) if os.path.isfile(save_to_file): answer = show_warning_yes_no(_('File warning'), _('There is a file with the same name in PC.\n' 'Do you want to rewrite <b>{}</b>?'.format(right_file_model_filename))) if answer == QMessageBox.No: return url = 'http://{}/data/{}'.format(self.server, device_path) try: b = bytearray() res = requests.get(url, timeout=5, stream=True) if res.ok: progress = QProgressBar() progress.setFormat(right_file_model_filename) self.file_manager_layout.addWidget(progress, 6, 12, 1, 9) total_length = int(res.headers.get('content-length')) len_b = 0 for chunk in tee_to_bytearray(res, b): len_b += len(chunk) progress.setValue((len_b/total_length)*99) QApplication.processEvents() else: return except: self.file_manager_layout.addWidget(self.right_file_model_auto_sync_label, 6, 12, 1, 9) show_error(_('GeoShark error'), _('GeoShark is not responding.')) return if res.ok: progress.setValue(100) with open(save_to_file, 'wb') as file: file.write(b) for i in reversed(range(self.file_manager_layout.count())): if isinstance(self.file_manager_layout.itemAt(i).widget(), QProgressBar): self.file_manager_layout.itemAt(i).widget().setParent(None) self.file_manager_layout.addWidget(self.right_file_model_auto_sync_label, 6, 12, 1, 9) def upload_file_to_device(self): if not self.parent.geoshark_widget.device_on_connect or self.server is None: return file = self.left_file_model.filePath(self.lefttableview.currentIndex()) filename = file.split('/')[-1] url = 'http://{}/data/{}'.format(self.server, '/'.join(self.right_file_model_path)) filesize = os.path.getsize(file) if filesize == 0: show_error(_('File error'), _('File size must be non zero.')) return progress = ProgressBar(text=_('Upload File Into GeoShark'), window_title=_('Upload file to GeoShark')) encoder = MultipartEncoder( fields={'upload_file': (filename, open(file, 'rb'))} # added mime-type here ) data = MultipartEncoderMonitor(encoder, lambda monitor: progress.update((monitor.bytes_read/filesize)*99)) try: res = requests.post(url, data=data, headers={'Content-Type': encoder.content_type}, timeout=5) except requests.exceptions.RequestException: progress.close() show_error(_('GeoShark error'), _('GeoShark is not responding.')) return if res.ok: progress.update(100) self.right_file_model_update() def delete_file_from_file_model(self, index=None): selected = self.find_selected_idx() if index is None and selected is None: return if index is None: index = selected model = index.model() index_row = index.row() path = model.filePath(index) if hasattr(model, 'filePath') else model.index(index_row, 0).data() answer = show_warning_yes_no(_('Remove File warning'), _('Do you really want to remove:\n{}').format(path)) if answer == QMessageBox.No: return if isinstance(model, QFileSystemModel): model.remove(index) elif isinstance(model, QStandardItemModel): if not self.parent.geoshark_widget.device_on_connect or self.server is None: return filename = self.right_file_model.item(index.row(), 0).text() path = '/'.join(self.right_file_model_path + [filename]) url = 'http://{}/data/{}'.format(self.server, path) try: res = requests.delete(url) except requests.exceptions.RequestException: show_error(_('GeoShark error'), _('GeoShark is not responding.')) return if res.ok: self.right_file_model_update() elif res.status_code == 400: self.right_file_model.removeRow(index.row()) elif res.status_code == 409: show_error(_('GeoShark error'), _('Request declined - directory is the part of active session working directory.')) return def find_selected_idx(self): left_indexes = self.lefttableview.selectedIndexes() right_indexes = self.righttableview.selectedIndexes() if len(left_indexes) == 0 and len(right_indexes) == 0: return None index = left_indexes[0] if len(left_indexes) > len(right_indexes) else right_indexes[0] return index def save_file_models_folder(self): self.left_file_model_auto_sync_label.setText(self.parent.settings_widget.left_folder_tracked.text()) self.right_file_model_auto_sync_label.setText(self.parent.settings_widget.right_folder_tracked.text())
class ERUploaderWindow(QDialog): """This window provides the user a visual picture of the local and online status of the Extra Reflectance calibration file repository. It also allows uploading of files that are present locally but not on the server. It does not have good handling of edge cases, e.g. online server in inconsistent state.""" def __init__(self, manager: ERManager, parent: Optional[QWidget] = None): self._dataComparator = ERDataComparator(manager.onlineDirectory, manager.localDirectory) self._manager = manager self._selectedId: str = None super().__init__(parent) self.setModal(False) self.setWindowTitle("Extra Reflectance File Manager") self.setLayout(QVBoxLayout()) self.table = QTableView(self) self.fileStatus = self._dataComparator.compare() self.table.setModel(PandasModel(self.fileStatus)) self.table.setSelectionMode(QTableView.SingleSelection) self.table.setSelectionBehavior(QTableView.SelectRows) self.table.customContextMenuRequested.connect(self.openContextMenu) self.table.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.uploadButton = QPushButton("Upload to Drive") self.uploadButton.released.connect(self._updateGDrive) self.uploadButton.setToolTip( "Upload any files for which the status is `Local Only` to the google drive account." ) self.refreshButton = QPushButton('Refresh') self.refreshButton.setToolTip( "Rescan the files in the applications data directory.") self.refreshButton.released.connect(self.refresh) self.updateIndexButton = QPushButton("Update Index File") self.updateIndexButton.setToolTip( "Download the online index file and merge it with our local index file." ) self.updateIndexButton.released.connect(self._updateIndexFile) self.layout().addWidget(self.table) l = QHBoxLayout() l.setContentsMargins(0, 0, 0, 0) l.addWidget(self.uploadButton) l.addWidget(self.updateIndexButton) l.addWidget(self.refreshButton) w = QWidget() w.setLayout(l) self.layout().addWidget(w) self.table.setColumnWidth(0, 300) self.table.setColumnWidth(1, 150) self.table.setColumnWidth(2, 150) self.table.setMinimumWidth( sum( self.table.columnWidth(i) for i in range(self.table.model().columnCount())) + self.table.verticalHeader().width() + 20) def displayInfo(self, index: QModelIndex): msg = QMessageBox.information(self, 'Info', repr(self.fileStatus.iloc[index.row()])) def plotData(self, index: QModelIndex): idTag = self.fileStatus.iloc[index.row()]['idTag'] md = self._dataComparator.local.getMetadataFromId(idTag) erCube = ExtraReflectanceCube.fromMetadata(md) self.plotHandle = PlotNd(erCube.data) def openContextMenu(self, pos: QPoint): """This method opens a context menu, it should be called when the user right clicks.""" index = self.table.indexAt(pos) row = self.fileStatus.iloc[index.row()] menu = QMenu() displayAction = QAction("Display Info") displayAction.triggered.connect(lambda: self.displayInfo(index)) menu.addAction(displayAction) if row['Local Status'] == self._dataComparator.local.DataStatus.found.value: plotAction = QAction("Plot Local Data") plotAction.triggered.connect(lambda: self.plotData(index)) menu.addAction(plotAction) menu.exec(self.mapToGlobal(pos)) def _updateGDrive(self): """Checks for all files taht are present locally but not on the server. Uploads those file and then overwrites the index.""" try: status = self.fileStatus if not np.all((status['Index Comparison'] == ERDataComparator.ComparisonStatus.LocalOnly.value) | (status['Index Comparison'] == ERDataComparator.ComparisonStatus.Match.value)): raise ValueError( "Uploading cannot be performed if the local index file is not valid. Try updating the index file." ) uploadableRows = ( status['Index Comparison'] == ERDataComparator.ComparisonStatus.LocalOnly.value) | ( status['Online Status'] == ERDataDirectory.DataStatus.missing.value) if np.any(uploadableRows): # There is something to upload for i, row, in status.loc[uploadableRows].iterrows(): fileName = [ i.fileName for i in self._dataComparator.local.index.cubes if i.idTag == row['idTag'] ][0] self._manager.upload(fileName) self._manager.upload('index.json') self.refresh() except Exception as e: logger = logging.getLogger(__name__) logger.exception(e) mess = QMessageBox.information(self, 'Sorry', str(e)) def refresh(self): """Scans local and online files to refresh the display.""" self._dataComparator.updateIndexes() self.fileStatus = self._dataComparator.compare() self.table.setModel(PandasModel(self.fileStatus)) def _updateIndexFile(self): self._dataComparator.online.updateIndex() index = ERIndex.merge(self._dataComparator.local.index, self._dataComparator.online.index) self._dataComparator.local.saveNewIndex(index) self.refresh()
class CustomTableWidget(QWidget): """ DESCRIPTION ----------- This is custom table widget. Public functions: 1) populate(data: ndarray or hdf5) Public slots: 1) fill_results(text: str, data: ndarray or hdf5) -> filling the cells 2) draw_plot(data: ndarray of hdf5) -> creates plot by 2 selected sections in table """ def __init__(self, model=None): super().__init__() # create the table self.table = QTableView(self) self.table.resizeColumnsToContents() # defining the model if model is None: self.model = QStandardItemModel() else: self.model = model # setting model to the table self.table.setModel(self.model) # disable edit on cells self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) # layout setting for widget self.myLay = QVBoxLayout() self.myLay.addWidget(self.table) self.setLayout(self.myLay) def __paint_column(self, data): """ DESCRIPTION ----------- This is private function for painting cells. If value of cell is postive -> red cell, otherwise it will be painted to green. """ for i in range(len(data[:, 0])): if data[:, 0][i] >= 0: self.model.setData(self.model.index(i, 0), QBrush(Qt.red), QtCore.Qt.BackgroundRole) else: self.model.setData(self.model.index(i, 0), QBrush(Qt.green), QtCore.Qt.BackgroundRole) def populate(self, data=None): """ This function fills the table depending on the data that was passed to it. Additionally, two columns are created to display aggregation results. The last column displays the sum of the rows in each cell. The penultimate is the sum of columns in each cell of the column. """ # clear the model data self.table.model().clear() # setting value from data to each cell for i in range(len(data)): row = [] for j in range(len(data[i] + 2)): if j < len(data) - 1: cell = QStandardItem(str(data[i][j])) else: cell = QStandardItem('0') row.append(cell) self.model.appendRow(row) # adding QComboBox to each cell in the last column for row in range(len(data)): c = QComboBox() c.addItems([ '1', '2', '3', '4', '5', ]) # getting the indexes in the table i = self.table.model().index(row, len(data[row]) - 1) # setting the QComboBox by index self.table.setIndexWidget(i, c) # setting the default QComboBox text if it in (0, 5] if 0 < data[row, -1] <= 5: self.table.indexWidget(i).setCurrentIndex(data[row, -1] - 1) self.model.setData(i, self.table.indexWidget(i).currentText()) # filling the results columns data[row, -1] = int(c.currentText()) self.model.setItem(row, len(data[row]) + 1, QStandardItem(str(np.sum(data[row])))) self.model.setItem(row, len(data[row]), QStandardItem(str(np.sum(data[:, row])))) # connecting to slot when text is changed self.table.indexWidget(i).currentTextChanged.connect( lambda text: self.fill_results(data, text)) # painting the first column self.__paint_column(data) # drawing plot when sections clicked self.table.horizontalHeader().sectionClicked.connect( lambda arg: self.draw_plot(arg, data)) def fill_results(self, data, text): """This function is PyQT slot and fills the last column of the table filling rule: sum """ # calling the sender widget = self.sender() # getting table row and column by widget position in QTableView index = self.table.indexAt(widget.pos()) row = index.row() column = index.column() # filling cells in last column data[row, -1] = int(text) self.model.setItem(row, len(data[row]) + 1, QStandardItem(str(np.sum(data[row])))) # filling cells in penult column (each cell rule: sum of columns) max_rows = len(data) - 1 self.model.setItem(max_rows, column + 1, QStandardItem(str(np.sum(data[:, column])))) def draw_plot(self, *args): """ This function is PyQT slot. Draws plot by given data """ # preventing results columns drawing try: cols = [] # getting selected columns indexes = self.table.selectionModel().selectedColumns(0) for index in indexes: col = index.column() cols.append(col) # drawing a plot if (len(cols) > 1) and (cols[0] != cols[-1]): x = args[1][:, cols[0]] y = args[1][:, cols[-1]] self.parent().guiplot.clear() self.parent().guiplot.plot(x, y) except: pass
class MainWindow1(QMainWindow, MainWindowUI): # Переопределяем конструктор класса def __init__(self): # Обязательно нужно вызвать метод супер класса QMainWindow.__init__(self) self.setMinimumSize(QSize(608, 684)) self.previousClick = 0 self.selected = [] selectBtn = QPushButton('Select', self) selectBtn.move(10,10) restartBtn = QPushButton('Restart', self) restartBtn.move(30, 30) central_widget = QWidget(self) # Создаём центральный виджет self.setCentralWidget(central_widget) # Устанавливаем центральный виджет grid_layout = QGridLayout() # Создаём QGridLayout central_widget.setLayout(grid_layout) # Устанавливаем данное размещение в центральный виджет self.table = QTableView(self) self.table.setGeometry(30, 30, 580, 660) self.model = QtGui.QStandardItemModel(5, 3, self) self.game = Game(5,9) for i in range(self.game.height): for j in range(self.game.width): self.model.setItem(i, j, QtGui.QStandardItem()) color = self.define_color(self.game.matrix[i][j]) self.model.item(i, j).setBackground(color) self.table.setModel(self.model) grid_layout.addWidget(selectBtn, 0, 0) grid_layout.addWidget(restartBtn,1,0) grid_layout.addWidget(self.table, 0, 1) # Добавляем таблицу в сетку def new_mouse_press_event(e: QMouseEvent) -> None: idx = self.table.indexAt(e.pos()) self.on_item_clicked(idx, e) self.table.mousePressEvent = new_mouse_press_event def init_game_field(self): self.game = Game(5,9) for i in range(self.game.height): for j in range(self.game.width): self.table.setItem(i, j, QTableWidgetItem()) color = self.define_color(self.game.matrix[i][j]) self.table.item(i, j).setBackground(color) def define_color(self, color): if color == Color.BLUE: return QtGui.QColor(0,0,255) if color == Color.GREEN: return QtGui.QColor(0,255,0) if color == Color.RED: return QtGui.QColor(255,0,0) if color == Color.PRINCE: return QtGui.QColor(205,205,205) if color == Color.PRINCESS: return QtGui.QColor(235,155,235) def on_item_clicked(self, e: QModelIndex, me: QMouseEvent = None) -> None: if me.button() == Qt.LeftButton: self.left_mouse_click(e.row(), e.column()) def left_mouse_click(self, row, col) -> None: if self.previousClick == 0: self.previousClick = [int(row), int(col)] #self.table.item(row, col).setFocusPolicy(Qt.NoFocus) else: if math.fabs(self.previousClick[0] - int(row)) + math.fabs(self.previousClick[1] - int(col)) != 1: self.selected = [] raise Exception("Последовательность выделена неверна") self.selected.append([row, col]) self.previousClick = [int(row), int(col)]