class MainWindow(QMainWindow): def __init__(self, parent=None, flags=Qt.WindowFlags()): super(MainWindow, self).__init__(parent, flags) self.dayWidth = 70 self.ui = Ui_MainWindow() self.ui.setupUi(self) self.initModel() self.initActions() self.initItemDelegate() self.initGrid() leftView = self.ui.ganttView.leftView() leftView.setColumnHidden(1, True) leftView.setColumnHidden(2, True) leftView.setColumnHidden(3, True) leftView.setColumnHidden(4, True) leftView.setColumnHidden(5, True) leftView.header().setStretchLastSection(True) self.ui.ganttView.leftView().customContextMenuRequested.connect( self.showContextMenu) self.ui.ganttView.selectionModel().selectionChanged.connect( self.enableActions) self.ui.ganttView.graphicsView().clicked.connect(self.slotClicked) self.ui.ganttView.graphicsView().qrealClicked.connect( self.slotDoubleClicked) def initModel(self): self.model = QStandardItemModel(0, 6, self) self.model.setHeaderData(0, Qt.Horizontal, "Task") self.ui.ganttView.setModel(self.model) self.l = QWidget(self) self.l.setWindowTitle("Legend") self.l.show() ##self.l.setModel(self.model) self.constraintModel = ConstraintModel(self) self.ui.ganttView.setConstraintModel(self.constraintModel) def initActions(self): self.newEntryAction = QAction("New entry", self) self.newEntryAction.setShortcut(QKeySequence.New) self.newEntryAction.triggered.connect(self.addNewEntry) self.removeEntryAction = QAction("Remove entry", self) self.removeEntryAction.setShortcut(QKeySequence.Delete) self.removeEntryAction.triggered.connect(self.removeEntry) self.demoAction = QAction("Demo entry", self) self.demoAction.triggered.connect(self.addDemoEntry) self.printAction = QAction("Print Preview...", self) self.printAction.triggered.connect(self.printPreview) self.zoomInAction = QAction("Zoom In", self) self.zoomInAction.setShortcut(QKeySequence.ZoomIn) self.zoomInAction.triggered.connect(self.zoomIn) self.zoomOutAction = QAction("Zoom Out", self) self.zoomOutAction.setShortcut(QKeySequence.ZoomOut) self.zoomOutAction.triggered.connect(self.zoomOut) self.ui.ganttView.leftView().setContextMenuPolicy(Qt.CustomContextMenu) self.ui.ganttView.leftView().addAction(self.newEntryAction) self.ui.ganttView.leftView().addAction(self.removeEntryAction) menuBar = QMenuBar(self) self.setMenuBar(menuBar) entryMenu = menuBar.addMenu("Entry") entryMenu.addAction(self.newEntryAction) entryMenu.addAction(self.removeEntryAction) entryMenu.addSeparator() entryMenu.addAction(self.demoAction) entryMenu.addSeparator() entryMenu.addAction(self.printAction) zoomMenu = menuBar.addMenu("Zoom") zoomMenu.addAction(self.zoomInAction) zoomMenu.addAction(self.zoomOutAction) ##self.enableActions(QItemSelection()) def initItemDelegate(self): delegate = EntryDelegate(self.constraintModel, self) self.ui.ganttView.leftView().setItemDelegate(delegate) def initGrid(self): self.grid = DateTimeGrid() self.grid.setDayWidth(self.dayWidth) self.ui.ganttView.setGrid(self.grid) def showContextMenu(self, pos): if not self.ui.ganttView.leftView().indexAt(pos).isValid(): self.ui.ganttView.selectionModel().clearSelection() menu = QMenu(self.ui.ganttView.leftView()) menu.addAction(self.newEntryAction) menu.addAction(self.removeEntryAction) menu.exec_(self.ui.ganttView.leftView().viewport().mapToGlobal(pos)) def enableActions(self, selected): if len(selected.indexes()) == 0: self.newEntryAction.setEnabled(True) self.removeEntryAction.setEnabled(False) return selectedIndex = selected.indexes()[0] dataType = self.model.data(self.model.index(selectedIndex.row(), 1)) if dataType in [KDGantt.TypeEvent, KDGantt.TypeTask]: self.newEntryAction.setEnabled(False) self.removeEntryAction.setEnabled(True) return self.newEntryAction.setEnabled(True) self.removeEntryAction.setEnabled(True) def addNewEntry(self): dialog = EntryDialog(self.model) dialog.setWindowTitle("New Entry") if dialog.exec_() == QDialog.Rejected: dialog = None return selectedIndexes = self.ui.ganttView.selectionModel().selectedIndexes() if len(selectedIndexes) > 0: parent = selectedIndexes[0] else: parent = QModelIndex() if not self.model.insertRow(self.model.rowCount(parent), parent): return row = self.model.rowCount(parent) - 1 if row == 0 and parent.isValid(): self.model.insertColumns(self.model.columnCount(paren), 5, parent) self.model.setData(self.model.index(row, 0, parent), dialog.name()) self.model.setData(self.model.index(row, 1, parent), dialog.type()) if dialog.type() != KDGantt.TypeSummary: self.model.setData(self.model.index(row, 2, parent), dialog.startDate(), KDGantt.StartTimeRole) self.model.setData(self.model.index(row, 3, parent), dialog.endDate(), KDGantt.EndTimeRole) self.model.setData(self.model.index(row, 4, parent), dialog.completion()) self.model.setData(self.model.index(row, 5, parent), dialog.legend()) self.addConstraint(dialog.depends(), self.model.index(row, 0, parent)) self.setReadOnly(self.model.index(row, 0, parent), dialog.readOnly()) dialog = None def setReadOnly(self, index, readOnly): row = index.row() parent = index.parent() for column in range(0, 5): item = self.model.itemFromIndex( self.model.index(row, column, parent)) flags = None if readOnly: flags = item.flags() & ~Qt.ItemIsEditable else: flags = item.flags() | Qt.ItemIsEditable item.setFlags(flags) def addConstraint(self, index1, index2): if not index1.isValid() or not index2.isValid(): return c = Constraint(index1, index2) self.ui.ganttView.constraintModel().addConstraint(c) def addConstraintFromItem(self, item1, item2): self.addConstraint(self.model.indexFromItem(item1), self.model.indexFromItem(item2)) def removeEntry(self): selectedIndexes = self.ui.ganttView.selectionModel().selectedIndexes() if len(selectedIndexes) > 0: index = selectedIndexes[0] else: index = QModelIndex() if not index.isValid(): return self.model.removeRow(index.row(), index.parent()) def addDemoEntry(self): softwareRelease = MyStandardItem("Software Release") codeFreeze = MyStandardItem("Code Freeze") codeFreeze.setData(KDGantt.TextPositionRole, StyleOptionGanttItem.Right) packaging = MyStandardItem("Packaging") upload = MyStandardItem("Upload") testing = MyStandardItem("Testing") updateDocumentation = MyStandardItem("Update Documentation") now = QDateTime.currentDateTime() softwareRelease.appendRow([ codeFreeze, MyStandardItem(KDGantt.TypeEvent), MyStandardItem(now, KDGantt.StartTimeRole) ]) softwareRelease.appendRow([ packaging, MyStandardItem(KDGantt.TypeTask), MyStandardItem(now.addDays(5), KDGantt.StartTimeRole), MyStandardItem(now.addDays(10), KDGantt.EndTimeRole) ]) softwareRelease.appendRow([ upload, MyStandardItem(KDGantt.TypeTask), MyStandardItem( now.addDays(10).addSecs(2 * 60 * 60), KDGantt.StartTimeRole), MyStandardItem(now.addDays(11), KDGantt.EndTimeRole) ]) softwareRelease.appendRow([ testing, MyStandardItem(KDGantt.TypeTask), MyStandardItem(now.addSecs(3 * 60 * 60), KDGantt.StartTimeRole), MyStandardItem(now.addDays(5), KDGantt.EndTimeRole) ]) softwareRelease.appendRow([ updateDocumentation, MyStandardItem(KDGantt.TypeTask), MyStandardItem(now.addSecs(3 * 60 * 60), KDGantt.StartTimeRole), MyStandardItem(now.addDays(3), KDGantt.EndTimeRole) ]) self.model.appendRow( [softwareRelease, MyStandardItem(KDGantt.TypeSummary)]) self.addConstraintFromItem(codeFreeze, packaging) self.addConstraintFromItem(codeFreeze, testing) self.addConstraintFromItem(codeFreeze, updateDocumentation) self.addConstraintFromItem(packaging, upload) self.addConstraintFromItem(testing, packaging) self.addConstraintFromItem(updateDocumentation, packaging) def zoomIn(self): self.dayWidth += 10 if self.dayWidth > 400: self.grid.setScale(DateTimeGrid.ScaleHour) self.grid.setDayWidth(self.dayWidth) def zoomOut(self): self.dayWidth -= 10 if self.dayWidth < 10: self.dayWidth = 10 if self.dayWidth <= 400: self.grid.setScale(DateTimeGrid.ScaleDay) self.grid.setDayWidth(self.dayWidth) def printPreview(self): preview = QLabel(self, Qt.Window) preview.setAttribute(Qt.WA_DeleteOnClose) preview.setScaledContents(True) preview.setWindowTitle("Print Preview") pix = QPixmap(1000, 300) pix.fill(Qt.white) p = QPainter(pix) p.setRenderHints(QPainter.Antialiasing) self.ui.ganttView.print_(p, pix.rect()) preview.setPixmap(pix) preview.show() def slotClicked(self, index): self.statusBar().showMessage( "(%d,%d,_,%s) clicked" % (index.row(), index.column(), index.model())) def slotDoubleClicked(self, index): self.statusBar().showMessage( "(%d,%d,_,%s) qreal clicked" % (index.row(), index.column(), index.model()))
class MainWindow(QMainWindow, Ui_MainWindow): _TV_FOLDERS_ITEM_MAP = {} # signals _dir_load_start = Signal(object) _dir_watcher_start = Signal() _loader_load_scandir = Signal(int, int, int, object) _is_watcher_running = False _update_mgr = None def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.actiongrp_thumbs_size = QtWidgets.QActionGroup(self) self.actiongrp_thumbs_size.addAction(self.action_small_thumbs) self.actiongrp_thumbs_size.addAction(self.action_normal_thumbs) self.actiongrp_thumbs_caption = QtWidgets.QActionGroup(self) self.actiongrp_thumbs_caption.addAction(self.action_caption_none) self.actiongrp_thumbs_caption.addAction(self.action_caption_filename) self.action_caption_none.setChecked(True) # threads self._dir_watcher_thread = QThread() self._img_loader_thread = QThread() # helpers self._meta_files_mgr = MetaFilesManager() self._meta_files_mgr.connect() self._watch = Watcher() self._img_loader = ImageLoader() self.listView_thumbs = ThumbsListView(self.frame_thumbs) self.listView_thumbs.setFrameShape(QtWidgets.QFrame.NoFrame) self.vlayout_frame_thumbs.addWidget(self.listView_thumbs) # connections self._setup_connections() # Populates the folder list self._setup_scan_dir_list_model() # Properties widget self.vlayout_properties = QtWidgets.QVBoxLayout( self.toolbox_metadata_properties) self.vlayout_properties.setContentsMargins(0, 0, 0, 0) self.vlayout_properties.setSpacing(0) self.properties_widget = PropertiesWidget( self.toolbox_metadata_properties) self.vlayout_properties.addWidget(self.properties_widget) self.statusBar().showMessage("Ready") # settings self.hslider_thumb_size.setValue( settings.get(SettingType.UI_THUMBS_SIZE, 128, 'int')) thumb_caption_type = settings.get( SettingType.UI_THUMBS_CAPTION_DISPLAY_MODE, Thumb_Caption_Type.NoCaption.name) if thumb_caption_type == Thumb_Caption_Type.FileName.name: self.action_caption_filename.setChecked(True) if settings.get(SettingType.UI_METADATA_SHOW_PROPS, False, 'bool'): self.toolBox_metadata.setCurrentIndex(0) self.toolbutton_properties.setChecked(True) self.toolbutton_tags.setChecked(False) self.action_properties.setChecked(True) self.action_tags.setChecked(False) self.frame_metadata.show() elif settings.get(SettingType.UI_METADATA_SHOW_TAGS, False, 'bool'): self.toolBox_metadata.setCurrentIndex(1) self.toolbutton_properties.setChecked(False) self.toolbutton_tags.setChecked(True) self.action_properties.setChecked(False) self.action_tags.setChecked(True) self.frame_metadata.show() else: self.frame_metadata.hide() # Set event filters self.btn_slideshow.installEventFilter(self) self._curr_img_serial = 1 def resizeEvent(self, event): if event.spontaneous(): # Begin loading the currently selected dir self._make_default_dir_list_selection() cur_sel_ids = self.get_current_selection_ids() if 'sd_id' in cur_sel_ids: self._load_dir_images(cur_sel_ids['sd_id']) # Start the dir watcher thread self.init_watch_thread() # Start the loader thread self.init_loader_thread() def closeEvent(self, event): LOGGER.debug('Shutting down gracefully....') self._meta_files_mgr.disconnect() settings.persist_to_disk() self._dir_watcher_thread.quit() self._dir_watcher_thread.wait() self._img_loader_thread.quit() self._img_loader_thread.wait() def _make_default_dir_list_selection(self): folders_index = self._dirs_list_model.indexFromItem( self._TV_FOLDERS_ITEM_MAP[0]) if self._dirs_list_model.rowCount(folders_index) > 0: self._dirs_list_selection_model.select( self._dirs_list_model.index(0, 0).child(0, 0), QItemSelectionModel.Select | QItemSelectionModel.Rows) def _setup_connections(self): # Menu # File self.action_add_folder.triggered.connect( self.action_folder_manager_clicked) self.action_rescan.triggered.connect(self._run_watcher) self.action_file_locate.triggered.connect( self.handle_action_file_locate_triggered) self.action_exit.triggered.connect(self.action_exit_clicked) # View self.action_small_thumbs.triggered.connect( self.handle_action_small_thumbs_triggered) self.action_normal_thumbs.triggered.connect( self.handle_action_normal_thumbs_triggered) self.action_properties.triggered.connect( self.action_properties_clicked) self.action_tags.triggered.connect(self.action_tags_clicked) self.action_slideshow.triggered.connect(self.start_slideshow) self.action_caption_none.triggered.connect( self.handle_action_thumbnail_caption_none_triggered) self.action_caption_filename.triggered.connect( self.handle_action_thumbnail_caption_filename_triggered) # Folder self.action_folder_slideshow.triggered.connect(self.start_slideshow) self.action_folder_locate.triggered.connect( self.handle_action_folder_locate_triggered) # Picture self.action_picture_properties.triggered.connect( self.show_image_properties) # Tools self.action_settings.triggered.connect( self.handle_action_settings_triggered) self.action_folder_manager.triggered.connect( self.action_folder_manager_clicked) # Help self.action_check_updates.triggered.connect( self._handle_check_for_updates_clicked) # Btns self.btn_slideshow.clicked.connect(self.start_slideshow) self.hslider_thumb_size.valueChanged.connect( self.on_hslider_thumb_size_value_changed) # Watcher self._dir_watcher_start.connect(self._watch.watch_all) self._watch.new_img_found.connect(self.on_new_img_found) self._watch.watch_all_done.connect(self.on_watch_all_done) self._watch.dir_added_or_updated.connect(self.on_dir_added_or_updated) self._watch.dir_empty_or_deleted.connect(self.on_dir_empty_deleted) self._watch.watch_empty_or_deleted_done.connect( self.on_watch_dir_empty_deleted_done) # Loader self._loader_load_scandir.connect(self._img_loader.load_scandir) # self._loader_load_scanimg.connect(self._img_loader.load_scanimg) self._img_loader.load_scan_dir_info_success.connect( self._handle_load_scan_dir_info_success) # self._img_loader.load_images_success.connect( # self._handle_load_images_sucess) self._img_loader.load_images_success.connect( self.listView_thumbs.render_thumbs) # Tree View self.treeView_scandirs.clicked.connect( self.on_scan_dir_treeView_clicked) # Thumbs view self.listView_thumbs.clicked.connect(self.on_thumb_clicked) self.listView_thumbs.empty_area_clicked.connect( self.on_thumb_listview_empty_area_clicked) self.listView_thumbs.load_dir_images_for_scroll_up.connect( self.on_load_dir_images_for_scroll_up) self.listView_thumbs.load_dir_images_for_scroll_down.connect( self.on_load_dir_images_for_scroll_down) self.buttonGroup_metadata.buttonClicked.connect( self.on_buttongroup_metadata_clicked) self.txtbox_search.textEdited.connect(self.handle_search) def init_watch_thread(self): self._watch.moveToThread(self._dir_watcher_thread) self._dir_watcher_thread.start() self._run_watcher() LOGGER.debug('Watcher thread started.') def init_loader_thread(self): self._img_loader.moveToThread(self._img_loader_thread) self._img_loader_thread.start() LOGGER.debug('Loader thread started.') def _run_watcher(self): self._is_watcher_running = True self.action_rescan.setEnabled(False) self._dir_watcher_start.emit() def _populate_dirs_tree_view(self, parent_key, folders): parent_item = self._TV_FOLDERS_ITEM_MAP[parent_key] if folders: for idx, dir in enumerate(folders): item_title = "%s(%s)" % (dir['name'], dir['img_count']) item = QStandardItem(item_title) item.setData(dir['id'], QtCore.Qt.UserRole + 1) item.setSizeHint(QSize(item.sizeHint().width(), 24)) item.setIcon(QIcon(':/images/icon_folder')) parent_item.appendRow(item) if parent_key == 0: self._TV_FOLDERS_ITEM_MAP[dir['id']] = item self.treeView_scandirs.expandAll() def _setup_scan_dir_list_model(self): self._dirs_list_model = QStandardItemModel() self._dirs_list_selection_model = QItemSelectionModel( self._dirs_list_model) self._thumbs_view_model = QStandardItemModel() self._thumbs_selection_model = QItemSelectionModel( self._thumbs_view_model) self._dirs_list_model.setColumnCount(1) # self._dirs_list_model.setRowCount(len(scan_dirs)) self._root_tree_item = self._dirs_list_model.invisibleRootItem() # FOLDERS item folder_item = QStandardItem("Folders") folder_item_font = QFont() folder_item_font.setBold(True) folder_item.setFont(folder_item_font) folder_item.setSizeHint(QSize(folder_item.sizeHint().width(), 24)) self._root_tree_item.appendRow(folder_item) self._TV_FOLDERS_ITEM_MAP[0] = folder_item self.treeView_scandirs.setModel(self._dirs_list_model) self.treeView_scandirs.setSelectionModel( self._dirs_list_selection_model) # self.treeView_scandirs.setRootIsDecorated(False) self.listView_thumbs.setModel(self._thumbs_view_model) self.listView_thumbs.setSelectionModel(self._thumbs_selection_model) scan_dirs = self._meta_files_mgr.get_scan_dirs() self._populate_dirs_tree_view(0, scan_dirs) def _repopulate_scan_dir_list_model(self): self._clear_folders_tree_view() scan_dirs = self._meta_files_mgr.get_scan_dirs() self._populate_dirs_tree_view(0, scan_dirs) def _populate_search_tree_view(self, results): if 'search' not in self._TV_FOLDERS_ITEM_MAP: self._root_tree_item = self._dirs_list_model.invisibleRootItem() # FOLDERS item search_item = QStandardItem("Search") search_item_font = QFont() search_item_font.setBold(True) search_item.setFont(search_item_font) search_item.setSizeHint(QSize(search_item.sizeHint().width(), 24)) self._root_tree_item.insertRow(0, search_item) self._TV_FOLDERS_ITEM_MAP['search'] = search_item self._populate_dirs_tree_view('search', results) def eventFilter(self, widget, event): if widget.objectName() == 'btn_slideshow': if event.type() == QtCore.QEvent.Enter: self.label_thumbs_toolbar_tooltip.setText( "Play Fullscreen Slideshow") elif event.type() == QtCore.QEvent.Leave: self.label_thumbs_toolbar_tooltip.setText("") return QtWidgets.QWidget.eventFilter(self, widget, event) def handle_search(self, search_term): self._clear_search() if search_term != '': searches = self._meta_files_mgr.search_scan_dirs(search_term) self._populate_search_tree_view(searches) else: self._remove_search_tree_view() def handle_action_file_locate_triggered(self): curr_sel_ids = self.get_current_selection_ids() if 'sd_id' in curr_sel_ids and 'si_id' in curr_sel_ids: dr_img = self._meta_files_mgr.get_image_from_id( curr_sel_ids['si_id'], curr_sel_ids['sd_id']) explorer_process = QtCore.QProcess() explorer_process.setProgram('explorer.exe') explorer_process.setArguments([ '/select,%s' % QtCore.QDir.toNativeSeparators(dr_img['abspath']) ]) explorer_process.startDetached() def handle_action_folder_locate_triggered(self): curr_sel_ids = self.get_current_selection_ids() if 'sd_id' in curr_sel_ids: dr_sd = self._meta_files_mgr.get_scan_dir(curr_sel_ids['sd_id']) explorer_process = QtCore.QProcess() explorer_process.setProgram('explorer.exe') explorer_process.setArguments([ '/select,%s' % QtCore.QDir.toNativeSeparators(dr_sd['abspath']) ]) explorer_process.startDetached() def handle_action_small_thumbs_triggered(self): if self.action_small_thumbs.isChecked(): self.hslider_thumb_size.triggerAction( self.hslider_thumb_size.SliderToMinimum) def handle_action_normal_thumbs_triggered(self): if self.action_normal_thumbs.isChecked(): slider_value = self.hslider_thumb_size.value() if slider_value < 128: self.hslider_thumb_size.triggerAction( self.hslider_thumb_size.SliderPageStepAdd) elif slider_value > 128 and slider_value <= 192: self.hslider_thumb_size.triggerAction( self.hslider_thumb_size.SliderPageStepSub) elif slider_value > 192 and slider_value <= 256: self.hslider_thumb_size.triggerAction( self.hslider_thumb_size.SliderPageStepSub) self.hslider_thumb_size.triggerAction( self.hslider_thumb_size.SliderPageStepSub) def handle_action_thumbnail_caption_none_triggered(self): if self.action_caption_none.isChecked(): settings.save(SettingType.UI_THUMBS_CAPTION_DISPLAY_MODE, Thumb_Caption_Type.NoCaption.name) curr_sel_ids = self.get_current_selection_ids() if 'sd_id' in curr_sel_ids: self._load_dir_images(curr_sel_ids['sd_id']) def handle_action_thumbnail_caption_filename_triggered(self): if self.action_caption_filename.isChecked(): settings.save(SettingType.UI_THUMBS_CAPTION_DISPLAY_MODE, Thumb_Caption_Type.FileName.name) curr_sel_ids = self.get_current_selection_ids() if 'sd_id' in curr_sel_ids: self._load_dir_images(curr_sel_ids['sd_id']) def action_folder_manager_clicked(self): self.folder_mgr_window = FolderManagerWindow(self) self.folder_mgr_window.accepted.connect( self._on_folder_manager_window_accepted) self.folder_mgr_window.setModal(True) self.folder_mgr_window.show() def _on_folder_manager_window_accepted(self): self._repopulate_scan_dir_list_model() self._run_watcher() def action_properties_clicked(self): if self.action_properties.isChecked(): curr_sel_ids = self.get_current_selection_ids() if 'sd_id' in curr_sel_ids and 'si_id' in curr_sel_ids: img_props = self._meta_files_mgr.get_img_properties( curr_sel_ids['si_id'], curr_sel_ids['sd_id']) self.properties_widget.setup_properties(img_props) self.toolBox_metadata.setCurrentIndex(0) self.frame_metadata.show() self.toolbutton_properties.setChecked(True) self.toolbutton_tags.setChecked(False) self.action_tags.setChecked(False) settings.save(SettingType.UI_METADATA_SHOW_PROPS, True) settings.save(SettingType.UI_METADATA_SHOW_TAGS, False) else: self.frame_metadata.hide() self.toolbutton_properties.setChecked(False) settings.save(SettingType.UI_METADATA_SHOW_PROPS, False) settings.save(SettingType.UI_METADATA_SHOW_TAGS, False) # Forces the list view to re-render after the metadata window is hidden self._thumbs_view_model.layoutChanged.emit() def action_tags_clicked(self): if self.action_tags.isChecked(): self.toolBox_metadata.setCurrentIndex(1) self.frame_metadata.show() self.toolbutton_tags.setChecked(True) self.toolbutton_properties.setChecked(False) self.action_properties.setChecked(False) settings.save(SettingType.UI_METADATA_SHOW_PROPS, False) settings.save(SettingType.UI_METADATA_SHOW_TAGS, True) else: self.frame_metadata.hide() self.toolbutton_tags.setChecked(False) settings.save(SettingType.UI_METADATA_SHOW_PROPS, False) settings.save(SettingType.UI_METADATA_SHOW_TAGS, False) # Forces the list view to re-render after the metadata window is hidden self._thumbs_view_model.layoutChanged.emit() def show_image_properties(self): curr_sel_ids = self.get_current_selection_ids() if 'sd_id' in curr_sel_ids and 'si_id' in curr_sel_ids: img_props = self._meta_files_mgr.get_img_properties( curr_sel_ids['si_id'], curr_sel_ids['sd_id']) self.properties_widget.setup_properties(img_props) self.toolBox_metadata.setCurrentIndex(0) self.frame_metadata.show() self.toolbutton_properties.setChecked(True) self.toolbutton_tags.setChecked(False) self.action_properties.setChecked(True) self.action_tags.setChecked(False) def handle_action_settings_triggered(self): self.settings_window = SettingsWindow(self) self.settings_window.setModal(True) self.settings_window.show() def on_buttongroup_metadata_clicked(self, button): if button.objectName() == 'toolbutton_tags': self.action_tags.trigger() elif button.objectName() == 'toolbutton_properties': self.action_properties.trigger() def on_hslider_thumb_size_value_changed(self, value): if self.hslider_thumb_size.value() == 64: self.action_small_thumbs.setChecked(True) elif self.hslider_thumb_size.value() == 128: self.action_normal_thumbs.setChecked(True) else: self.action_small_thumbs.setChecked(False) self.action_normal_thumbs.setChecked(False) self.listView_thumbs.setIconSize(QSize(value, value)) self.listView_thumbs.setGridSize(QSize(value + 20, value + 20)) settings.save(SettingType.UI_THUMBS_SIZE, value) def _handle_check_for_updates_clicked(self): if not self._update_mgr: self._update_mgr = UpdateManager() self._update_mgr.get_updates() def _load_dir_images(self, sd_id): self._clear_thumbs() load_count = self.listView_thumbs.get_visible_thumb_count( self.hslider_thumb_size.value() + 20) print("load count %d" % load_count) self._loader_load_scandir.emit(sd_id, 0, load_count, ScrollDirection.Down) QScroller.grabGesture(self.listView_thumbs.viewport(), QScroller.LeftMouseButtonGesture) def _load_dir_images_for_scroll_up(self, sd_id, serial, count): # self._clear_thumbs() load_count = self.listView_thumbs.get_visible_thumb_count( self.hslider_thumb_size.value() + 20) self._loader_load_scandir.emit(sd_id, serial, count, ScrollDirection.Up) QScroller.grabGesture(self.listView_thumbs.viewport(), QScroller.LeftMouseButtonGesture) def _load_dir_images_for_scroll_down(self, sd_id, serial, count): # self._clear_thumbs() load_count = self.listView_thumbs.get_visible_thumb_count( self.hslider_thumb_size.value() + 20) self._loader_load_scandir.emit(sd_id, serial, count, ScrollDirection.Down) QScroller.grabGesture(self.listView_thumbs.viewport(), QScroller.LeftMouseButtonGesture) @Slot(int, int) def on_load_dir_images_for_scroll_up(self, serial, count): cur_sel_ids = self.get_current_selection_ids() if 'sd_id' in cur_sel_ids: self._load_dir_images_for_scroll_up(cur_sel_ids['sd_id'], serial, count) @Slot(int, int) def on_load_dir_images_for_scroll_down(self, serial, count): cur_sel_ids = self.get_current_selection_ids() if 'sd_id' in cur_sel_ids: self._load_dir_images_for_scroll_down(cur_sel_ids['sd_id'], serial, count) def _handle_load_scan_dir_info_success(self, dir_info): self.lbl_dir_name.setText(dir_info['name']) @Slot(object, int) def _handle_load_images_sucess(self, images, scrollDirection): img_count = len(images) print('Recevied %s images' % img_count) LOGGER.debug('Recevied %s images' % img_count) for img in images: img['thumb'] = QImage.fromData(img['thumb']) item = QStandardItem() thumb_caption_type = settings.get( SettingType.UI_THUMBS_CAPTION_DISPLAY_MODE, Thumb_Caption_Type.NoCaption.name) if thumb_caption_type == Thumb_Caption_Type.FileName.name: item.setText(img['name']) item.setData(img['id'], QtCore.Qt.UserRole + 1) item.setData(img['serial'], QtCore.Qt.UserRole + 2) item.setIcon(QIcon(QPixmap.fromImage(img['thumb']))) item.setText(str(img['serial'])) if scrollDirection == ScrollDirection.Up: self._thumbs_view_model.insertRow(0, item) if scrollDirection == ScrollDirection.Down: self._thumbs_view_model.appendRow(item) def _clear_thumbs(self): self._thumbs_view_model.clear() self.lbl_dir_name.setText('') def _tv_add_scan_dir(self, dir_info, highlight=False): item_title = "%s(%s)" % (dir_info['name'], dir_info['img_count']) item = QStandardItem(item_title) item.setData(dir_info['id'], QtCore.Qt.UserRole + 1) item.setSizeHint(QSize(item.sizeHint().width(), 24)) item.setIcon(QIcon(':/images/icon_folder')) if highlight: bold_font = QFont() bold_font.setBold(True) item.setFont(bold_font) folder_item = self._TV_FOLDERS_ITEM_MAP[0] folder_item.appendRow(item) self._TV_FOLDERS_ITEM_MAP[dir_info['id']] = item @Slot() def start_slideshow(self): selected = self.treeView_scandirs.selectedIndexes() sd_id = selected[0].data(QtCore.Qt.UserRole + 1) img_serial = 1 thumb_selected = self.listView_thumbs.selectedIndexes() if len(thumb_selected) > 0: img_serial = thumb_selected[0].data(QtCore.Qt.UserRole + 2) if sd_id > 0: self._slideshow = SlideshowWindow(sd_id, img_serial) self._slideshow.setWindowFlags(QtCore.Qt.CustomizeWindowHint | QtCore.Qt.FramelessWindowHint) self._slideshow.showFullScreen() @Slot(QModelIndex) def on_thumb_clicked(self, mindex): selected = self.treeView_scandirs.selectedIndexes() sd_id = selected[0].data(QtCore.Qt.UserRole + 1) si_id = mindex.data(QtCore.Qt.UserRole + 1) img_props = self._meta_files_mgr.get_img_properties(si_id, sd_id) self.lbl_selection_summary.setText( self.get_thumb_selection_summary(img_props)) if self.action_properties.isChecked(): self.properties_widget.setup_properties(img_props) @Slot() def on_thumb_listview_empty_area_clicked(self): selected_thumb = self.listView_thumbs.selectedIndexes() if len(selected_thumb) == 0: selected = self.treeView_scandirs.selectedIndexes() sd_id = selected[0].data(QtCore.Qt.UserRole + 1) if sd_id: props = self._meta_files_mgr.get_dir_properties(sd_id) self.lbl_selection_summary.setText( self.get_dir_selection_summary(props)) def get_dir_selection_summary(self, props): img_count = props['img_count'] modified = props['modified'].toString('dd MMMM yyyy') size = props['size'] return "%s pictures %s %s on disk" % (img_count, modified, size) def get_thumb_selection_summary(self, props): filename = props['filename'] modified = props['DateTime'] if 'DateTime' in props else '' dimensions = props['dimensions'] filesize = props['filesize'] return "%s %s %s %s" % (filename, modified, dimensions, filesize) @Slot(QModelIndex) def on_scan_dir_treeView_clicked(self, index): sd_id = index.data(QtCore.Qt.UserRole + 1) # Categories tree nodes will not contain 'data' if sd_id: item = self._TV_FOLDERS_ITEM_MAP[sd_id] bold_font = QFont() bold_font.setBold(False) item.setFont(bold_font) props = self._meta_files_mgr.get_dir_properties(sd_id) self.lbl_selection_summary.setText( self.get_dir_selection_summary(props)) self._load_dir_images(sd_id) @Slot(object) def on_new_img_found(self, img_info): self.statusBar().showMessage("Found new image: %s - %s" % (img_info['dir'], img_info['filename'])) @Slot(object) def on_dir_added_or_updated(self, dir_info): if dir_info['id'] in self._TV_FOLDERS_ITEM_MAP: item = self._TV_FOLDERS_ITEM_MAP[dir_info['id']] item_title = "%s(%s)" % (dir_info['name'], dir_info['img_count']) item.setText(item_title) bold_font = QFont() bold_font.setBold(True) item.setFont(bold_font) else: self._tv_add_scan_dir(dir_info, True) @Slot(object) def on_dir_empty_deleted(self, dir_info): if dir_info['id'] in self._TV_FOLDERS_ITEM_MAP: item = self._TV_FOLDERS_ITEM_MAP[dir_info['id']] item_index = self._dirs_list_model.indexFromItem(item) parent_index = self._dirs_list_model.indexFromItem( self._TV_FOLDERS_ITEM_MAP[0]) self._dirs_list_model.removeRow(item_index.row(), parent_index) self._TV_FOLDERS_ITEM_MAP.pop(dir_info['id']) @Slot() def on_watch_dir_empty_deleted_done(self): # Here we make sure a folder is always selected if one more folders # ever get deleted by the watcher thread. If no folders exits, just # display an empty thumbs list cur_sel_ids = self.get_current_selection_ids() print(cur_sel_ids) if 'sd_id' not in cur_sel_ids: self._make_default_dir_list_selection() cur_sel_ids = self.get_current_selection_ids() if 'sd_id' in cur_sel_ids: self._load_dir_images(cur_sel_ids['sd_id']) else: self._clear_thumbs() @Slot(object, object) def on_watch_all_done(self, elapsed, suffix): self.statusBar().clearMessage() self._is_watcher_running = False self.action_rescan.setEnabled(True) self.statusBar().showMessage("Folder scan completed in %.2f %s" % (elapsed, suffix)) def get_current_selection_ids(self): selected_ids = {} selected = self.treeView_scandirs.selectedIndexes() if len(selected) <= 0: return selected_ids selected_ids['sd_id'] = selected[0].data(QtCore.Qt.UserRole + 1) selected_thumb = self.listView_thumbs.selectedIndexes() if len(selected_thumb) <= 0: return selected_ids selected_ids['si_id'] = selected_thumb[0].data(QtCore.Qt.UserRole + 1) return selected_ids def action_exit_clicked(self): self.close() def _clear_search(self): if 'search' in self._TV_FOLDERS_ITEM_MAP: search_item = self._TV_FOLDERS_ITEM_MAP['search'] search_item.removeRows(0, search_item.rowCount()) def _clear_folders_tree_view(self): folder_item = self._TV_FOLDERS_ITEM_MAP[0] self._TV_FOLDERS_ITEM_MAP.clear() self._TV_FOLDERS_ITEM_MAP[0] = folder_item folder_item.removeRows(0, folder_item.rowCount()) def _remove_search_tree_view(self): if 'search' in self._TV_FOLDERS_ITEM_MAP: root_tree_item = self._dirs_list_model.invisibleRootItem() root_tree_item.removeRow(0) self._TV_FOLDERS_ITEM_MAP.pop('search') def is_watcher_running(self): return self._is_watcher_running