mirror of
https://github.com/rbreu/beeref.git
synced 2026-03-11 08:54:28 +00:00
wip
This commit is contained in:
parent
c251bb8159
commit
d5cdf19b73
5 changed files with 106 additions and 7 deletions
|
|
@ -13,24 +13,27 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with BeeRef. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
|
||||
from PyQt6 import QtCore
|
||||
|
||||
from beeref import commands
|
||||
from beeref.fileio.errors import BeeFileIOError
|
||||
from beeref.fileio.image import load_image
|
||||
from beeref.fileio.sql import SQLiteIO, is_bee_file
|
||||
from beeref.fileio.sql import SQLiteIO, is_bee_file, read_uppdate_from_file
|
||||
from beeref.items import BeePixmapItem
|
||||
|
||||
|
||||
__all__ = [
|
||||
'is_bee_file',
|
||||
'load_bee',
|
||||
'save_bee',
|
||||
'load_images',
|
||||
'ThreadedLoader',
|
||||
'read_uppdate_from_file'
|
||||
'save_bee',
|
||||
'BeeFileIOError',
|
||||
'ThreadedLoader',
|
||||
]
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -52,6 +55,31 @@ def save_bee(filename, scene, create_new=False, worker=None):
|
|||
logger.info('End save')
|
||||
|
||||
|
||||
def save_backup(filename, backup_filename, scene, worker=None):
|
||||
"""Save backup bee file."""
|
||||
logger.info(f'Saving backup to file {filename}...')
|
||||
copy_to_backup = False
|
||||
past = datetime(2000, 1, 1, tzinfo=datetime.timezone.utc)
|
||||
|
||||
if os.path.exists(filename):
|
||||
upddate_original = read_uppdate_from_file(filename) or past
|
||||
if os.path.exists(backup_filename):
|
||||
upddate_backup = read_uppdate_from_file(backup_filename) or past
|
||||
if upddate_original > upddate_backup:
|
||||
copy_to_backup = True
|
||||
logger.debug('Original file newer than backup')
|
||||
else:#tbd
|
||||
copy_to_backup = True
|
||||
logger.debug('Backup file does\'t exist yet')
|
||||
|
||||
if copy_to_backup:
|
||||
logger.debug('Copying original file to backup file...')
|
||||
#tbd
|
||||
|
||||
#tbd backup
|
||||
|
||||
worker.finished.emit(filename, [])
|
||||
|
||||
def load_images(filenames, pos, scene, worker):
|
||||
"""Add images to existing scene."""
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ SCHEMA = [
|
|||
ON UPDATE NO ACTION
|
||||
)
|
||||
""",
|
||||
"""CREATE TABLE info (
|
||||
"""
|
||||
CREATE TABLE info (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT
|
||||
)
|
||||
|
|
|
|||
|
|
@ -49,6 +49,13 @@ def is_bee_file(path):
|
|||
return os.path.splitext(path)[1] == '.bee'
|
||||
|
||||
|
||||
def read_uppdate_from_file(filename):
|
||||
io = SQLiteIO(filename, None, create_new=False, readonly=True)
|
||||
datestring = io.read_info_value('upddate')
|
||||
if datestring:
|
||||
return datetime.datetime.fromisoformat(datestring)
|
||||
|
||||
|
||||
def handle_sqlite_errors(func):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from functools import partial
|
|||
import logging
|
||||
import os
|
||||
import os.path
|
||||
import tempfile
|
||||
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
from PyQt6.QtCore import Qt
|
||||
|
|
@ -67,6 +68,7 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
self.undo_stack.cleanChanged.connect(self.on_undo_clean_changed)
|
||||
|
||||
self.filename = None
|
||||
self.backup_filename = None
|
||||
self.previous_transform = None
|
||||
self.active_mode = None
|
||||
|
||||
|
|
@ -92,6 +94,11 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
|
||||
self.update_window_title()
|
||||
|
||||
# Initiate back
|
||||
timer = QtCore.QTimer(parent=self)
|
||||
timer.timeout.connect(self.save_backup)
|
||||
timer.start(1000 * 5)# tbd configurable
|
||||
|
||||
@property
|
||||
def filename(self):
|
||||
return self._filename
|
||||
|
|
@ -104,6 +111,42 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
self.settings.update_recent_files(value)
|
||||
self.update_menu_and_actions()
|
||||
|
||||
@property
|
||||
def backup_filename(self):
|
||||
if self.filename:
|
||||
return f'{self.filename}~'
|
||||
|
||||
if not self._backup_filename:
|
||||
self._backup_filename = tempfile.NamedTemporaryFile(
|
||||
prefix=constants.APPNAME,
|
||||
suffix='.bee~',
|
||||
delete=False,
|
||||
delete_on_close=False
|
||||
).name
|
||||
return self._backup_filename
|
||||
|
||||
@backup_filename.setter
|
||||
def backup_filename(self, value):
|
||||
self._backup_filename = value
|
||||
|
||||
def save_backup(self):
|
||||
if self.undo_stack.isClean():
|
||||
logger.debug('No unsaved changes to back up')
|
||||
return
|
||||
|
||||
if not hasattr(self, 'backup_worker'):
|
||||
self.backup_worker = fileio.ThreadedIO(
|
||||
fileio.save_backup,
|
||||
self.filename, self.backup_filename, self.scene)
|
||||
self.backup_worker.finished.connect(self.on_save_backup_finished)
|
||||
self.backup_worker.start()
|
||||
else:
|
||||
logger.debug('Backup still ongoing, skipping')
|
||||
|
||||
def on_save_backup_finished(self):
|
||||
del self.backup_worker
|
||||
logger.debug('Saving backup finished')
|
||||
|
||||
def cancel_active_modes(self):
|
||||
self.scene.cancel_active_modes()
|
||||
self.cancel_sample_color_mode()
|
||||
|
|
@ -174,6 +217,7 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
self.scene.clear()
|
||||
self.undo_stack.clear()
|
||||
self.filename = None
|
||||
self.backup_filename = None
|
||||
self.setTransform(QtGui.QTransform())
|
||||
|
||||
def reset_previous_transform(self, toggle_item=None):
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import pytest
|
|||
|
||||
from beeref.fileio import schema, is_bee_file
|
||||
from beeref.fileio.errors import BeeFileIOError
|
||||
from beeref.fileio.sql import SQLiteIO
|
||||
from beeref.fileio.sql import SQLiteIO, read_uppdate_from_file
|
||||
from beeref.items import BeePixmapItem, BeeTextItem, BeeErrorItem
|
||||
|
||||
|
||||
|
|
@ -22,6 +22,24 @@ def test_is_bee_file(filename, expected):
|
|||
assert is_bee_file(filename) is expected
|
||||
|
||||
|
||||
def test_read_upddate_from_file(tmpfile):
|
||||
io = SQLiteIO(tmpfile, MagicMock(), create_new=True)
|
||||
io.create_schema_on_new()
|
||||
dt = datetime.datetime(2024, 5, 10, 12, 45, tzinfo=datetime.timezone.utc)
|
||||
io.write_info_value('upddate', dt.isoformat())
|
||||
io.connection.commit()
|
||||
del io
|
||||
assert read_uppdate_from_file(tmpfile) == dt
|
||||
|
||||
|
||||
def test_read_upddate_from_file_when_not_set(tmpfile):
|
||||
io = SQLiteIO(tmpfile, MagicMock(), create_new=True)
|
||||
io.create_schema_on_new()
|
||||
io.connection.commit()
|
||||
del io
|
||||
assert read_uppdate_from_file(tmpfile) is None
|
||||
|
||||
|
||||
def test_sqliteio_migrate_does_nothing_when_version_ok(tmpfile):
|
||||
io = SQLiteIO(tmpfile, MagicMock(), create_new=True)
|
||||
io.ex('PRAGMA user_version=%s' % schema.USER_VERSION)
|
||||
|
|
@ -214,8 +232,9 @@ def test_sqliteio_write_calls_create_schema_on_new(tmpfile, view):
|
|||
with patch.object(io, 'create_schema_on_new') as crmock:
|
||||
with patch.object(io, 'fetchall'):
|
||||
with patch.object(io, 'exmany'):
|
||||
io.write()
|
||||
crmock.assert_called_once()
|
||||
with patch.object(io, 'ex'):
|
||||
io.write()
|
||||
crmock.assert_called_once()
|
||||
|
||||
|
||||
def test_sqliteio_write_calls_write_meta(tmpfile, view):
|
||||
|
|
|
|||
Loading…
Reference in a new issue