예제 #1
0
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_())
예제 #2
0
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)
예제 #3
0
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)
예제 #4
0
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()