mirror of
https://github.com/rbreu/beeref.git
synced 2026-03-11 08:54:28 +00:00
Show list of recent files on welcome screen
This commit is contained in:
parent
05301859b6
commit
22e219f56f
5 changed files with 206 additions and 53 deletions
|
|
@ -1,6 +1,16 @@
|
|||
0.2.1 - (unreleased)
|
||||
====================
|
||||
|
||||
Added
|
||||
-----
|
||||
|
||||
* Show list of recent files on welcome screen
|
||||
|
||||
Fixed
|
||||
-----
|
||||
|
||||
* Various typos (by luzpaz)
|
||||
|
||||
|
||||
0.2.0 - 2021-09-06
|
||||
==================
|
||||
|
|
|
|||
|
|
@ -16,33 +16,111 @@
|
|||
import logging
|
||||
import os.path
|
||||
|
||||
from PyQt6 import QtCore, QtWidgets
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
from PyQt6.QtCore import Qt
|
||||
|
||||
from beeref import constants
|
||||
from beeref.config import logfile_name
|
||||
from beeref.config import logfile_name, BeeSettings
|
||||
from beeref.main_controls import MainControlsMixin
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WelcomeOverlay(QtWidgets.QWidget):
|
||||
class RecentFilesModel(QtCore.QAbstractListModel):
|
||||
"""An entry in the 'Recent Files' list."""
|
||||
|
||||
def __init__(self, files):
|
||||
super().__init__()
|
||||
self.files = files
|
||||
|
||||
def rowCount(self, parent):
|
||||
return len(self.files)
|
||||
|
||||
def data(self, index, role):
|
||||
if role == QtCore.Qt.ItemDataRole.DisplayRole:
|
||||
return os.path.basename(self.files[index.row()])
|
||||
if role == QtCore.Qt.ItemDataRole.FontRole:
|
||||
font = QtGui.QFont()
|
||||
font.setUnderline(True)
|
||||
return font
|
||||
|
||||
|
||||
class RecentFilesView(QtWidgets.QListView):
|
||||
|
||||
def __init__(self, parent, files=None):
|
||||
super().__init__(parent)
|
||||
self.files = files or []
|
||||
self.clicked.connect(self.on_clicked)
|
||||
self.setModel(RecentFilesModel(self.files))
|
||||
self.setMouseTracking(True)
|
||||
|
||||
def on_clicked(self, index):
|
||||
self.parent().parent().open_from_file(self.files[index.row()])
|
||||
|
||||
def update_files(self, files):
|
||||
self.files = files
|
||||
self.model().files = files
|
||||
self.reset()
|
||||
|
||||
def sizeHint(self):
|
||||
size = QtCore.QSize()
|
||||
height = sum(
|
||||
(self.sizeHintForRow(i) + 2) for i in range(len(self.files)))
|
||||
width = max(self.sizeHintForColumn(i) for i in range(len(self.files)))
|
||||
size.setHeight(height)
|
||||
size.setWidth(width + 2)
|
||||
return size
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
index = self.indexAt(
|
||||
QtCore.QPoint(int(event.position().x()),
|
||||
int(event.position().y())))
|
||||
if index.isValid():
|
||||
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
else:
|
||||
self.setCursor(Qt.CursorShape.ArrowCursor)
|
||||
|
||||
super().mouseMoveEvent(event)
|
||||
|
||||
|
||||
class WelcomeOverlay(MainControlsMixin, QtWidgets.QWidget):
|
||||
"""Some basic info to be displayed when the scene is empty."""
|
||||
|
||||
txt = """<p>Paste or drop images here.</p>
|
||||
<p>Right-click for more options.</p>"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self.control_target = parent
|
||||
self.setAttribute(Qt.WidgetAttribute.WA_NoSystemBackground)
|
||||
self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents)
|
||||
label = QtWidgets.QLabel(self)
|
||||
label.setText(self.txt)
|
||||
self.init_main_controls()
|
||||
|
||||
# Recent files
|
||||
self.files_layout = QtWidgets.QVBoxLayout()
|
||||
self.files_layout.addStretch(50)
|
||||
self.files_layout.addWidget(
|
||||
QtWidgets.QLabel('<h3>Recent Files</h3>', self))
|
||||
self.files_view = RecentFilesView(self)
|
||||
self.files_layout.addWidget(self.files_view)
|
||||
self.files_layout.addStretch(50)
|
||||
|
||||
# Help text
|
||||
label = QtWidgets.QLabel(self.txt, self)
|
||||
label.setAlignment(Qt.AlignmentFlag.AlignVCenter
|
||||
| Qt.AlignmentFlag.AlignCenter)
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.addWidget(label)
|
||||
self.setLayout(layout)
|
||||
self.layout = QtWidgets.QHBoxLayout()
|
||||
self.layout.addStretch(50)
|
||||
self.layout.addWidget(label)
|
||||
self.layout.addStretch(50)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def show(self):
|
||||
files = BeeSettings().get_recent_files(existing_only=True)
|
||||
self.files_view.update_files(files)
|
||||
if files and self.layout.indexOf(self.files_layout) < 0:
|
||||
self.layout.insertLayout(0, self.files_layout)
|
||||
super().show()
|
||||
|
||||
|
||||
class BeeProgressDialog(QtWidgets.QProgressDialog):
|
||||
|
|
|
|||
78
beeref/main_controls.py
Normal file
78
beeref/main_controls.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
# This file is part of BeeRef.
|
||||
#
|
||||
# BeeRef is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BeeRef is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BeeRef. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
|
||||
from PyQt6 import QtCore, QtGui
|
||||
from PyQt6.QtCore import Qt
|
||||
|
||||
from beeref import commands
|
||||
from beeref.items import BeePixmapItem
|
||||
from beeref import fileio
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MainControlsMixin:
|
||||
"""Basic controls shared by the main view and the welcome overlay:
|
||||
|
||||
* Right-click menu
|
||||
* Dropping files
|
||||
"""
|
||||
|
||||
def init_main_controls(self):
|
||||
self.setContextMenuPolicy(
|
||||
Qt.ContextMenuPolicy.CustomContextMenu)
|
||||
self.customContextMenuRequested.connect(
|
||||
self.control_target.on_context_menu)
|
||||
self.setAcceptDrops(True)
|
||||
|
||||
def dragEnterEvent(self, event):
|
||||
mimedata = event.mimeData()
|
||||
logger.debug(f'Drag enter event: {mimedata.formats()}')
|
||||
if mimedata.hasUrls():
|
||||
event.acceptProposedAction()
|
||||
elif mimedata.hasImage():
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
logger.info('Attempted drop not an image')
|
||||
|
||||
def dragMoveEvent(self, event):
|
||||
event.acceptProposedAction()
|
||||
|
||||
def dropEvent(self, event):
|
||||
mimedata = event.mimeData()
|
||||
logger.debug(f'Handling file drop: {mimedata.formats()}')
|
||||
pos = QtCore.QPoint(round(event.position().x()),
|
||||
round(event.position().y()))
|
||||
if mimedata.hasUrls():
|
||||
logger.debug(f'Found dropped urls: {mimedata.urls()}')
|
||||
if not self.control_target.scene.items():
|
||||
# Check if we have a bee file we can open directly
|
||||
path = mimedata.urls()[0]
|
||||
if (path.isLocalFile()
|
||||
and fileio.is_bee_file(path.toLocalFile())):
|
||||
self.control_target.open_from_file(path.toLocalFile())
|
||||
return
|
||||
self.control_target.do_insert_images(mimedata.urls(), pos)
|
||||
elif mimedata.hasImage():
|
||||
img = QtGui.QImage(mimedata.imageData())
|
||||
item = BeePixmapItem(img)
|
||||
pos = self.control_target.mapToScene(pos)
|
||||
self.control_target.undo_stack.push(
|
||||
commands.InsertItems(self.control_target.scene, [item], pos))
|
||||
else:
|
||||
logger.info('Drop not an image')
|
||||
|
|
@ -28,6 +28,7 @@ from beeref import constants
|
|||
from beeref import fileio
|
||||
from beeref import gui
|
||||
from beeref.items import BeePixmapItem, BeeTextItem
|
||||
from beeref.main_controls import MainControlsMixin
|
||||
from beeref.scene import BeeGraphicsScene
|
||||
|
||||
|
||||
|
|
@ -35,7 +36,9 @@ commandline_args = CommandlineArgs()
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BeeGraphicsView(QtWidgets.QGraphicsView, ActionsMixin):
|
||||
class BeeGraphicsView(MainControlsMixin,
|
||||
QtWidgets.QGraphicsView,
|
||||
ActionsMixin):
|
||||
|
||||
def __init__(self, app, parent=None):
|
||||
super().__init__(parent)
|
||||
|
|
@ -47,7 +50,6 @@ class BeeGraphicsView(QtWidgets.QGraphicsView, ActionsMixin):
|
|||
self.setBackgroundBrush(
|
||||
QtGui.QBrush(QtGui.QColor(*constants.COLORS['Scene:Canvas'])))
|
||||
self.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
|
||||
self.setAcceptDrops(True)
|
||||
|
||||
self.undo_stack = QtGui.QUndoStack(self)
|
||||
self.undo_stack.setUndoLimit(100)
|
||||
|
|
@ -68,9 +70,8 @@ class BeeGraphicsView(QtWidgets.QGraphicsView, ActionsMixin):
|
|||
|
||||
# Context menu and actions
|
||||
self.build_menu_and_actions()
|
||||
self.setContextMenuPolicy(
|
||||
Qt.ContextMenuPolicy.CustomContextMenu)
|
||||
self.customContextMenuRequested.connect(self.on_context_menu)
|
||||
self.control_target = self
|
||||
self.init_main_controls()
|
||||
|
||||
# Load file given via command line
|
||||
if commandline_args.filename:
|
||||
|
|
@ -671,39 +672,3 @@ class BeeGraphicsView(QtWidgets.QGraphicsView, ActionsMixin):
|
|||
super().resizeEvent(event)
|
||||
self.recalc_scene_rect()
|
||||
self.welcome_overlay.resize(self.size())
|
||||
|
||||
def dragEnterEvent(self, event):
|
||||
mimedata = event.mimeData()
|
||||
logger.debug(f'Drag enter event: {mimedata.formats()}')
|
||||
if mimedata.hasUrls():
|
||||
event.acceptProposedAction()
|
||||
elif mimedata.hasImage():
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
logger.info('Attempted drop not an image')
|
||||
|
||||
def dragMoveEvent(self, event):
|
||||
event.acceptProposedAction()
|
||||
|
||||
def dropEvent(self, event):
|
||||
mimedata = event.mimeData()
|
||||
logger.debug(f'Handling file drop: {mimedata.formats()}')
|
||||
pos = QtCore.QPoint(round(event.position().x()),
|
||||
round(event.position().y()))
|
||||
if mimedata.hasUrls():
|
||||
logger.debug(f'Found dropped urls: {mimedata.urls()}')
|
||||
if not self.scene.items():
|
||||
# Check if we have a bee file we can open directly
|
||||
path = mimedata.urls()[0]
|
||||
if (path.isLocalFile()
|
||||
and fileio.is_bee_file(path.toLocalFile())):
|
||||
self.open_from_file(path.toLocalFile())
|
||||
return
|
||||
self.do_insert_images(mimedata.urls(), pos)
|
||||
elif mimedata.hasImage():
|
||||
img = QtGui.QImage(mimedata.imageData())
|
||||
item = BeePixmapItem(img)
|
||||
pos = self.mapToScene(pos)
|
||||
self.undo_stack.push(commands.InsertItems(self.scene, [item], pos))
|
||||
else:
|
||||
logger.info('Drop not an image')
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
from PyQt6 import QtWidgets
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from PyQt6 import QtCore, QtWidgets
|
||||
from PyQt6.QtCore import Qt
|
||||
|
||||
from beeref.config import logfile_name
|
||||
from beeref.gui import DebugLogDialog
|
||||
from beeref.gui import DebugLogDialog, RecentFilesModel
|
||||
|
||||
|
||||
def test_debug_log_dialog(qtbot, settings, view):
|
||||
|
|
@ -16,3 +18,23 @@ def test_debug_log_dialog(qtbot, settings, view):
|
|||
qtbot.mouseClick(dialog.copy_button, Qt.MouseButton.LeftButton)
|
||||
clipboard = QtWidgets.QApplication.clipboard()
|
||||
assert clipboard.text() == 'my log output'
|
||||
|
||||
|
||||
def test_recent_files_model_rowcount(view):
|
||||
model = RecentFilesModel(['foo.png', 'bar.png'])
|
||||
assert model.rowCount(None) == 2
|
||||
|
||||
|
||||
def test_recent_files_model_data_diplayrole(view):
|
||||
model = RecentFilesModel(['foo.png', 'bar.png'])
|
||||
index = MagicMock()
|
||||
index.row.return_value = 1
|
||||
assert model.data(index, QtCore.Qt.ItemDataRole.DisplayRole) == 'bar.png'
|
||||
|
||||
|
||||
def test_recent_files_model_data_fontrole(view):
|
||||
model = RecentFilesModel(['foo.png', 'bar.png'])
|
||||
index = MagicMock()
|
||||
index.row.return_value = 1
|
||||
font = model.data(index, QtCore.Qt.ItemDataRole.FontRole)
|
||||
assert font.underline() is True
|
||||
|
|
|
|||
Loading…
Reference in a new issue