Skip to content

Commit 426e1c8

Browse files
authored
Feature: add context menu to graphical preview (#26)
Related to #17 ![image](https://user-images.githubusercontent.com/1596222/233450132-baa24875-5d1f-4888-a08d-5c5f0a514a24.png)
2 parents ce24356 + 42c58e2 commit 426e1c8

File tree

2 files changed

+130
-11
lines changed

2 files changed

+130
-11
lines changed

pyqgis_resource_browser/core/resource_table_view.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@ def contextMenuEvent(self, event: QContextMenuEvent) -> None:
1818
if isinstance(idx, QModelIndex) and idx.isValid():
1919
uri = idx.data(Qt.UserRole)
2020
m = QMenu()
21-
a = m.addAction("Copy Name")
21+
a = m.addAction(self.tr("Copy name"))
2222
a.triggered.connect(
2323
lambda *args, n=os.path.basename(uri): QApplication.clipboard().setText(
2424
n
2525
)
2626
)
27-
a = m.addAction("Copy Path")
27+
a = m.addAction(self.tr("Copy path"))
2828
a.triggered.connect(
2929
lambda *args, n=uri: QApplication.clipboard().setText(n)
3030
)
3131

32-
a = m.addAction("Copy Icon")
32+
a = m.addAction(self.tr("Copy icon"))
3333
a.triggered.connect(
3434
lambda *args, n=uri: QApplication.clipboard().setPixmap(QPixmap(n))
3535
)

pyqgis_resource_browser/gui/resource_browser.py

Lines changed: 127 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# standard lib
22
import os
3-
import pathlib
43
import re
54
from functools import partial
5+
from pathlib import Path
6+
from typing import Literal, Union
67

78
from qgis.core import QgsApplication
89
from qgis.PyQt import uic
910
from qgis.PyQt.QtCore import QFile, QModelIndex, QRegExp, Qt, QTextStream, pyqtSignal
10-
from qgis.PyQt.QtGui import QPixmap
11+
from qgis.PyQt.QtGui import QContextMenuEvent, QPixmap
1112
from qgis.PyQt.QtSvg import QGraphicsSvgItem
1213
from qgis.PyQt.QtWidgets import (
1314
QAction,
@@ -17,6 +18,7 @@
1718
QGraphicsView,
1819
QLabel,
1920
QLineEdit,
21+
QMenu,
2022
QTextBrowser,
2123
QToolButton,
2224
QWidget,
@@ -27,20 +29,29 @@
2729

2830
# plugin
2931
from pyqgis_resource_browser.__about__ import __title__
30-
31-
from ..core.resource_table_model import ResourceTableFilterModel, ResourceTableModel
32-
from ..core.resource_table_view import ResourceTableView
33-
from ..toolbelt import PlgOptionsManager
32+
from pyqgis_resource_browser.core.resource_table_model import (
33+
ResourceTableFilterModel,
34+
ResourceTableModel,
35+
)
36+
from pyqgis_resource_browser.core.resource_table_view import ResourceTableView
37+
from pyqgis_resource_browser.toolbelt import PlgLogger, PlgOptionsManager
3438

3539

3640
class ResourceGraphicsView(QGraphicsView):
3741
resized = pyqtSignal()
42+
uri: str = ""
3843

3944
def __init__(self, *args, **kwds):
4045
super().__init__(*args, **kwds)
46+
self.log = PlgLogger().log
4147
self.item = None
4248

43-
def setItem(self, item):
49+
def setItem(self, item: Union[QGraphicsSvgItem, QGraphicsPixmapItem]):
50+
"""Set view item.
51+
52+
:param item: _description_
53+
:type item: Union[QGraphicsSvgItem, QGraphicsPixmapItem]
54+
"""
4455
self.scene().clear()
4556
self.scene().addItem(item)
4657
self.item = item
@@ -50,6 +61,113 @@ def resizeEvent(self, QResizeEvent):
5061
if self.item:
5162
self.fitInView(self.item, Qt.KeepAspectRatio)
5263

64+
def contextMenuEvent(self, event: QContextMenuEvent):
65+
"""Custom menu displayed on righ-click event on widget view.
66+
67+
:param event: event that triggers the context-menu, typically right-click
68+
:type event: QContextMenuEvent
69+
"""
70+
menu = QMenu(parent=self)
71+
72+
# Copy image name
73+
action_copy_name = QAction(
74+
icon=QgsApplication.getThemeIcon("mIconLabelQuadrantOffset.svg"),
75+
text=self.tr("Copy name"),
76+
parent=self,
77+
)
78+
action_copy_name.triggered.connect(partial(self.copy_to_clipboard, "name"))
79+
80+
# Copy image path
81+
action_copy_path = QAction(
82+
icon=QgsApplication.getThemeIcon("mIconFileLink.svg"),
83+
text=self.tr("Copy path"),
84+
parent=self,
85+
)
86+
action_copy_path.triggered.connect(partial(self.copy_to_clipboard, "path"))
87+
88+
# Copy as getThemeIcon syntax
89+
action_copy_theme_icon = QAction(
90+
icon=QgsApplication.getThemeIcon("mActionEditInsertImage.svg"),
91+
text=self.tr("Copy as getThemeIcon syntax"),
92+
parent=self,
93+
)
94+
action_copy_theme_icon.triggered.connect(
95+
partial(self.copy_to_clipboard, "getThemeIcon")
96+
)
97+
98+
# Copy as QIcon syntax
99+
action_copy_qicon = QAction(
100+
icon=QgsApplication.getThemeIcon("mActionEditCopy.svg"),
101+
text=self.tr("Copy as QIcon syntax"),
102+
parent=self,
103+
)
104+
action_copy_qicon.triggered.connect(partial(self.copy_to_clipboard, "qicon"))
105+
106+
# Copy as QPixmap syntax
107+
action_copy_qpixmap = QAction(
108+
icon=QgsApplication.getThemeIcon("mIconColorPicker.svg"),
109+
text=self.tr("Copy as QPixmap syntax"),
110+
parent=self,
111+
)
112+
action_copy_qpixmap.triggered.connect(
113+
partial(self.copy_to_clipboard, "qpixmap")
114+
)
115+
116+
# add actions to context menu
117+
menu.addAction(action_copy_name)
118+
menu.addAction(action_copy_path)
119+
menu.addSeparator()
120+
menu.addAction(action_copy_theme_icon)
121+
menu.addAction(action_copy_qicon)
122+
menu.addAction(action_copy_qpixmap)
123+
124+
# open the menu at the event global position
125+
menu.exec_(event.globalPos())
126+
127+
def copy_to_clipboard(
128+
self,
129+
expected_format: Literal["getThemeIcon", "name", "path", "qicon", "qpixmap"],
130+
) -> str:
131+
"""Copy item uri to system clipboard in an expected format.
132+
133+
:param expected_format: expected format
134+
:type expected_format: Literal["name", "path", "qicon", "qpixmap"]
135+
136+
:return: formatted uri in the expected format
137+
:rtype: str
138+
"""
139+
self.log(
140+
message=f"DEBUG - Copy to clipboard {self.uri} in {expected_format} format.",
141+
log_level=4,
142+
)
143+
if expected_format.lower() == "name":
144+
QApplication.clipboard().setText(Path(self.uri).name)
145+
self.log(message=f"Text copied: {Path(self.uri).name}", log_level=4)
146+
return Path(self.uri).name
147+
if expected_format.lower() == "path":
148+
QApplication.clipboard().setText(self.uri)
149+
self.log(message=f"Text copied: {self.uri}", log_level=4)
150+
return self.uri
151+
if expected_format.lower() == "getthemeicon":
152+
QApplication.clipboard().setText(
153+
f"QgsApplication.getThemeIcon('{Path(self.uri).name}')"
154+
)
155+
self.log(
156+
message=f"Text copied: QgsApplication.getThemeIcon('{Path(self.uri).name}')",
157+
log_level=4,
158+
)
159+
return f"QgsApplication.getThemeIcon('{self.uri}')"
160+
if expected_format.lower() == "qpixmap":
161+
QApplication.clipboard().setText(f"QPixmap('{self.uri}')")
162+
self.log(message=f"Text copied: QPixmap('{self.uri}')", log_level=4)
163+
return f"QPixmap('{self.uri}')"
164+
if expected_format.lower() == "qicon":
165+
QApplication.clipboard().setText(f"QIcon('{self.uri}')")
166+
self.log(message=f"Text copied: QIcon('{self.uri}')", log_level=4)
167+
return f"QIcon('{self.uri}')"
168+
169+
self.log(message=f"Undefined format: {expected_format}", push=True, log_level=1)
170+
53171

54172
class ResourceBrowser(QWidget):
55173
"""
@@ -59,7 +177,7 @@ class ResourceBrowser(QWidget):
59177
def __init__(self, *args, **kwds):
60178
super().__init__(*args, **kwds)
61179

62-
pathUi = pathlib.Path(__file__).parent / "resource_browser.ui"
180+
pathUi = Path(__file__).parent / "resource_browser.ui"
63181
with open(pathUi.as_posix()) as uifile:
64182
uic.loadUi(uifile, baseinstance=self)
65183

@@ -183,6 +301,7 @@ def updatePreview(self, uri: str):
183301
if item:
184302
hasImage = True
185303
self.graphicsView.setItem(item)
304+
self.graphicsView.uri = uri
186305

187306
if re.search(r"\.(svg|html|xml|txt|js|css)$", uri, re.I) is not None:
188307
file = QFile(uri)

0 commit comments

Comments
 (0)