def main(): app = QApplication() window = QMainWindow() window.setMinimumSize(QSize(640, 480)) imageFlow = FlowWidget(window) proxy = QSortFilterProxyModel() proxy.setFilterRole(FlowModel.FileNameRole) proxy.setSortRole(FlowModel.FileNameRole) imageFlow.setProxyModel(proxy) searchFilter = QLineEdit() searchFilter.textChanged.connect( lambda text: proxy.setFilterWildcard(text)) layout = QVBoxLayout() layout.addWidget(searchFilter) layout.addWidget(imageFlow) widget = QWidget() widget.setLayout(layout) window.setCentralWidget(widget) window.show() # 画像を同期読み込み # for i, filePath in enumerate(glob.glob('C:/tmp/test_images2/*.png')): # image = QImage(filePath).scaled(100, 100) # item = FlowItem(filePath) # item.setImage(image) # imageFlow.appendItem(item) # 画像を非同期読み込み loader = BatchImageLoader() loader.addCallback(ImageLoadingCallback.LOADED, lambda img: img.scaled(100, 100)) tasks = {} def _on_load_image(taskId): filePath = tasks[taskId] image = loader.image(taskId) item = FlowItem(filePath, image) imageFlow.appendItem(item) def _on_load_complete(): proxy.sort(0) loader.loaded.connect(_on_load_image) loader.completed.connect(_on_load_complete) for filePath in glob.iglob('C:/tmp/test_images/*.png'): taskId = loader.addFile(filePath) tasks[taskId] = filePath loader.loadAsync() sys.exit(app.exec_())
class QStringTable(QTableView): def __init__(self, parent, selection_callback=None): super(QStringTable, self).__init__(parent) self._selected = selection_callback self._filter = None self.setSelectionBehavior(QAbstractItemView.SelectRows) self.setShowGrid(False) self.verticalHeader().setVisible(False) self.verticalHeader().setDefaultSectionSize(24) self.setHorizontalScrollMode(self.ScrollPerPixel) self._model = QStringModel(None) self._proxy = QSortFilterProxyModel(self) self._proxy.setSourceModel(self._model) self._proxy.setFilterCaseSensitivity(Qt.CaseInsensitive) self.setModel(self._proxy) self.setSortingEnabled(True) self.setSelectionMode(QAbstractItemView.SingleSelection) # let the last column (string) fill table width self.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed) self.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch) self.doubleClicked.connect(self._on_string_selected) # # Properties # @property def cfg(self): return self._model.cfg @cfg.setter def cfg(self, v): self._model.cfg = v self.fast_resize() @property def xrefs(self): return self._model.xrefs @xrefs.setter def xrefs(self, v): self._model.xrefs = v @property def function(self): return self._model.function @function.setter def function(self, v): self._model.function = v self.fast_resize() @property def filter_string(self): return self._filter @filter_string.setter def filter_string(self, v): self._filter = v if isinstance(v, re.Pattern): self._proxy.setFilterRegExp(self._filter.pattern) else: self._proxy.setFilterWildcard(self._filter) self._proxy.setFilterKeyColumn(2) # # Public methods # def fast_resize(self): self.setVisible(False) self.resizeColumnsToContents() self.setVisible(True) # # Event handlers # def _on_string_selected(self, model_index): model_index = self._proxy.mapToSource(model_index) selected_index = model_index.row() if self._model is None: return if 0 <= selected_index < len(self._model.values): selected_item = self._model.values[selected_index] else: selected_item = None if self._selected is not None: self._selected(selected_item)
class PlaylistView(QTableView): current_index_changed = Signal(QModelIndex) playlist_double_clicked = Signal() filtering = Signal(str) unfiltered = Signal(str) next = Slot(int) previous = Slot(int) @property def mime_Index(self): return 'application/x-original_index' @property def mime_URLS(self): return 'application/x-file-urls' @property def mime_url_count(self): return 'application/x-urls-count' @property def url_delimiter(self): return '\n' @property def open_file_filter(self): return '*.mp4 *.m4v *.mov *.mpg *.mpeg *. mp3 *.m4a *.wmv *.aiff *.wav' def __init__(self, parent=None): super(PlaylistView, self).__init__(parent) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setDragEnabled(True) self.setAcceptDrops(True) self.setDragDropMode(QAbstractItemView.DragDrop) self.setDropIndicatorShown(True) self.proxy_model = QSortFilterProxyModel(self) self.proxy_model.setSourceModel(PlaylistModel(self)) self.setModel(self.proxy_model) # self.setModel(PlaylistModel()) self.setShowGrid(False) self.setSelectionBehavior(QAbstractItemView.SelectRows) self.verticalHeader().setDefaultSectionSize(16) self.verticalHeader().hide() self.horizontalHeader().setMinimumSectionSize(30) self.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive) self.current_index = QModelIndex() self.previousIndex = QModelIndex() self.rubberBand: QRubberBand = QRubberBand(QRubberBand.Rectangle, self) self.isDragging = False self.wasSelected = False self.context_menu = QMenu(self) self.create_context_menu() # self.current_index_changed.connect(self.proxy_model.sourceModel().set_current_index) self.current_index_changed.connect( self.proxy_model.sourceModel().set_current_index) def create_context_menu(self): add_file = createAction(self, 'Add File(s)', self.open) delete_selected = createAction(self, 'Delete selected', self.delete_items) sort_action = createAction(self, 'Sort', self.proxy_model.sourceModel().sort) pickup_dup_action = createAction(self, 'Filter by same title', self.filter_same_title) stop_filtering_action = createAction(self, 'Stop Filtering', self.unfilter) self.context_menu.addActions([ add_file, delete_selected, sort_action, pickup_dup_action, stop_filtering_action ]) def contextMenuEvent(self, event): self.context_menu.exec_(event.globalPos()) def count(self): return self.proxy_model.sourceModel().rowCount() def open(self): list, _ = QFileDialog.getOpenFileNames(self, 'Open File', QDir.homePath()) for path in list: if path[-3:] == 'm3u': self.load(path) else: self.add_item(path) def open_directory(self): directory_url = QFileDialog.getExistingDirectory( self, '0Open directory', QDir.homePath()) dir = QDir(directory_url) filters = [ '*.mp4', '*.m4v', '*.mov', '*.mpg', '*.mpeg', '*.mp3', '*.m4a', '*.wmv', '*.wav', '*.aiff' ] dir.setNameFilters(filters) file_list = dir.entryList() path = dir.absolutePath() + '/' for file in file_list: self.add_item(path + file) def save(self, path=None): """プレイリストを保存する。 :param file :QFile 出力するようのファイル fileが指定されていれば、fileに内容を書き込み、 指定がなければ、ダイアログで名前を指定してそこにファイルを保存。 """ if path is None: return with open(path, 'wt') as fout: for i in range(self.proxy_model.sourceModel().rowCount()): index = self.proxy_model.sourceModel().index(i, 0) print(self.url(index).toLocalFile(), file=fout) return True def load(self, path=None): """プレイリストを読み込む pathが与えられた場合は、そこから読み込み、 ない場合は、何も読み込まない。""" with open(path, 'rt') as fin: for line in fin: self.add_item(line[:-1]) # 最後の改行文字を取り除く def add_item(self, path): if is_media(path): self.proxy_model.sourceModel().add(QUrl.fromLocalFile(path)) return True return False def current_url(self): return self.url(self.current_index) def current_title(self): return self.title(self.current_index) def next(self, step=1): if self.current_row() + step < self.count(): self.set_current_index_from_row(self.current_row() + step) return self.url(self.current_index) else: return None def previous(self, step=1): if self.current_row() - step >= 0: self.set_current_index_from_row(self.current_row() - step) return self.url(self.current_index) else: return None def selected(self): selected_indexes = self.selectedIndexes() if len(selected_indexes) > 0: return selected_indexes[0] else: return None def current_row(self): return self.current_index.row() def url(self, index): if isinstance(index, int): row = index if 0 <= row < self.count(): index = self.proxy_model.sourceModel().index(row, 0) if isinstance(index, QModelIndex): return self.proxy_model.sourceModel().data(index) else: return None def title(self, index): if isinstance(index, int): row = index if 0 <= row < self.count(): index = self.proxy_model.sourceModel().index(row, 0) if isinstance(index, QModelIndex): return self.proxy_model.sourceModel().data(index, Qt.DisplayRole) else: return None def set_current_index_from_row(self, row): new_index = self.proxy_model.sourceModel().index(row, 0) return self.set_current_index(new_index) def set_current_index(self, new_index: QModelIndex): self.current_index = new_index self.current_index_changed.emit(new_index) def deactivate(self): self.set_current_index(QModelIndex()) def auto_resize_header(self): """auto resize Header width on table view. """ width = self.viewport().width() duration_width = 120 self.horizontalHeader().resizeSection(0, width - duration_width) self.horizontalHeader().resizeSection(1, duration_width) def mousePressEvent(self, event): """左クリックされたらカーソル下にある要素を選択し、ドラッグを認識するために現在の位置を保存する。 :param event: QMousePressEvent :return: nothing """ self.isDragging = False if Qt.LeftButton == event.button(): self.dragStartPosition = event.pos() index = self.indexAt(self.dragStartPosition) if index in self.selectedIndexes(): self.isDragging = True self.wasSelected = True return self.rubberBand.setGeometry(QRect(self.dragStartPosition, QSize())) self.rubberBand.show() super(PlaylistView, self).mousePressEvent(event) def mouseMoveEvent(self, event): """start Drag and prepare for Drop. :type event: QMoveEvent マウスを動かした嶺がQApplication.startDragDistance()を超えると、Drag開始されたと認識し、 そのための準備を行う。QMimeDataを使って、データをやりとりする。 """ if not (event.buttons() & Qt.LeftButton): return if (event.pos() - self.dragStartPosition).manhattanLength() \ < QApplication.startDragDistance(): return if self.isDragging: indexes = self.selectedIndexes() urls = self.url_list(indexes) mimeData = QMimeData() # mimeData.setData(self.mime_URLS, convert_to_bytearray(urls)) mimeData.setUrls(urls) file_icon = self.style().standardIcon(QStyle.SP_FileIcon) pixmap = file_icon.pixmap(32, 32) drag = QDrag(self) drag.setMimeData(mimeData) drag.setPixmap(pixmap) drag.setHotSpot(QPoint(0, 0)) dropAction = drag.exec_(Qt.CopyAction | Qt.MoveAction, Qt.CopyAction) if dropAction == Qt.MoveAction: pass else: self.rubberBand.setGeometry( QRect(self.dragStartPosition, event.pos()).normalized()) super(PlaylistView, self).mouseMoveEvent(event) def mouseReleaseEvent(self, event): '''マウスを離したときにQRubberBandを隠す。 左クリックをpress と release がだいたい同じ位置であれば、その要素を1つだけ選択する。 :param event: ''' self.rubberBand.hide() if Qt.LeftButton == event.button( ) and Qt.NoModifier == event.modifiers(): if self.indexAt(event.pos()).row() == -1 and \ self.indexAt(self.dragStartPosition).row() == -1: self.clearSelection() elif len(self.selectedIndexes() ) / 2 == 1 and self.wasSelected == True: self.clearSelection() elif (event.pos() - self.dragStartPosition).manhattanLength() \ < QApplication.startDragDistance(): self.setCurrentIndex(self.indexAt(event.pos())) self.wasSelected = False super(PlaylistView, self).mouseReleaseEvent(event) def dragEnterEvent(self, event): """ドラッグした状態でWidgetに入った縁で呼ばれる関数。 :param event: QDragEvent :return: nothing イベントが発生元と発生しているWidgetが同一の場合はMoveActionにする。それ以外はCopyAction。 その二つの場合は受け入れられるように、accept()もしくはacceptProposedAction()を呼ぶ。 """ if event.mimeData().hasUrls() or event.mimeData().hasFormat( self.mime_URLS): if event.source() is self: event.setDropAction(Qt.MoveAction) event.accept() else: event.acceptProposedAction() else: event.ignore() def dragMoveEvent(self, event): """ドラッグした状態でWidget内を移動したときに呼ばれる。 :param event: QDragMoveEvent :return: nothing ドラッグしている要素の背景の色を変えて、どこにファイルがDropされるかをグラデーションした背景で 表現する。 """ if event.mimeData().hasUrls() or event.mimeData().hasFormat( self.mime_URLS): self.rubberBand.setGeometry( self.rectForDropIndicator( self.index_for_dropping_pos(event.pos()))) self.rubberBand.show() self.previousIndex = self.indexAt(event.pos()) if event.source() is self: event.setDropAction(Qt.MoveAction) event.accept() else: event.acceptProposedAction() else: event.ignore() def dragLeaveEvent(self, event): """ドラッグしたままWidget内を出たときにドラッグ下にあった要素の背景色の色を元に戻す。 :param event: QDragLeaveEvent :return: nothing """ self.rubberBand.hide() def dropEvent(self, event): """Dropされたらデータを取り出して、新たに登録する。 :param event: QDropEvent :return: nothing ファイルへのパスと移動前に登録してあった要素のindexを取り出す。 """ self.rubberBand.hide() if event.mimeData().hasUrls() or event.mimeData().hasFormat( self.mime_URLS): if event.mimeData().hasUrls(): urls = event.mimeData().urls() else: urls = convert_from_bytearray(event.mimeData().data( self.mime_URLS)) index = self.index_for_dropping_pos(event.pos()) if event.source() is self: self.move_items(self.selectedIndexes(), index) event.setDropAction(Qt.MoveAction) event.accept() else: self.add_items(urls) event.acceptProposedAction() else: event.ignore() def mouseDoubleClickEvent(self, event): if event.button() == Qt.LeftButton: new_index = self.indexAt(event.pos()) if not new_index.isValid(): return self.selectRow(new_index.row()) self.playlist_double_clicked.emit() def add_items(self, items: [QUrl], start: int = -1): """渡された要素をmodelに追加する。 :param items: 追加する項目 :param start: 追加するindexを表す。初期値は-1 start に −1を渡すと一番後ろに追加する。 """ if isinstance(items, QUrl): self.proxy_model.sourceModel().add(items) elif start == -1: for item in items: self.proxy_model.sourceModel().add(item) else: for item, i in items, range(start, len(items)): self.proxy_model.sourceModel().add(item, i) def delete_items(self): """渡されたインデックスを順番に消していく。 :param indexes: 消すためのインデックス """ indexes = self.selectedIndexes() if indexes: self.proxy_model.sourceModel().remove_items(indexes) else: return def move_items(self, indexes: [QModelIndex], dest: QModelIndex): self.proxy_model.sourceModel().move(indexes, dest.row()) def filter_same_title(self): dup = self.proxy_model.sourceModel().pickup_same_title() re = QRegularExpression('|'.join(dup)) self.proxy_model.setFilterRegularExpression(re) self.filtering.emit(' - filtered') def unfilter(self): self.proxy_model.setFilterWildcard('*') self.unfiltered.emit('') def index_for_dropping_pos(self, pos: QPoint) -> QModelIndex: """dropした場所のindexを返す。ただし、要素の高さ半分より下にある場合は、下の要素を返す。 :param pos: :return: posから導き出されたindex 挿入や移動のために、要素の間を意識している。 """ index = self.indexAt(pos) if index.row() < 0: new_index = self.proxy_model.sourceModel().index( self.proxy_model.sourceModel().rowCount(), 0) return new_index item_rect = self.visualRect(index) pos_in_rect = pos.y() - item_rect.top() if pos_in_rect < (item_rect.height() / 2): return index else: return self.proxy_model.sourceModel().index(index.row() + 1, 0) def rectForDropIndicator(self, index: QModelIndex) -> QRect: """QRubberBand を DropIndicatorとして表示するためのQRectを返す。 Geometryに渡されるので、表示位置となるようにQRectを作成する。 幅が表示領域、縦1pixelの棒で表示する。 """ item_rect = self.visualRect(index) top_left = item_rect.topLeft() size = QSize(item_rect.width(), 3) return QRect(top_left, size) def url_list(self, indexes): urls = [] for index in indexes: urls.append(self.proxy_model.sourceModel().data(index)) return sorted(set(urls), key=urls.index)
class MainWindow(QMainWindow): createUpload = Signal(list, htauthcontroller.HTAuthorizationController, str, list) def __init__(self): super(MainWindow, self).__init__() self.hyperthoughtui = HyperthoughtDialogImpl() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.TabWidget.setCurrentWidget(self.ui.CreateTemplateTab) self.ui.actionHelp.triggered.connect(self.help) self.ui.actionOpenPackage.triggered.connect(self.openPackage) self.ui.actionSave_Package.triggered.connect(self.savePackageAs) self.ui.actionClose.triggered.connect(self.close) self.ui.actionSave_Template.triggered.connect(self.saveTemplate) self.ui.actionOpen_Template.triggered.connect(self.restoreTemplate) self.ui.dataFileSelect.clicked.connect(self.selectFile) self.ui.hyperthoughtTemplateSelect.clicked.connect(self.selectTemplate) self.ui.saveTemplateButton.clicked.connect(self.saveTemplate) self.ui.otherDataFileSelect.clicked.connect(self.extractFile) self.ui.hyperthoughtUploadButton.clicked.connect( self.uploadToHyperthought) self.setAcceptDrops(True) self.numCustoms = 0 self.customInputs = [] self.templateFilePath = "" aTree = {} self.createtablemodel = TableModelC(aTree, self) self.filterModel = FilterModel(self) self.filterModel.setSourceModel(self.createtablemodel) self.ui.metadataTableView.setModel(self.filterModel) self.ui.metadataTableView.horizontalHeader().setSectionResizeMode( self.createtablemodel.K_SOURCE_COL_INDEX, QHeaderView.ResizeToContents) self.ui.metadataTableView.horizontalHeader().setSectionResizeMode( self.createtablemodel.K_HTNAME_COL_INDEX, QHeaderView.ResizeToContents) self.ui.metadataTableView.horizontalHeader().setSectionResizeMode( self.createtablemodel.K_SOURCEVAL_COL_INDEX, QHeaderView.ResizeToContents) self.ui.metadataTableView.horizontalHeader().setSectionResizeMode( self.createtablemodel.K_HTVALUE_COL_INDEX, QHeaderView.ResizeToContents) self.ui.metadataTableView.setColumnWidth( self.createtablemodel.K_USESOURCE_COL_INDEX, self.width() * .1) self.checkboxDelegate = CheckBoxDelegate() self.createtrashDelegate = TrashDelegate() self.ui.metadataTableView.setItemDelegateForColumn( self.createtablemodel.K_USESOURCE_COL_INDEX, self.checkboxDelegate) self.ui.metadataTableView.setItemDelegateForColumn( self.createtablemodel.K_EDITABLE_COL_INDEX, self.checkboxDelegate) self.ui.metadataTableView.setItemDelegateForColumn( self.createtablemodel.K_REMOVE_COL_INDEX, self.createtrashDelegate) self.ui.metadataTableView.setColumnWidth( self.createtablemodel.K_REMOVE_COL_INDEX, self.width() * .05) self.treeModel = TreeModel(["Available File Metadata"], aTree, self.createtablemodel) self.ui.metadataTreeView.setModel(self.treeModel) self.treeModel.checkChanged.connect(self.filterModel.checkList) self.createtrashDelegate.pressed.connect(self.handleRemoveCreate) self.editableKeys = [] self.usetablemodel = TableModelU(self, [], self.editableKeys) self.usefilterModel = FilterModelU(self) self.usefilterModel.setSourceModel(self.usetablemodel) self.ui.useTemplateTableView.setModel(self.usefilterModel) self.ui.useTemplateTableView.setColumnWidth( self.usetablemodel.K_HTKEY_COL_INDEX, self.width() * .25) self.ui.useTemplateTableView.setColumnWidth( self.usetablemodel.K_HTVALUE_COL_INDEX, self.width() * .25) self.ui.useTemplateTableView.setColumnWidth( self.usetablemodel.K_SOURCE_COL_INDEX, self.width() * .25) self.ui.useTemplateTableView.setColumnWidth( self.usetablemodel.K_USESOURCE_COL_INDEX, self.width() * .1) self.ui.useTemplateTableView.setColumnWidth( self.usetablemodel.K_HTANNOTATION_COL_INDEX, self.width() * .1) self.usetrashDelegate = TrashDelegate() self.ui.useTemplateTableView.setItemDelegateForColumn( self.usetablemodel.K_USESOURCE_COL_INDEX, self.checkboxDelegate) self.ui.useTemplateTableView.setItemDelegateForColumn( self.usetablemodel.K_REMOVE_COL_INDEX, self.usetrashDelegate) self.ui.useTemplateTableView.setColumnWidth( self.usetablemodel.K_REMOVE_COL_INDEX, self.width() * .075) self.usetrashDelegate.pressed.connect(self.handleRemoveUse) self.uselistmodel = ListModel(self, self.usetablemodel, []) self.ui.useTemplateListView.setModel(self.uselistmodel) self.uselistmodel.rowRemoved.connect(self.toggleButtons) self.uselistmodel.rowAdded.connect(self.toggleButtons) self.useFileDelegate = UseFileDelegate(self) self.ui.useTemplateListView.setItemDelegate(self.useFileDelegate) self.ui.useTemplateListView.clicked.connect( self.removeRowfromUsefileType) self.addAppendButton() self.ui.TabWidget.currentChanged.connect(self.movethedamnbutton) self.appendSourceFilesButton.clicked.connect(self.addFile) self.ui.appendCreateTableRowButton.clicked.connect( self.addCreateTableRow) self.ui.appendUseTableRowButton.clicked.connect(self.addUseTableRow) self.ui.hyperthoughtLocationButton.clicked.connect( self.hyperthoughtui.exec) self.ui.usetableSearchBar.textChanged.connect(self.filterUseTable) self.ui.createTemplateListSearchBar.textChanged.connect( self.filterCreateTable) self.ui.createTemplateTreeSearchBar.textChanged.connect( self.filterCreateTree) self.ui.addMetadataFileCheckBox.stateChanged.connect( self.checkFileList) self.fileType = "" self.accessKey = "" self.folderuuid = "" self.mThread = QThread() self.uploader = Uploader() self.uploader.moveToThread(self.mThread) self.mThread.start() self.createUpload.connect(self.uploader.performUpload) self.hyperthoughtui.apiSubmitted.connect(self.acceptKey) self.hyperthoughtui.finished.connect(self.getLocation) self.ui.hyperthoughtTemplateLineEdit.installEventFilter(self) self.ui.otherDataFileLineEdit.installEventFilter(self) self.ui.dataFileLineEdit.installEventFilter(self) def acceptKey(self, apikey): self.accessKey = apikey def addCreateTableRow(self): self.createtablemodel.addEmptyRow(self.numCustoms) self.numCustoms += 1 def addFile(self): linetexts = QFileDialog.getOpenFileNames( self, self.tr("Select File"), QStandardPaths.displayName(QStandardPaths.HomeLocation), self.tr("Files (*.ctf *.xml *.ang)"))[0] for line in linetexts: self.uselistmodel.addRow(line) self.toggleButtons() def addAppendButton(self): self.appendSourceFilesButton = QToolButton(self.ui.useTemplateListView) icon = QApplication.style().standardIcon(QStyle.SP_FileIcon) def addUseTableRow(self): self.usetablemodel.addEmptyRow() def checkFileList(self, checked): if checked == Qt.Checked: if self.ui.otherDataFileLineEdit.text() != "": self.uselistmodel.addRow(self.ui.otherDataFileLineEdit.text()) elif checked == Qt.Unchecked: if self.ui.otherDataFileLineEdit.text( ) in self.uselistmodel.metadataList: rowIndex = self.uselistmodel.metadataList.index( self.ui.otherDataFileLineEdit.text()) self.uselistmodel.removeRow(rowIndex) def closeEvent(self, event): self.mThread.quit() self.mThread.wait(250) def extractFile(self, fileLink=False): if fileLink == False: linetext = QFileDialog.getOpenFileName( self, self.tr("Select File"), QStandardPaths.displayName(QStandardPaths.HomeLocation), self.tr("Files (*" + self.fileType + ")"))[0] else: linetext = fileLink if linetext != "": self.setWindowTitle(linetext) self.ui.dataTypeText.setText(linetext.split(".")[1].upper()) self.ui.otherDataFileLineEdit.setText(linetext) if self.ui.addMetadataFileCheckBox.checkState() == Qt.Checked: self.uselistmodel.removeAllRows() self.uselistmodel.addRow(linetext) self.toggleButtons() if self.ui.fileParserCombo.findText( linetext.split(".")[1].upper() + " Parser") != -1: headerDict = {} self.ui.fileParserCombo.setCurrentIndex( self.ui.fileParserCombo.findText( linetext.split(".")[1].upper() + " Parser")) if linetext.split(".")[1].upper() == "CTF": headerDict = ctf.parse_header_as_dict(linetext) elif linetext.split(".")[1].upper() == "ANG": headerDict = ang.parse_header_as_dict(linetext) elif linetext.split(".")[1].upper() == "XML": print("XML Parser used") if self.templatedata: self.usetablemodel.metadataList = [] self.usefilterModel = FilterModelU(self) self.usefilterModel.setSourceModel(self.usetablemodel) self.unusedTreeModel = TreeModelU(["Available File Metadata"], headerDict, self.usetablemodel, self.editableKeys) self.templatelist = [] self.templatesources = [] for i in range(len(self.templatedata)): self.templatelist.append(self.templatedata[i]) if "Custom Input" not in self.templatedata[i]["Source"]: self.templatesources.append("/".join( self.templatedata[i]['Source'].split("/")[1:])) else: self.usetablemodel.addExistingRow(self.templatedata[i]) self.usesearchFilterModel = QSortFilterProxyModel(self) self.usesearchFilterModel.setSourceModel(self.usefilterModel) self.usesearchFilterModel.setFilterKeyColumn(0) self.usesearchFilterModel.setDynamicSortFilter(True) self.ui.useTemplateTableView.setModel( self.usesearchFilterModel) self.toggleButtons() def eventFilter(self, object, event): if object == self.ui.hyperthoughtTemplateLineEdit: if event.type() == QEvent.DragEnter: if str(event.mimeData().urls()[0])[-5:-2] == ".ez": event.acceptProposedAction() if (event.type() == QEvent.Drop): if str(event.mimeData().urls()[0])[-5:-2] == ".ez": event.acceptProposedAction() self.loadTemplateFile( event.mimeData().urls()[0].toLocalFile()) if object == self.ui.otherDataFileLineEdit: if event.type() == QEvent.DragEnter: if str(event.mimeData().urls()[0])[-6:-2] == self.fileType: event.acceptProposedAction() if (event.type() == QEvent.Drop): if str(event.mimeData().urls()[0])[-6:-2] == self.fileType: event.acceptProposedAction() self.extractFile(event.mimeData().urls()[0].toLocalFile()) if object == self.ui.dataFileLineEdit: if event.type() == QEvent.DragEnter: if str(event.mimeData().urls()[0])[-6:-2] == ".ctf" or str( event.mimeData().urls()[0])[-6:-2] == ".ang": event.acceptProposedAction() if (event.type() == QEvent.Drop): if str(event.mimeData().urls()[0])[-6:-2] == ".ctf" or str( event.mimeData().urls()[0])[-6:-2] == ".ang": event.acceptProposedAction() self.selectFile(event.mimeData().urls()[0].toLocalFile()) return QMainWindow.eventFilter(self, object, event) def filterCreateTable(self): self.createTableSearchFilterModel.invalidate() self.createTableSearchFilterModel.setFilterCaseSensitivity( Qt.CaseInsensitive) self.createTableSearchFilterModel.setFilterWildcard( "*" + self.ui.createTemplateListSearchBar.text() + "*") def filterCreateTree(self): self.createTreeSearchFilterModel.invalidate() self.createTreeSearchFilterModel.setFilterCaseSensitivity( Qt.CaseInsensitive) self.createTreeSearchFilterModel.setFilterWildcard( "*" + self.ui.createTemplateTreeSearchBar.text() + "*") def filterUseTable(self): self.usesearchFilterModel.invalidate() self.usesearchFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.usesearchFilterModel.setFilterWildcard( "*" + self.ui.usetableSearchBar.text() + "*") def getLocation(self): remoteDirPath = self.hyperthoughtui.getUploadDirectory() self.folderuuid = ht_requests.get_ht_id_path_from_ht_path( self.hyperthoughtui.authcontrol, ht_path=remoteDirPath) self.ui.hyperthoughtLocationLineEdit.setText(remoteDirPath) self.toggleButtons() def handleRemoveCreate(self, source, filterIndex, tableIndex): if "Custom Input" in source: for i in range(len(self.createtablemodel.metadataList)): if self.createtablemodel.metadataList[i]["Source"] == source: self.createtablemodel.beginRemoveRows(QModelIndex(), i, i) del self.createtablemodel.metadataList[i] self.createtablemodel.endRemoveRows() break else: self.treeModel.changeLeafCheck(source) def handleRemoveUse(self, source, listIndex, filterIndex): self.usetablemodel.beginRemoveRows(QModelIndex(), listIndex.row(), listIndex.row()) del self.usetablemodel.metadataList[listIndex.row()] self.usetablemodel.endRemoveRows() def help(self): QDesktopServices.openUrl("http://www.bluequartz.net/") def movethedamnbutton(self): self.appendSourceFilesButton.move( self.ui.useTemplateListView.width() - self.appendSourceFilesButton.width() - 15, self.ui.useTemplateListView.height() - self.appendSourceFilesButton.height()) def openPackage(self): linetext = QFileDialog.getOpenFileName( self, self.tr("Select File"), QStandardPaths.displayName(QStandardPaths.HomeLocation), self.tr("Files (*.ezpak)"))[0] if linetext != "": infile = open(linetext, "r") self.loadTemplateFile(infile.readline()[1:-2]) extractedFile = infile.readline()[1:-2] fileList = infile.readline() fileList = json.loads(fileList) self.fileList = fileList[:] self.uselistmodel = ListModel(self, self.usetablemodel, self.fileList) self.ui.useTemplateListView.setModel(self.uselistmodel) self.extractFile(extractedFile) self.uselistmodel.removeAllRows() for i in range(len(fileList)): self.uselistmodel.addRow(fileList[i]) self.toggleButtons() infile.close() self.ui.TabWidget.setCurrentIndex(1) def restoreTemplate(self): #Clear data on create side self.createtablemodel.metadataList = [] self.createtablemodel.hiddenList = [] self.filterModel.displayed = [] #open template linetext = QFileDialog.getOpenFileName( self, self.tr("Select File"), QStandardPaths.displayName(QStandardPaths.HomeLocation), self.tr("Files (*.ez)"))[0] if linetext != "": infile = open(linetext, "r") infile.readline() fileType = infile.readline() self.fileType = json.loads(fileType) infile.readline() newList = infile.readline() newList = json.loads(newList) newDict = infile.readline() newDict = json.loads(newDict) self.ui.dataTypeText.setText(self.fileType[0][-3:].upper()) self.ui.fileParserCombo.setCurrentIndex( self.ui.fileParserCombo.findText( self.fileType[0][-3:].upper() + " Parser")) self.ui.dataFileLineEdit.setText(self.fileType[0]) self.createtablemodel = TableModelC(newDict, self) self.filterModel.displayed = [] self.filterModel.setSourceModel(self.createtablemodel) self.filterModel.fileType = self.fileType self.createTableSearchFilterModel = QSortFilterProxyModel(self) self.createTableSearchFilterModel.setSourceModel(self.filterModel) self.createTableSearchFilterModel.setFilterKeyColumn(1) self.createTableSearchFilterModel.setDynamicSortFilter(True) self.ui.metadataTableView.setModel( self.createTableSearchFilterModel) self.treeModel = TreeModelR(["Available File Metadata"], newDict, self.createtablemodel, newList, self.filterModel) for i in range(len(newList)): if "Custom Input" in newList[i]["Source"]: self.numCustoms += 1 self.customInputs.append(newList[i]) self.createtablemodel.beginInsertRows( self.createtablemodel.index( len(self.createtablemodel.metadataList), 0), i, i) self.createtablemodel.metadataList.append(newList[i]) self.createtablemodel.endInsertRows() self.createTreeSearchFilterModel = QSortFilterProxyModel(self) self.createTreeSearchFilterModel.setSourceModel(self.treeModel) self.createTreeSearchFilterModel.setFilterKeyColumn(0) self.createTreeSearchFilterModel.setDynamicSortFilter(True) self.createTreeSearchFilterModel.setRecursiveFilteringEnabled(True) self.ui.metadataTreeView.setModel(self.createTreeSearchFilterModel) self.treeModel.checkChanged.connect(self.filterModel.checkList) self.createtrashDelegate.pressed.connect(self.handleRemoveCreate) self.ui.TabWidget.setCurrentIndex(0) def removeRowfromUsefileType(self, index): if self.ui.useTemplateListView.width( ) - 64 < self.ui.useTemplateListView.mapFromGlobal(QCursor.pos()).x(): #this is where to remove the row self.uselistmodel.removeRow(index.row()) def resizeEvent(self, event): super().resizeEvent(event) self.movethedamnbutton() def savePackageAs(self): fileName = QFileDialog.getSaveFileName(self, "Save File", "/Packages/", "Packages (*.ezpak)")[0] if fileName != "": myDir = QDir() myDir.mkpath(fileName) for file in self.uselistmodel.metadataList: QFile.copy(file, fileName + "/" + file.split("/")[-1]) oldtemplate = open(self.templateFilePath, 'r') oldtemplatelist = oldtemplate.readline() filetype = oldtemplate.readline() oldtemplate.readline() oldlist = oldtemplate.readline() oldtree = oldtemplate.readline() oldtemplate.close() with open(fileName + "/" + self.currentTemplate, 'w') as outfile: outfile.write(oldtemplatelist) outfile.write(filetype) json.dump(self.editableKeys, outfile) outfile.write("\n") outfile.write(oldlist) outfile.write(oldtree) with open(fileName + "/" + self.currentTemplate + "pak", 'w') as outfile: json.dump(fileName + "/" + self.currentTemplate, outfile) outfile.write("\n") json.dump(self.ui.otherDataFileLineEdit.text(), outfile) outfile.write("\n") json.dump(self.uselistmodel.metadataList, outfile) def saveTemplate(self): dialog = QFileDialog(self, "Save File", "", "Templates (*.ez)") dialog.setDefaultSuffix(".ez") dialog.setAcceptMode(QFileDialog.AcceptSave) fileName = "" if dialog.exec(): fileName = dialog.selectedFiles()[0] if fileName != "": with open(fileName, 'w') as outfile: json.dump(self.filterModel.displayed, outfile) outfile.write("\n") json.dump(self.filterModel.fileType, outfile) outfile.write("\n") self.createtablemodel.editableList = [] for i in range(len(self.createtablemodel.metadataList)): if self.createtablemodel.metadataList[i][ "Editable"] == 2 and ( self.createtablemodel.metadataList[i] ["Checked"] == 2 or self.createtablemodel. metadataList[i]["Checked"] == 1): self.createtablemodel.editableList.append( self.createtablemodel.metadataList[i]["Key"]) json.dump(self.createtablemodel.editableList, outfile) outfile.write("\n") json.dump(self.createtablemodel.metadataList, outfile) outfile.write("\n") json.dump(self.treeModel.treeDict, outfile) def selectFile(self, fileLink=None): if fileLink == False: linetext = QFileDialog.getOpenFileName( self, self.tr("Select File"), QStandardPaths.displayName(QStandardPaths.HomeLocation), self.tr("Files (*.*)"))[0] else: linetext = fileLink if linetext != "": self.setWindowTitle(linetext) self.ui.dataFileLineEdit.setText(linetext) self.ui.dataTypeText.setText(linetext.split(".")[1].upper()) if self.ui.fileParserCombo.findText( linetext.split(".")[1].upper() + " Parser") != -1: headerDict = {} self.ui.fileParserCombo.setCurrentIndex( self.ui.fileParserCombo.findText( linetext.split(".")[1].upper() + " Parser")) if linetext.split(".")[1].upper() == "CTF": headerDict = ctf.parse_header_as_dict(linetext) elif linetext.split(".")[1].upper() == "ANG": headerDict = ang.parse_header_as_dict(linetext) elif linetext.split(".")[1].upper() == "XML": print("XML Parser used") self.createtablemodel = TableModelC(headerDict, self) self.filterModel.displayed = [] self.filterModel.setSourceModel(self.createtablemodel) self.filterModel.fileType.append(linetext) self.createTableSearchFilterModel = QSortFilterProxyModel(self) self.createTableSearchFilterModel.setSourceModel(self.filterModel) self.createTableSearchFilterModel.setFilterKeyColumn(1) self.createTableSearchFilterModel.setDynamicSortFilter(True) self.ui.metadataTableView.setModel( self.createTableSearchFilterModel) self.treeModel = TreeModel(["Available File Metadata"], headerDict, self.createtablemodel) if len(self.customInputs) != 0: for i in range(len(self.customInputs)): self.createtablemodel.beginInsertRows( self.createtablemodel.index( len(self.createtablemodel.metadataList), 0), i, i) self.createtablemodel.metadataList.append( self.customInputs[i]) self.createtablemodel.endInsertRows() self.createTreeSearchFilterModel = QSortFilterProxyModel(self) self.createTreeSearchFilterModel.setSourceModel(self.treeModel) self.createTreeSearchFilterModel.setFilterKeyColumn(0) self.createTreeSearchFilterModel.setDynamicSortFilter(True) self.createTreeSearchFilterModel.setRecursiveFilteringEnabled(True) self.ui.metadataTreeView.setModel(self.createTreeSearchFilterModel) self.treeModel.checkChanged.connect(self.filterModel.checkList) self.createtrashDelegate.pressed.connect(self.handleRemoveCreate) self.toggleButtons() return True def selectTemplate(self): startLocation = self.ui.hyperthoughtTemplateLineEdit.text() if startLocation == "": startLocation = QStandardPaths.writableLocation( QStandardPaths.HomeLocation) templateFilePath = QFileDialog.getOpenFileName( self, self.tr("Select File"), startLocation, self.tr("Files (*.ez)"))[0] self.loadTemplateFile(templateFilePath) def loadTemplateFile(self, templateFilePath=None): if templateFilePath == "": return False self.templateFilePath = templateFilePath self.usetablemodel.metadataList = [] self.usefilterModel.displayed = [] self.currentTemplate = templateFilePath.split("/")[-1] self.ui.displayedFileLabel.setText(templateFilePath.split("/")[-1]) self.ui.hyperthoughtTemplateLineEdit.setText(templateFilePath) self.ui.otherDataFileLineEdit.setText("") infile = open(templateFilePath, "r") data = infile.readline() fileType = infile.readline() fileType = json.loads(fileType) self.fileType = fileType[0][-4:] editables = infile.readline() self.editableKeys = json.loads(editables) self.usetablemodel.editableKeys = self.editableKeys self.toggleButtons() self.templatedata = json.loads(data) self.usetablemodel.addTemplateList(self.templatedata) self.usefilterModel.setFilterRegExp(QRegExp()) infile.close() return True def showEvent(self, event): super().showEvent(event) self.movethedamnbutton() def toggleButtons(self): if (self.ui.hyperthoughtTemplateLineEdit.text() != "" and self.ui.otherDataFileLineEdit.text() != "" and self.ui.useTemplateListView.model().rowCount() > 0 and self.ui.hyperthoughtLocationLineEdit.text() != ""): self.ui.hyperthoughtUploadButton.setEnabled(True) def uploadToHyperthought(self): auth_control = htauthcontroller.HTAuthorizationController( self.accessKey) metadataJson = ht_utilities.dict_to_ht_metadata( self.usefilterModel.displayed) progress = QProgressDialog("Uploading files...", "Abort Upload", 0, len(self.uselistmodel.metadataList), self) progress.setWindowFlags(Qt.Window | Qt.CustomizeWindowHint | Qt.WindowTitleHint) progress.setAttribute(Qt.WA_DeleteOnClose) self.createUpload.emit(self.uselistmodel.metadataList, auth_control, self.folderuuid, metadataJson) self.uploader.currentUploadDone.connect(progress.setValue) self.uploader.currentlyUploading.connect(progress.setLabelText) self.uploader.allUploadsDone.connect(progress.accept) progress.canceled.connect(lambda: self.uploader.interruptUpload()) progress.setFixedSize(500, 100) progress.exec()