1
0
mirror of https://github.com/arsenetar/dupeguru.git synced 2024-10-18 16:45:57 +00:00
dupeguru/qt/pe/details_dialog.py

299 lines
12 KiB
Python

# Copyright 2016 Hardcoded Software (http://www.hardcoded.net)
#
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
# which should be included with this package. The terms are also available at
# http://www.gnu.org/licenses/gpl-3.0.html
from PyQt5.QtCore import Qt, QSize, pyqtSlot, pyqtSignal
from PyQt5.QtGui import QPixmap, QIcon, QKeySequence
from PyQt5.QtWidgets import (QLayout, QVBoxLayout, QAbstractItemView, QHBoxLayout,
QLabel, QSizePolicy, QToolBar, QToolButton, QGridLayout, QStyle, QAction,
QWidget, QApplication, QSpacerItem, QSplitter, QFrame )
from hscommon.trans import trget
from hscommon import desktop
from ..details_dialog import DetailsDialog as DetailsDialogBase
from ..details_table import DetailsTable
from qtlib.util import createActions
from qt.pe.image_viewer import (
QWidgetImageViewer, ScrollAreaImageViewer, GraphicsViewViewer,
QWidgetController, ScrollAreaController, GraphicsViewController)
tr = trget("ui")
class DetailsDialog(DetailsDialogBase):
def __init__(self, parent, app):
self.vController = None
super().__init__(parent, app)
def setupActions(self):
# (name, shortcut, icon, desc, func)
ACTIONS = [
(
"actionZoomIn",
QKeySequence.ZoomIn,
"zoom-in",
tr("Increase zoom"),
self.zoomIn,
),
(
"actionZoomOut",
QKeySequence.ZoomOut,
"zoom-out",
tr("Decrease zoom"),
self.zoomOut,
),
(
"actionNormalSize",
QKeySequence.Refresh,
"zoom-original",
tr("Normal size"),
self.zoomNormalSize,
),
(
"actionBestFit",
tr("Ctrl+p"),
"zoom-best-fit",
tr("Best fit"),
self.zoomBestFit,
)
]
createActions(ACTIONS, self)
def _setupUi(self):
self.setupActions()
self.setWindowTitle(tr("Details"))
self.resize(502, 502)
self.setMinimumSize(QSize(250, 250))
# self.verticalLayout = QVBoxLayout(self)
# self.verticalLayout.setSpacing(0)
# self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.splitter = QSplitter(Qt.Vertical, self)
self.setCentralWidget(self.splitter)
self.topFrame = QFrame()
self.topFrame.setFrameShape(QFrame.StyledPanel)
self.horizontalLayout = QGridLayout()
# Minimum width for the toolbar in the middle:
self.horizontalLayout.setColumnMinimumWidth(1, 10)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setColumnStretch(0,24)
self.horizontalLayout.setColumnStretch(1,1)
self.horizontalLayout.setColumnStretch(2,24)
# self.horizontalLayout.setColumnStretch(3,0)
self.horizontalLayout.setSpacing(1)
self.selectedImageViewer = GraphicsViewViewer(self, "selectedImage")
# self.selectedImage = QLabel(self)
# sizePolicy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
# sizePolicy.setHorizontalStretch(0)
# sizePolicy.setVerticalStretch(0)
# sizePolicy.setHeightForWidth(
# self.selectedImage.sizePolicy().hasHeightForWidth()
# )
# self.selectedImage.setSizePolicy(sizePolicy)
# self.selectedImage.setScaledContents(False)
# self.selectedImage.setAlignment(Qt.AlignCenter)
# # self.horizontalLayout.addWidget(self.selectedImage)
self.horizontalLayout.addWidget(self.selectedImageViewer, 0, 0, 3, 1)
# self.horizontalLayout.addItem(QSpacerItem(5,0, QSizePolicy.Minimum),
# 1, 3, 1, 1, Qt.Alignment(Qt.AlignRight))
# FIXME make a subclass to initialize buttons later
# FIXME use qwidgetaction to make the popup on resize work -> QWidgetAction::createWidget()
# FIXME figure out why margins are changing when the window is updating (after Normal Size, on resize)
# it seems toggling the scrollbars reduce viewport size and messes up sizeHint returned?
# thus shrinking the space available for the toolbar?
self.verticalToolBar = QToolBar(self)
# self.verticalToolBar.setMaximumWidth(10)
self.verticalToolBar.setOrientation(Qt.Orientation(Qt.Vertical))
# self.subVLayout = QVBoxLayout(self)
# self.subVLayout.addWidget(self.verticalToolBar)
# self.horizontalLayout.addLayout(self.subVLayout)
self.buttonImgSwap = QToolButton(self.verticalToolBar)
self.buttonImgSwap.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.buttonImgSwap.setIcon(QIcon.fromTheme('view-refresh', \
self.style().standardIcon(QStyle.SP_BrowserReload)))
self.buttonImgSwap.setText('Swap images')
self.buttonImgSwap.setToolTip('Swap images')
self.buttonImgSwap.pressed.connect(self.swapImages)
self.buttonImgSwap.released.connect(self.swapImages)
self.buttonZoomIn = QToolButton(self.verticalToolBar)
self.buttonZoomIn.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.buttonZoomIn.setDefaultAction(self.actionZoomIn)
self.buttonZoomIn.setText('ZoomIn')
self.buttonZoomIn.setIcon(QIcon.fromTheme('zoom-in'))
self.buttonZoomOut = QToolButton(self.verticalToolBar)
self.buttonZoomOut.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.buttonZoomOut.setDefaultAction(self.actionZoomOut)
self.buttonZoomOut.setText('ZoomOut')
self.buttonZoomOut.setIcon(QIcon.fromTheme('zoom-out'))
self.buttonZoomOut.setEnabled(False)
self.buttonNormalSize = QToolButton(self.verticalToolBar)
self.buttonNormalSize.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.buttonNormalSize.setDefaultAction(self.actionNormalSize)
self.buttonNormalSize.setText('Normal Size')
self.buttonNormalSize.setIcon(QIcon.fromTheme('zoom-original'))
self.buttonNormalSize.setEnabled(True)
self.buttonBestFit = QToolButton(self.verticalToolBar)
self.buttonBestFit.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.buttonBestFit.setDefaultAction(self.actionBestFit)
self.buttonBestFit.setText('BestFit')
self.buttonBestFit.setIcon(QIcon.fromTheme('zoom-best-fit'))
self.buttonBestFit.setEnabled(False)
self.verticalToolBar.addWidget(self.buttonImgSwap)
self.verticalToolBar.addWidget(self.buttonZoomIn)
self.verticalToolBar.addWidget(self.buttonZoomOut)
self.verticalToolBar.addWidget(self.buttonNormalSize)
self.verticalToolBar.addWidget(self.buttonBestFit)
self.horizontalLayout.addWidget(self.verticalToolBar, 1, 1, 1, 1, Qt.AlignCenter)
self.referenceImageViewer = GraphicsViewViewer(self, "referenceImage")
# self.referenceImage = QLabel(self)
# sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
# sizePolicy.setHorizontalStretch(0)
# sizePolicy.setVerticalStretch(0)
# self.verticalToolBar.setSizePolicy(sizePolicy)
# sizePolicy.setHeightForWidth(
# self.referenceImage.sizePolicy().hasHeightForWidth()
# )
# self.referenceImageViewer.setSizePolicy(sizePolicy)
# self.referenceImageViewer.setAlignment(Qt.AlignCenter)
self.horizontalLayout.addWidget(self.referenceImageViewer, 0, 2, 3, 1)
# self.verticalLayout.addLayout(self.horizontalLayout)
self.topFrame.setLayout(self.horizontalLayout)
self.splitter.addWidget(self.topFrame)
# container = QWidget(self)
# container.setLayout(self.horizontalLayout)
# self.setLayout(self.horizontalLayout)
# self.splitter.addWidget(self)
self.splitter.setStretchFactor(0, 8)
self.tableView = DetailsTable(self)
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
# sizePolicy.setHeightForWidth(self.tableView.sizePolicy().hasHeightForWidth())
self.tableView.setSizePolicy(sizePolicy)
# self.tableView.setMinimumSize(QSize(0, 190))
# self.tableView.setMaximumSize(QSize(16777215, 190))
self.tableView.setAlternatingRowColors(True)
self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
self.tableView.setShowGrid(False)
# self.verticalLayout.addLayout(self.tableView)
self.splitter.addWidget(self.tableView)
self.splitter.setStretchFactor(1, 1)
# self.tableView.hide()
self.buttonImgSwap.setEnabled(False)
self.buttonZoomIn.setEnabled(False)
self.buttonZoomOut.setEnabled(False)
self.buttonNormalSize.setEnabled(False)
self.buttonBestFit.setEnabled(False)
# We use different types of controller depending on the
# underlying widgets we use to display images
# because their interface and methods might differ
if isinstance(self.selectedImageViewer, QWidgetImageViewer):
self.vController = QWidgetController(
self.selectedImageViewer,
self.referenceImageViewer,
self)
elif isinstance(self.selectedImageViewer, ScrollAreaImageViewer):
self.vController = ScrollAreaController(
self.selectedImageViewer,
self.referenceImageViewer,
self)
elif isinstance(self.selectedImageViewer, GraphicsViewViewer):
self.vController = GraphicsViewController(
self.selectedImageViewer,
self.referenceImageViewer,
self)
def _update(self):
if self.vController is None: # Not yet constructed!
return
if not self.app.model.selected_dupes:
# No item from the model, disable and clear everything.
self.vController.resetViewersState()
return
dupe = self.app.model.selected_dupes[0]
group = self.app.model.results.get_group_of_duplicate(dupe)
ref = group.ref
self.vController.updateView(ref, dupe, group)
# --- Override
def resizeEvent(self, event):
# HACK referenceViewer might be 1 pixel shorter in width
# due to the toolbar in the middle keeping the same width,
# so resizing in the GridLayout's engine leads to not enough space
# left for the panel on the right.
# This ensures same size while shrinking at least:
self.horizontalLayout.setColumnMinimumWidth(
0, self.selectedImageViewer.size().width())
self.horizontalLayout.setColumnMinimumWidth(
2, self.selectedImageViewer.size().width())
# This works when expanding but it's ugly:
# if self.selectedImageViewer.size().width() > self.referenceImageViewer.size().width():
# print(f"Before selected size: {self.selectedImageViewer.size()}\n\
# Before reference size: {self.referenceImageViewer.size()}")
# self.selectedImageViewer.resize(self.referenceImageViewer.size())
# print(f"After selected size: {self.selectedImageViewer.size()}\n\
# After reference size: {self.referenceImageViewer.size()}")
if self.vController is None or not self.vController.bestFit:
return
# Only update the scaled down pixmaps
self.vController.updateBothImages()
def show(self):
# Compute the maximum size the table view can reach
self.tableView.setMaximumHeight(
self.tableView.rowHeight(1) * self.tableModel.model.row_count()\
+ self.tableView.verticalHeader().sectionSize(0))
DetailsDialogBase.show(self)
self._update()
# model --> view
def refresh(self):
DetailsDialogBase.refresh(self)
if self.isVisible():
self._update()
# ImageViewers
@pyqtSlot()
def swapImages(self):
self.vController.swapPixmaps()
# swap the columns in the details table as well
self.tableView.horizontalHeader().swapSections(1, 2)
@pyqtSlot()
def zoomIn(self):
self.vController.zoomIn()
@pyqtSlot()
def zoomOut(self):
self.vController.zoomOut()
@pyqtSlot()
def zoomBestFit(self):
self.vController.ScaleToBestFit()
@pyqtSlot()
def zoomNormalSize(self):
self.vController.zoomNormalSize()